├── .github ├── dependabot.yml └── workflows │ ├── crypto-bigint.yml │ └── security-audit.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── SECURITY.md ├── benches ├── boxed_monty.rs ├── boxed_uint.rs ├── const_monty.rs ├── int.rs ├── limb.rs ├── monty.rs └── uint.rs ├── src ├── array.rs ├── checked.rs ├── const_choice.rs ├── int.rs ├── int │ ├── add.rs │ ├── bit_and.rs │ ├── bit_not.rs │ ├── bit_or.rs │ ├── bit_xor.rs │ ├── cmp.rs │ ├── div.rs │ ├── div_uint.rs │ ├── encoding.rs │ ├── from.rs │ ├── gcd.rs │ ├── invert_mod.rs │ ├── mul.rs │ ├── mul_uint.rs │ ├── neg.rs │ ├── rand.rs │ ├── resize.rs │ ├── shl.rs │ ├── shr.rs │ ├── sign.rs │ ├── sub.rs │ └── types.rs ├── lib.rs ├── limb.rs ├── limb │ ├── add.rs │ ├── bit_and.rs │ ├── bit_not.rs │ ├── bit_or.rs │ ├── bit_xor.rs │ ├── bits.rs │ ├── cmp.rs │ ├── encoding.rs │ ├── from.rs │ ├── mul.rs │ ├── neg.rs │ ├── rand.rs │ ├── shl.rs │ ├── shr.rs │ └── sub.rs ├── macros.rs ├── modular.rs ├── modular │ ├── add.rs │ ├── boxed_monty_form.rs │ ├── boxed_monty_form │ │ ├── add.rs │ │ ├── invert.rs │ │ ├── lincomb.rs │ │ ├── mul.rs │ │ ├── neg.rs │ │ ├── pow.rs │ │ └── sub.rs │ ├── const_monty_form.rs │ ├── const_monty_form │ │ ├── add.rs │ │ ├── invert.rs │ │ ├── lincomb.rs │ │ ├── macros.rs │ │ ├── mul.rs │ │ ├── neg.rs │ │ ├── pow.rs │ │ └── sub.rs │ ├── div_by_2.rs │ ├── lincomb.rs │ ├── monty_form.rs │ ├── monty_form │ │ ├── add.rs │ │ ├── invert.rs │ │ ├── lincomb.rs │ │ ├── mul.rs │ │ ├── neg.rs │ │ ├── pow.rs │ │ └── sub.rs │ ├── mul.rs │ ├── pow.rs │ ├── reduction.rs │ ├── safegcd.rs │ ├── safegcd │ │ ├── boxed.rs │ │ └── macros.rs │ └── sub.rs ├── non_zero.rs ├── odd.rs ├── primitives.rs ├── traits.rs ├── traits │ └── sealed.rs ├── uint.rs ├── uint │ ├── add.rs │ ├── add_mod.rs │ ├── array.rs │ ├── bit_and.rs │ ├── bit_not.rs │ ├── bit_or.rs │ ├── bit_xor.rs │ ├── bits.rs │ ├── boxed.rs │ ├── boxed │ │ ├── add.rs │ │ ├── add_mod.rs │ │ ├── bit_and.rs │ │ ├── bit_not.rs │ │ ├── bit_or.rs │ │ ├── bit_xor.rs │ │ ├── bits.rs │ │ ├── cmp.rs │ │ ├── ct.rs │ │ ├── div.rs │ │ ├── div_limb.rs │ │ ├── encoding.rs │ │ ├── from.rs │ │ ├── gcd.rs │ │ ├── invert_mod.rs │ │ ├── mul.rs │ │ ├── mul_mod.rs │ │ ├── neg.rs │ │ ├── neg_mod.rs │ │ ├── rand.rs │ │ ├── shl.rs │ │ ├── shr.rs │ │ ├── sqrt.rs │ │ ├── sub.rs │ │ └── sub_mod.rs │ ├── cmp.rs │ ├── concat.rs │ ├── div.rs │ ├── div_limb.rs │ ├── encoding.rs │ ├── encoding │ │ ├── der.rs │ │ └── rlp.rs │ ├── extra_sizes.rs │ ├── from.rs │ ├── gcd.rs │ ├── invert_mod.rs │ ├── macros.rs │ ├── mul.rs │ ├── mul │ │ └── karatsuba.rs │ ├── mul_mod.rs │ ├── neg.rs │ ├── neg_mod.rs │ ├── rand.rs │ ├── ref_type.rs │ ├── resize.rs │ ├── shl.rs │ ├── shr.rs │ ├── split.rs │ ├── sqrt.rs │ ├── sub.rs │ └── sub_mod.rs └── wrapping.rs └── tests ├── boxed_monty_form.proptest-regressions ├── boxed_monty_form.rs ├── boxed_uint.proptest-regressions ├── boxed_uint.rs ├── common └── mod.rs ├── const_monty_form.rs ├── impl_modulus.rs ├── monty_form.proptest-regressions ├── monty_form.rs ├── safegcd.proptest-regressions ├── safegcd.rs └── uint.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/workflows/security-audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | on: 3 | pull_request: 4 | paths: 5 | - Cargo.lock 6 | - .github/workflows/security-audit.yml 7 | push: 8 | branches: master 9 | paths: 10 | - Cargo.lock 11 | schedule: 12 | - cron: "0 0 * * *" 13 | 14 | jobs: 15 | security_audit: 16 | name: Security Audit 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Cache cargo bin 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.cargo/bin 24 | key: ${{ runner.os }}-cargo-audit-v0.21.0 25 | - uses: rustsec/audit-check@v2 26 | with: 27 | token: ${{ secrets.GITHUB_TOKEN }} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | proptest-regressions 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crypto-bigint" 3 | version = "0.7.0-pre.4" 4 | description = """ 5 | Pure Rust implementation of a big integer library which has been designed from 6 | the ground-up for use in cryptographic applications. Provides constant-time, 7 | no_std-friendly implementations of modern formulas using const generics. 8 | """ 9 | authors = ["RustCrypto Developers"] 10 | license = "Apache-2.0 OR MIT" 11 | repository = "https://github.com/RustCrypto/crypto-bigint" 12 | categories = ["algorithms", "cryptography", "data-structures", "mathematics", "no-std"] 13 | keywords = ["arbitrary", "crypto", "bignum", "integer", "precision"] 14 | readme = "README.md" 15 | resolver = "2" 16 | edition = "2024" 17 | rust-version = "1.85" 18 | 19 | [dependencies] 20 | subtle = { version = "2.6", default-features = false } 21 | 22 | # optional dependencies 23 | der = { version = "0.8.0-rc.3", optional = true, default-features = false } 24 | hybrid-array = { version = "0.3", optional = true } 25 | num-traits = { version = "0.2.19", default-features = false } 26 | rand_core = { version = "0.9.2", optional = true, default-features = false } 27 | rlp = { version = "0.6", optional = true, default-features = false } 28 | serdect = { version = "0.3", optional = true, default-features = false } 29 | zeroize = { version = "1", optional = true, default-features = false } 30 | 31 | [dev-dependencies] 32 | bincode = "1" 33 | criterion = { version = "0.5", features = ["html_reports"] } 34 | hex-literal = "1" 35 | num-bigint = "0.4" 36 | num-integer = "0.1" 37 | num-modular = { version = "0.6", features = ["num-bigint", "num-integer", "num-traits"] } 38 | proptest = "1.5" 39 | rand_core = { version = "0.9", features = ["std", "os_rng"] } 40 | rand_chacha = "0.9" 41 | 42 | 43 | [features] 44 | default = ["rand"] 45 | alloc = ["serdect?/alloc"] 46 | 47 | extra-sizes = [] 48 | rand = ["rand_core"] 49 | serde = ["dep:serdect"] 50 | 51 | [package.metadata.docs.rs] 52 | all-features = true 53 | rustdoc-args = ["--cfg", "docsrs"] 54 | 55 | [[bench]] 56 | name = "boxed_monty" 57 | harness = false 58 | required-features = ["alloc"] 59 | 60 | [[bench]] 61 | name = "boxed_uint" 62 | harness = false 63 | required-features = ["alloc"] 64 | 65 | [[bench]] 66 | name = "const_monty" 67 | harness = false 68 | 69 | [[bench]] 70 | name = "limb" 71 | harness = false 72 | 73 | [[bench]] 74 | name = "monty" 75 | harness = false 76 | 77 | [[bench]] 78 | name = "uint" 79 | harness = false 80 | 81 | [[bench]] 82 | name = "int" 83 | harness = false 84 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-2025 The RustCrypto Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: Cryptographic Big Integers 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Pure Rust implementation of a big integer library which has been designed from 11 | the ground-up for use in cryptographic applications. 12 | 13 | Provides constant-time, `no_std`-friendly implementations of modern formulas 14 | using const generics. 15 | 16 | [Documentation][docs-link] 17 | 18 | ## Goals 19 | 20 | - Supports `no_std`-friendly const generic stack-allocated big integers. 21 | - Constant-time by default. Variable-time functions are explicitly marked as such. 22 | - Leverage what is possible today with const generics on `stable` rust. 23 | - Support `const fn` as much as possible with the goal of being able to compute 24 | values at compile-time. 25 | - Optional heap-allocated `Boxed*` types gated under an `alloc` feature. 26 | 27 | ## Security Notes 28 | 29 | This crate has been [audited by NCC Group] with no significant 30 | findings. We would like to thank [Entropy] for funding the audit. 31 | 32 | All functions contained in the crate are designed to execute in constant 33 | time unless explicitly specified otherwise (via a `*_vartime` name suffix). 34 | 35 | This library is not suitable for use on processors with a variable-time 36 | multiplication operation (e.g. short circuit on multiply-by-zero / 37 | multiply-by-one, such as certain 32-bit PowerPC CPUs and some non-ARM 38 | microcontrollers). 39 | 40 | ## License 41 | 42 | Licensed under either of: 43 | 44 | - [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 45 | - [MIT license](http://opensource.org/licenses/MIT) 46 | 47 | at your option. 48 | 49 | ### Contribution 50 | 51 | Unless you explicitly state otherwise, any contribution intentionally submitted 52 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 53 | dual licensed as above, without any additional terms or conditions. 54 | 55 | [//]: # (badges) 56 | 57 | [crate-image]: https://img.shields.io/crates/v/crypto-bigint?logo=rust 58 | [crate-link]: https://crates.io/crates/crypto-bigint 59 | [docs-image]: https://docs.rs/crypto-bigint/badge.svg 60 | [docs-link]: https://docs.rs/crypto-bigint/ 61 | [build-image]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml/badge.svg?branch=master 62 | [build-link]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml?query=branch:master 63 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 64 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 65 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 66 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300602-crypto-bigint 67 | 68 | [//]: # (links) 69 | 70 | [RustCrypto]: https://github.com/rustcrypto 71 | [audited by NCC Group]: https://www.nccgroup.com/us/research-blog/public-report-entropyrust-cryptography-review/ 72 | [Entropy]: https://entropy.xyz/ 73 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Security updates are applied only to the most recent release. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you have discovered a security vulnerability in this project, please report 10 | it privately. **Do not disclose it as a public issue.** This gives us time to 11 | work with you to fix the issue before public exposure, reducing the chance that 12 | the exploit will be used before a patch is released. 13 | 14 | Please disclose it at [security advisory](https://github.com/RustCrypto/crypto-bigint/security/advisories/new). 15 | 16 | This project is maintained by a team of volunteers on a reasonable-effort basis. 17 | As such, please give us at least 90 days to work on a fix before public exposure. 18 | -------------------------------------------------------------------------------- /benches/limb.rs: -------------------------------------------------------------------------------- 1 | use criterion::{ 2 | BatchSize, BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main, 3 | measurement::Measurement, 4 | }; 5 | use crypto_bigint::{Limb, Random}; 6 | use rand_chacha::ChaChaRng; 7 | use rand_core::SeedableRng; 8 | use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; 9 | 10 | fn bench_cmp(group: &mut BenchmarkGroup<'_, M>) { 11 | let mut rng = ChaChaRng::from_os_rng(); 12 | group.bench_function("ct_lt", |b| { 13 | b.iter_batched( 14 | || { 15 | let x = Limb::random(&mut rng); 16 | let y = Limb::random(&mut rng); 17 | (x, y) 18 | }, 19 | |(x, y)| black_box(x.ct_lt(&y)), 20 | BatchSize::SmallInput, 21 | ) 22 | }); 23 | 24 | group.bench_function("ct_eq", |b| { 25 | b.iter_batched( 26 | || { 27 | let x = Limb::random(&mut rng); 28 | let y = Limb::random(&mut rng); 29 | (x, y) 30 | }, 31 | |(x, y)| black_box(x.ct_eq(&y)), 32 | BatchSize::SmallInput, 33 | ) 34 | }); 35 | 36 | group.bench_function("ct_gt", |b| { 37 | b.iter_batched( 38 | || { 39 | let x = Limb::random(&mut rng); 40 | let y = Limb::random(&mut rng); 41 | (x, y) 42 | }, 43 | |(x, y)| black_box(x.ct_gt(&y)), 44 | BatchSize::SmallInput, 45 | ) 46 | }); 47 | } 48 | 49 | fn bench_ops(c: &mut Criterion) { 50 | let mut group = c.benchmark_group("ops"); 51 | bench_cmp(&mut group); 52 | group.finish(); 53 | } 54 | 55 | criterion_group!(benches, bench_ops); 56 | 57 | criterion_main!(benches); 58 | -------------------------------------------------------------------------------- /src/array.rs: -------------------------------------------------------------------------------- 1 | //! Interop support for `hybrid-array` 2 | 3 | use crate::{Encoding, Integer}; 4 | use core::ops::Add; 5 | use hybrid_array::{Array, ArraySize, typenum::Unsigned}; 6 | 7 | /// Alias for a byte array whose size is defined by [`ArrayEncoding::ByteSize`]. 8 | pub type ByteArray = Array::ByteSize>; 9 | 10 | /// Support for encoding a big integer as a `Array`. 11 | pub trait ArrayEncoding: Encoding { 12 | /// Size of a byte array which encodes a big integer. 13 | type ByteSize: ArraySize + Add + Eq + Ord + Unsigned; 14 | 15 | /// Deserialize from a big-endian byte array. 16 | fn from_be_byte_array(bytes: ByteArray) -> Self; 17 | 18 | /// Deserialize from a little-endian byte array. 19 | fn from_le_byte_array(bytes: ByteArray) -> Self; 20 | 21 | /// Serialize to a big-endian byte array. 22 | fn to_be_byte_array(&self) -> ByteArray; 23 | 24 | /// Serialize to a little-endian byte array. 25 | fn to_le_byte_array(&self) -> ByteArray; 26 | } 27 | 28 | /// Support for decoding a `Array` as a big integer. 29 | pub trait ArrayDecoding { 30 | /// Big integer which decodes a `Array`. 31 | type Output: ArrayEncoding + Integer; 32 | 33 | /// Deserialize from a big-endian `Array`. 34 | fn into_uint_be(self) -> Self::Output; 35 | 36 | /// Deserialize from a little-endian `Array`. 37 | fn into_uint_le(self) -> Self::Output; 38 | } 39 | -------------------------------------------------------------------------------- /src/int/bit_and.rs: -------------------------------------------------------------------------------- 1 | //! [`Int`] bitwise AND operations. 2 | 3 | use core::ops::{BitAnd, BitAndAssign}; 4 | 5 | use crate::{ConstCtOption, Int, Limb, Uint, Wrapping}; 6 | 7 | impl Int { 8 | /// Computes bitwise `a & b`. 9 | #[inline(always)] 10 | pub const fn bitand(&self, rhs: &Self) -> Self { 11 | Self(Uint::bitand(&self.0, &rhs.0)) 12 | } 13 | 14 | /// Perform bitwise `AND` between `self` and the given [`Limb`], performing the `AND` operation 15 | /// on every limb of `self`. 16 | pub const fn bitand_limb(&self, rhs: Limb) -> Self { 17 | Self(Uint::bitand_limb(&self.0, rhs)) 18 | } 19 | 20 | /// Perform wrapping bitwise `AND`. 21 | /// 22 | /// There's no way wrapping could ever happen. 23 | /// This function exists so that all operations are accounted for in the wrapping operations 24 | pub const fn wrapping_and(&self, rhs: &Self) -> Self { 25 | self.bitand(rhs) 26 | } 27 | 28 | /// Perform checked bitwise `AND`, returning a [`ConstCtOption`] which `is_some` always 29 | pub const fn checked_and(&self, rhs: &Self) -> ConstCtOption { 30 | ConstCtOption::some(self.bitand(rhs)) 31 | } 32 | } 33 | 34 | impl BitAnd for Int { 35 | type Output = Self; 36 | 37 | fn bitand(self, rhs: Self) -> Int { 38 | self.bitand(&rhs) 39 | } 40 | } 41 | 42 | impl BitAnd<&Int> for Int { 43 | type Output = Int; 44 | 45 | #[allow(clippy::needless_borrow)] 46 | fn bitand(self, rhs: &Int) -> Int { 47 | (&self).bitand(rhs) 48 | } 49 | } 50 | 51 | impl BitAnd> for &Int { 52 | type Output = Int; 53 | 54 | fn bitand(self, rhs: Int) -> Int { 55 | self.bitand(&rhs) 56 | } 57 | } 58 | 59 | impl BitAnd<&Int> for &Int { 60 | type Output = Int; 61 | 62 | fn bitand(self, rhs: &Int) -> Int { 63 | self.bitand(rhs) 64 | } 65 | } 66 | 67 | impl BitAndAssign for Int { 68 | #[allow(clippy::assign_op_pattern)] 69 | fn bitand_assign(&mut self, other: Self) { 70 | *self = *self & other; 71 | } 72 | } 73 | 74 | impl BitAndAssign<&Int> for Int { 75 | #[allow(clippy::assign_op_pattern)] 76 | fn bitand_assign(&mut self, other: &Self) { 77 | *self = *self & other; 78 | } 79 | } 80 | 81 | impl BitAnd for Wrapping> { 82 | type Output = Self; 83 | 84 | fn bitand(self, rhs: Self) -> Wrapping> { 85 | Wrapping(self.0.bitand(&rhs.0)) 86 | } 87 | } 88 | 89 | impl BitAnd<&Wrapping>> for Wrapping> { 90 | type Output = Wrapping>; 91 | 92 | fn bitand(self, rhs: &Wrapping>) -> Wrapping> { 93 | Wrapping(self.0.bitand(&rhs.0)) 94 | } 95 | } 96 | 97 | impl BitAnd>> for &Wrapping> { 98 | type Output = Wrapping>; 99 | 100 | fn bitand(self, rhs: Wrapping>) -> Wrapping> { 101 | Wrapping(self.0.bitand(&rhs.0)) 102 | } 103 | } 104 | 105 | impl BitAnd<&Wrapping>> for &Wrapping> { 106 | type Output = Wrapping>; 107 | 108 | fn bitand(self, rhs: &Wrapping>) -> Wrapping> { 109 | Wrapping(self.0.bitand(&rhs.0)) 110 | } 111 | } 112 | 113 | impl BitAndAssign for Wrapping> { 114 | #[allow(clippy::assign_op_pattern)] 115 | fn bitand_assign(&mut self, other: Self) { 116 | *self = *self & other; 117 | } 118 | } 119 | 120 | impl BitAndAssign<&Wrapping>> for Wrapping> { 121 | #[allow(clippy::assign_op_pattern)] 122 | fn bitand_assign(&mut self, other: &Self) { 123 | *self = *self & other; 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod tests { 129 | use crate::I128; 130 | 131 | #[test] 132 | fn checked_and_ok() { 133 | assert_eq!(I128::ZERO.checked_and(&I128::ONE).unwrap(), I128::ZERO); 134 | assert_eq!(I128::ONE.checked_and(&I128::ONE).unwrap(), I128::ONE); 135 | assert_eq!(I128::MAX.checked_and(&I128::ONE).unwrap(), I128::ONE); 136 | } 137 | 138 | #[test] 139 | fn wrapping_and_ok() { 140 | assert_eq!(I128::ZERO.wrapping_and(&I128::ONE), I128::ZERO); 141 | assert_eq!(I128::ONE.wrapping_and(&I128::ONE), I128::ONE); 142 | assert_eq!(I128::MAX.wrapping_and(&I128::ONE), I128::ONE); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/int/bit_not.rs: -------------------------------------------------------------------------------- 1 | //! [`Int`] bitwise NOT operations. 2 | 3 | use core::ops::Not; 4 | 5 | use crate::{Uint, Wrapping}; 6 | 7 | use super::Int; 8 | 9 | impl Int { 10 | /// Computes bitwise `!a`. 11 | #[inline(always)] 12 | pub const fn not(&self) -> Self { 13 | Self(Uint::not(&self.0)) 14 | } 15 | } 16 | 17 | impl Not for Int { 18 | type Output = Self; 19 | 20 | fn not(self) -> Self { 21 | Self::not(&self) 22 | } 23 | } 24 | 25 | impl Not for Wrapping> { 26 | type Output = Self; 27 | 28 | fn not(self) -> ::Output { 29 | Wrapping(self.0.not()) 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use crate::I128; 36 | 37 | #[test] 38 | fn bitnot_ok() { 39 | assert_eq!(I128::ZERO.not(), I128::MINUS_ONE); 40 | assert_eq!(I128::MAX.not(), I128::MIN); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/int/bit_or.rs: -------------------------------------------------------------------------------- 1 | //! [`Int`] bitwise OR operations. 2 | 3 | use core::ops::{BitOr, BitOrAssign}; 4 | 5 | use crate::{ConstCtOption, Uint, Wrapping}; 6 | 7 | use super::Int; 8 | 9 | impl Int { 10 | /// Computes bitwise `a & b`. 11 | #[inline(always)] 12 | pub const fn bitor(&self, rhs: &Self) -> Self { 13 | Self(Uint::bitor(&self.0, &rhs.0)) 14 | } 15 | 16 | /// Perform wrapping bitwise `OR`. 17 | /// 18 | /// There's no way wrapping could ever happen. 19 | /// This function exists so that all operations are accounted for in the wrapping operations 20 | pub const fn wrapping_or(&self, rhs: &Self) -> Self { 21 | self.bitor(rhs) 22 | } 23 | 24 | /// Perform checked bitwise `OR`, returning a [`ConstCtOption`] which `is_some` always 25 | pub const fn checked_or(&self, rhs: &Self) -> ConstCtOption { 26 | ConstCtOption::some(self.bitor(rhs)) 27 | } 28 | } 29 | 30 | impl BitOr for Int { 31 | type Output = Self; 32 | 33 | fn bitor(self, rhs: Self) -> Int { 34 | self.bitor(&rhs) 35 | } 36 | } 37 | 38 | impl BitOr<&Int> for Int { 39 | type Output = Int; 40 | 41 | #[allow(clippy::needless_borrow)] 42 | fn bitor(self, rhs: &Int) -> Int { 43 | (&self).bitor(rhs) 44 | } 45 | } 46 | 47 | impl BitOr> for &Int { 48 | type Output = Int; 49 | 50 | fn bitor(self, rhs: Int) -> Int { 51 | self.bitor(&rhs) 52 | } 53 | } 54 | 55 | impl BitOr<&Int> for &Int { 56 | type Output = Int; 57 | 58 | fn bitor(self, rhs: &Int) -> Int { 59 | self.bitor(rhs) 60 | } 61 | } 62 | 63 | impl BitOrAssign for Int { 64 | fn bitor_assign(&mut self, other: Self) { 65 | *self = *self | other; 66 | } 67 | } 68 | 69 | impl BitOrAssign<&Int> for Int { 70 | fn bitor_assign(&mut self, other: &Self) { 71 | *self = *self | other; 72 | } 73 | } 74 | 75 | impl BitOr for Wrapping> { 76 | type Output = Self; 77 | 78 | fn bitor(self, rhs: Self) -> Wrapping> { 79 | Wrapping(self.0.bitor(&rhs.0)) 80 | } 81 | } 82 | 83 | impl BitOr<&Wrapping>> for Wrapping> { 84 | type Output = Wrapping>; 85 | 86 | fn bitor(self, rhs: &Wrapping>) -> Wrapping> { 87 | Wrapping(self.0.bitor(&rhs.0)) 88 | } 89 | } 90 | 91 | impl BitOr>> for &Wrapping> { 92 | type Output = Wrapping>; 93 | 94 | fn bitor(self, rhs: Wrapping>) -> Wrapping> { 95 | Wrapping(self.0.bitor(&rhs.0)) 96 | } 97 | } 98 | 99 | impl BitOr<&Wrapping>> for &Wrapping> { 100 | type Output = Wrapping>; 101 | 102 | fn bitor(self, rhs: &Wrapping>) -> Wrapping> { 103 | Wrapping(self.0.bitor(&rhs.0)) 104 | } 105 | } 106 | 107 | impl BitOrAssign for Wrapping> { 108 | fn bitor_assign(&mut self, other: Self) { 109 | *self = *self | other; 110 | } 111 | } 112 | 113 | impl BitOrAssign<&Wrapping>> for Wrapping> { 114 | fn bitor_assign(&mut self, other: &Self) { 115 | *self = *self | other; 116 | } 117 | } 118 | 119 | #[cfg(test)] 120 | mod tests { 121 | use crate::I128; 122 | 123 | #[test] 124 | fn checked_or_ok() { 125 | assert_eq!(I128::ZERO.checked_or(&I128::ONE).unwrap(), I128::ONE); 126 | assert_eq!(I128::ONE.checked_or(&I128::ONE).unwrap(), I128::ONE); 127 | assert_eq!(I128::MAX.checked_or(&I128::ONE).unwrap(), I128::MAX); 128 | } 129 | 130 | #[test] 131 | fn wrapping_or_ok() { 132 | assert_eq!(I128::ZERO.wrapping_or(&I128::ONE), I128::ONE); 133 | assert_eq!(I128::ONE.wrapping_or(&I128::ONE), I128::ONE); 134 | assert_eq!(I128::MAX.wrapping_or(&I128::ONE), I128::MAX); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/int/bit_xor.rs: -------------------------------------------------------------------------------- 1 | //! [`Int`] bitwise XOR operations. 2 | 3 | use core::ops::{BitXor, BitXorAssign}; 4 | 5 | use crate::{ConstCtOption, Uint, Wrapping}; 6 | 7 | use super::Int; 8 | 9 | impl Int { 10 | /// Computes bitwise `a ^ b`. 11 | #[inline(always)] 12 | pub const fn bitxor(&self, rhs: &Self) -> Self { 13 | Self(Uint::bitxor(&self.0, &rhs.0)) 14 | } 15 | 16 | /// Perform wrapping bitwise `XOR`. 17 | /// 18 | /// There's no way wrapping could ever happen. 19 | /// This function exists so that all operations are accounted for in the wrapping operations 20 | pub const fn wrapping_xor(&self, rhs: &Self) -> Self { 21 | self.bitxor(rhs) 22 | } 23 | 24 | /// Perform checked bitwise `XOR`, returning a [`ConstCtOption`] which `is_some` always 25 | pub fn checked_xor(&self, rhs: &Self) -> ConstCtOption { 26 | ConstCtOption::some(self.bitxor(rhs)) 27 | } 28 | } 29 | 30 | impl BitXor for Int { 31 | type Output = Self; 32 | 33 | fn bitxor(self, rhs: Self) -> Int { 34 | self.bitxor(&rhs) 35 | } 36 | } 37 | 38 | impl BitXor<&Int> for Int { 39 | type Output = Int; 40 | 41 | #[allow(clippy::needless_borrow)] 42 | fn bitxor(self, rhs: &Int) -> Int { 43 | (&self).bitxor(rhs) 44 | } 45 | } 46 | 47 | impl BitXor> for &Int { 48 | type Output = Int; 49 | 50 | fn bitxor(self, rhs: Int) -> Int { 51 | self.bitxor(&rhs) 52 | } 53 | } 54 | 55 | impl BitXor<&Int> for &Int { 56 | type Output = Int; 57 | 58 | fn bitxor(self, rhs: &Int) -> Int { 59 | self.bitxor(rhs) 60 | } 61 | } 62 | 63 | impl BitXorAssign for Int { 64 | fn bitxor_assign(&mut self, other: Self) { 65 | *self = *self ^ other; 66 | } 67 | } 68 | 69 | impl BitXorAssign<&Int> for Int { 70 | fn bitxor_assign(&mut self, other: &Self) { 71 | *self = *self ^ other; 72 | } 73 | } 74 | 75 | impl BitXor for Wrapping> { 76 | type Output = Self; 77 | 78 | fn bitxor(self, rhs: Self) -> Wrapping> { 79 | Wrapping(self.0.bitxor(&rhs.0)) 80 | } 81 | } 82 | 83 | impl BitXor<&Wrapping>> for Wrapping> { 84 | type Output = Wrapping>; 85 | 86 | fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { 87 | Wrapping(self.0.bitxor(&rhs.0)) 88 | } 89 | } 90 | 91 | impl BitXor>> for &Wrapping> { 92 | type Output = Wrapping>; 93 | 94 | fn bitxor(self, rhs: Wrapping>) -> Wrapping> { 95 | Wrapping(self.0.bitxor(&rhs.0)) 96 | } 97 | } 98 | 99 | impl BitXor<&Wrapping>> for &Wrapping> { 100 | type Output = Wrapping>; 101 | 102 | fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { 103 | Wrapping(self.0.bitxor(&rhs.0)) 104 | } 105 | } 106 | 107 | impl BitXorAssign for Wrapping> { 108 | fn bitxor_assign(&mut self, other: Self) { 109 | *self = *self ^ other; 110 | } 111 | } 112 | 113 | impl BitXorAssign<&Wrapping>> for Wrapping> { 114 | fn bitxor_assign(&mut self, other: &Self) { 115 | *self = *self ^ other; 116 | } 117 | } 118 | 119 | #[cfg(test)] 120 | mod tests { 121 | use crate::I128; 122 | 123 | #[test] 124 | fn checked_xor_ok() { 125 | assert_eq!(I128::ZERO.checked_xor(&I128::ONE).unwrap(), I128::ONE); 126 | assert_eq!(I128::ONE.checked_xor(&I128::ONE).unwrap(), I128::ZERO); 127 | assert_eq!( 128 | I128::MAX.checked_xor(&I128::ONE).unwrap(), 129 | I128::MAX - I128::ONE 130 | ); 131 | } 132 | 133 | #[test] 134 | fn wrapping_xor_ok() { 135 | assert_eq!(I128::ZERO.wrapping_xor(&I128::ONE), I128::ONE); 136 | assert_eq!(I128::ONE.wrapping_xor(&I128::ONE), I128::ZERO); 137 | assert_eq!(I128::MAX.wrapping_xor(&I128::ONE), I128::MAX - I128::ONE); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/int/encoding.rs: -------------------------------------------------------------------------------- 1 | //! Const-friendly decoding/encoding operations for [`Int`]. 2 | 3 | use crate::{Int, Uint}; 4 | 5 | impl Int { 6 | /// Create a new [`Int`] from the provided big endian hex string. 7 | /// 8 | /// Panics if the hex is malformed or not zero-padded accordingly for the size. 9 | /// 10 | /// See [`Uint::from_be_hex`] for more details. 11 | pub const fn from_be_hex(hex: &str) -> Self { 12 | Self(Uint::from_be_hex(hex)) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/int/gcd.rs: -------------------------------------------------------------------------------- 1 | //! Support for computing the greatest common divisor of `Int`s. 2 | 3 | use crate::modular::SafeGcdInverter; 4 | use crate::{Gcd, Int, Odd, PrecomputeInverter, Uint}; 5 | 6 | /// Gcd of two [Int]s 7 | impl Gcd for Int 8 | where 9 | Odd>: PrecomputeInverter>, 10 | { 11 | type Output = Uint; 12 | 13 | fn gcd(&self, rhs: &Self) -> Self::Output { 14 | self.abs().gcd(&rhs.abs()) 15 | } 16 | 17 | fn gcd_vartime(&self, rhs: &Self) -> Self::Output { 18 | self.abs().gcd_vartime(&rhs.abs()) 19 | } 20 | } 21 | 22 | /// Gcd of an [Int] and a [Uint]. 23 | impl Gcd> for Int 24 | where 25 | Odd>: PrecomputeInverter>, 26 | { 27 | type Output = Uint; 28 | 29 | fn gcd(&self, rhs: &Uint) -> Self::Output { 30 | self.abs().gcd(rhs) 31 | } 32 | 33 | fn gcd_vartime(&self, rhs: &Uint) -> Self::Output { 34 | self.abs().gcd_vartime(rhs) 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use crate::{Gcd, I256, U256}; 41 | 42 | #[test] 43 | fn gcd_always_positive() { 44 | // Two numbers with a shared factor of 61 45 | let f = I256::from(59i32 * 61); 46 | let g = I256::from(61i32 * 71); 47 | 48 | assert_eq!(U256::from(61u32), f.gcd(&g)); 49 | assert_eq!(U256::from(61u32), f.wrapping_neg().gcd(&g)); 50 | assert_eq!(U256::from(61u32), f.gcd(&g.wrapping_neg())); 51 | assert_eq!(U256::from(61u32), f.wrapping_neg().gcd(&g.wrapping_neg())); 52 | } 53 | 54 | #[test] 55 | fn gcd_int_uint() { 56 | // Two numbers with a shared factor of 61 57 | let f = I256::from(59i32 * 61); 58 | let g = U256::from(61u32 * 71); 59 | 60 | assert_eq!(U256::from(61u32), f.gcd(&g)); 61 | assert_eq!(U256::from(61u32), f.wrapping_neg().gcd(&g)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/int/neg.rs: -------------------------------------------------------------------------------- 1 | //! [`Int`] negation-related operations. 2 | 3 | use crate::{ConstChoice, ConstCtOption, Int, Uint}; 4 | 5 | impl Int { 6 | /// Map this [`Int`] to its two's-complement negation: 7 | /// map `self` to `(self ^ 1111...1111) + 0000...0001`. 8 | /// 9 | /// Returns the negation, as well as whether the operation overflowed. 10 | /// The operation overflows when attempting to negate [`Int::MIN`]; the positive counterpart 11 | /// of this value cannot be represented. 12 | pub const fn overflowing_neg(&self) -> (Self, ConstChoice) { 13 | Self(self.0.bitxor(&Uint::MAX)).overflowing_add(&Int::ONE) 14 | } 15 | 16 | /// Wrapping negate this [`Int`]. 17 | /// 18 | /// Warning: this operation maps [`Int::MIN`] to itself, since the positive counterpart of this 19 | /// value cannot be represented. 20 | pub const fn wrapping_neg(&self) -> Self { 21 | self.overflowing_neg().0 22 | } 23 | 24 | /// Wrapping negate this [`Int`] if `negate` is truthy; otherwise do nothing. 25 | /// 26 | /// Warning: this operation maps [`Int::MIN`] to itself, since the positive counterpart of this 27 | /// value cannot be represented. 28 | pub const fn wrapping_neg_if(&self, negate: ConstChoice) -> Int { 29 | Self(self.0.wrapping_neg_if(negate)) 30 | } 31 | 32 | /// Negate this [`Int`]. 33 | /// 34 | /// Yields `None` when `self == Self::MIN`, since the positive counterpart of this value cannot 35 | /// be represented. 36 | pub const fn checked_neg(&self) -> ConstCtOption { 37 | let (value, overflow) = self.overflowing_neg(); 38 | ConstCtOption::new(value, overflow.not()) 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use crate::{ConstChoice, I128}; 45 | 46 | #[test] 47 | fn overflowing_neg() { 48 | let min_plus_one = I128 { 49 | 0: I128::MIN.0.wrapping_add(&I128::ONE.0), 50 | }; 51 | 52 | let (res, overflow) = I128::MIN.overflowing_neg(); 53 | assert_eq!(res, I128::MIN); 54 | assert_eq!(overflow, ConstChoice::TRUE); 55 | 56 | let (res, overflow) = I128::MINUS_ONE.overflowing_neg(); 57 | assert_eq!(res, I128::ONE); 58 | assert_eq!(overflow, ConstChoice::FALSE); 59 | 60 | let (res, overflow) = I128::ZERO.overflowing_neg(); 61 | assert_eq!(res, I128::ZERO); 62 | assert_eq!(overflow, ConstChoice::FALSE); 63 | 64 | let (res, overflow) = I128::ONE.overflowing_neg(); 65 | assert_eq!(res, I128::MINUS_ONE); 66 | assert_eq!(overflow, ConstChoice::FALSE); 67 | 68 | let (res, overflow) = I128::MAX.overflowing_neg(); 69 | assert_eq!(res, min_plus_one); 70 | assert_eq!(overflow, ConstChoice::FALSE); 71 | } 72 | 73 | #[test] 74 | fn wrapping_neg_if() { 75 | let min_plus_one = I128 { 76 | 0: I128::MIN.0.wrapping_add(&I128::ONE.0), 77 | }; 78 | 79 | let do_negate = ConstChoice::TRUE; 80 | assert_eq!(I128::MIN.wrapping_neg_if(do_negate), I128::MIN); 81 | assert_eq!(I128::MINUS_ONE.wrapping_neg_if(do_negate), I128::ONE); 82 | assert_eq!(I128::ZERO.wrapping_neg_if(do_negate), I128::ZERO); 83 | assert_eq!(I128::ONE.wrapping_neg_if(do_negate), I128::MINUS_ONE); 84 | assert_eq!(I128::MAX.wrapping_neg_if(do_negate), min_plus_one); 85 | 86 | let do_not_negate = ConstChoice::FALSE; 87 | assert_eq!(I128::MIN.wrapping_neg_if(do_not_negate), I128::MIN); 88 | assert_eq!( 89 | I128::MINUS_ONE.wrapping_neg_if(do_not_negate), 90 | I128::MINUS_ONE 91 | ); 92 | assert_eq!(I128::ZERO.wrapping_neg_if(do_not_negate), I128::ZERO); 93 | assert_eq!(I128::ONE.wrapping_neg_if(do_not_negate), I128::ONE); 94 | assert_eq!(I128::MAX.wrapping_neg_if(do_not_negate), I128::MAX); 95 | } 96 | 97 | #[test] 98 | fn checked_neg() { 99 | assert_eq!(I128::MIN.checked_neg().is_none(), ConstChoice::TRUE); 100 | assert_eq!(I128::MINUS_ONE.checked_neg().unwrap(), I128::ONE); 101 | assert_eq!(I128::ZERO.checked_neg().unwrap(), I128::ZERO); 102 | assert_eq!(I128::ONE.checked_neg().unwrap(), I128::MINUS_ONE); 103 | assert_eq!( 104 | I128::MAX.checked_neg().unwrap(), 105 | I128::from_be_hex("80000000000000000000000000000001") 106 | ); 107 | 108 | let negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF"); 109 | let positive = I128::from_be_hex("6EEECCCCAAAA88886666444422220001"); 110 | assert_eq!(negative.checked_neg().unwrap(), positive); 111 | assert_eq!(positive.checked_neg().unwrap(), negative); 112 | assert_eq!( 113 | positive.checked_neg().unwrap().checked_neg().unwrap(), 114 | positive 115 | ); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/int/rand.rs: -------------------------------------------------------------------------------- 1 | //! Random number generator support 2 | 3 | use rand_core::TryRngCore; 4 | 5 | use crate::{Int, Random, RandomBits, RandomBitsError}; 6 | 7 | use super::Uint; 8 | 9 | impl Random for Int { 10 | /// Generate a cryptographically secure random [`Int`]. 11 | fn try_random(rng: &mut R) -> Result { 12 | Ok(Self(Uint::try_random(rng)?)) 13 | } 14 | } 15 | 16 | impl RandomBits for Int { 17 | fn try_random_bits( 18 | rng: &mut R, 19 | bit_length: u32, 20 | ) -> Result> { 21 | Self::try_random_bits_with_precision(rng, bit_length, Self::BITS) 22 | } 23 | 24 | fn try_random_bits_with_precision( 25 | rng: &mut R, 26 | bit_length: u32, 27 | bits_precision: u32, 28 | ) -> Result> { 29 | Uint::try_random_bits_with_precision(rng, bit_length, bits_precision).map(Self) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/int/resize.rs: -------------------------------------------------------------------------------- 1 | use crate::{Int, Limb, Uint}; 2 | 3 | impl Int { 4 | /// Resize the representation of `self` to an `Int`. 5 | /// Warning: this operation may lead to loss of information. 6 | #[inline(always)] 7 | pub const fn resize(&self) -> Int { 8 | let mut limbs = [Limb::select(Limb::ZERO, Limb::MAX, self.is_negative()); T]; 9 | let mut i = 0; 10 | let dim = if T < LIMBS { T } else { LIMBS }; 11 | while i < dim { 12 | limbs[i] = self.0.limbs[i]; 13 | i += 1; 14 | } 15 | Uint { limbs }.as_int() 16 | } 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use num_traits::WrappingSub; 22 | 23 | use crate::{I128, I256}; 24 | 25 | #[test] 26 | fn scale_down() { 27 | assert_eq!(I256::MIN.resize::<{ I128::LIMBS }>(), I128::ZERO); 28 | assert_eq!(I256::MINUS_ONE.resize::<{ I128::LIMBS }>(), I128::MINUS_ONE); 29 | assert_eq!(I256::ZERO.resize::<{ I128::LIMBS }>(), I128::ZERO); 30 | assert_eq!(I256::ONE.resize::<{ I128::LIMBS }>(), I128::ONE); 31 | assert_eq!(I256::MAX.resize::<{ I128::LIMBS }>(), I128::MINUS_ONE); 32 | } 33 | 34 | #[test] 35 | fn scale_up() { 36 | assert_eq!( 37 | I128::MIN.resize::<{ I256::LIMBS }>(), 38 | I256::ZERO.wrapping_sub(&I256 { 39 | 0: I128::MIN.0.resize() 40 | }) 41 | ); 42 | assert_eq!(I128::MINUS_ONE.resize::<{ I256::LIMBS }>(), I256::MINUS_ONE); 43 | assert_eq!(I128::ZERO.resize::<{ I256::LIMBS }>(), I256::ZERO); 44 | assert_eq!(I128::ONE.resize::<{ I256::LIMBS }>(), I256::ONE); 45 | assert_eq!( 46 | I128::MAX.resize::<{ I256::LIMBS }>(), 47 | I128::MAX.0.resize().as_int() 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/int/sign.rs: -------------------------------------------------------------------------------- 1 | use crate::{ConstChoice, ConstCtOption, Int, Uint, Word}; 2 | use num_traits::ConstZero; 3 | 4 | impl Int { 5 | /// Returns the word of most significant [`Limb`]. 6 | /// For the generative case where the number of limbs is zero, 7 | /// zeroed word is returned (which is semantically correct). 8 | /// This method leaks the limb length of the value, which is also OK. 9 | const fn most_significant_word(&self) -> Word { 10 | if Self::LIMBS == 0 { 11 | Word::ZERO 12 | } else { 13 | self.0.to_words()[LIMBS - 1] 14 | } 15 | } 16 | 17 | /// Construct new [`Int`] from an absolute value and sign. 18 | /// Returns `None` when the absolute value does not fit in an [`Int`]. 19 | pub const fn new_from_abs_sign( 20 | abs: Uint, 21 | is_negative: ConstChoice, 22 | ) -> ConstCtOption { 23 | let magnitude = Self(abs).wrapping_neg_if(is_negative); 24 | let fits = Uint::lte(&abs, &Int::MAX.0).or(is_negative.and(Uint::eq(&abs, &Int::MIN.0))); 25 | ConstCtOption::new(magnitude, fits) 26 | } 27 | 28 | /// Whether this [`Int`] is negative, as a `ConstChoice`. 29 | pub const fn is_negative(&self) -> ConstChoice { 30 | ConstChoice::from_word_msb(self.most_significant_word()) 31 | } 32 | 33 | /// Whether this [`Int`] is positive, as a `ConstChoice`. 34 | pub const fn is_positive(&self) -> ConstChoice { 35 | self.is_negative().not().and(self.is_nonzero()) 36 | } 37 | 38 | /// The sign and magnitude of this [`Int`]. 39 | pub const fn abs_sign(&self) -> (Uint, ConstChoice) { 40 | let sign = self.is_negative(); 41 | // Note: this negate_if is safe to use, since we are negating based on self.is_negative() 42 | let abs = self.wrapping_neg_if(sign); 43 | (abs.0, sign) 44 | } 45 | 46 | /// The magnitude of this [`Int`]. 47 | pub const fn abs(&self) -> Uint { 48 | self.abs_sign().0 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | use crate::I128; 56 | 57 | #[test] 58 | fn is_negative() { 59 | assert_eq!(I128::MIN.is_negative(), ConstChoice::TRUE); 60 | assert_eq!(I128::MINUS_ONE.is_negative(), ConstChoice::TRUE); 61 | assert_eq!(I128::ZERO.is_negative(), ConstChoice::FALSE); 62 | assert_eq!(I128::ONE.is_negative(), ConstChoice::FALSE); 63 | assert_eq!(I128::MAX.is_negative(), ConstChoice::FALSE); 64 | 65 | let random_negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF"); 66 | assert_eq!(random_negative.is_negative(), ConstChoice::TRUE); 67 | 68 | let random_positive = I128::from_be_hex("71113333555577779999BBBBDDDDFFFF"); 69 | assert_eq!(random_positive.is_negative(), ConstChoice::FALSE); 70 | } 71 | 72 | #[test] 73 | fn is_positive() { 74 | assert_eq!(I128::MIN.is_positive(), ConstChoice::FALSE); 75 | assert_eq!(I128::MINUS_ONE.is_positive(), ConstChoice::FALSE); 76 | assert_eq!(I128::ZERO.is_positive(), ConstChoice::FALSE); 77 | assert_eq!(I128::ONE.is_positive(), ConstChoice::TRUE); 78 | assert_eq!(I128::MAX.is_positive(), ConstChoice::TRUE); 79 | 80 | let random_negative = I128::from_be_hex("deadbeefcafebabedeadbeefcafebabe"); 81 | assert_eq!(random_negative.is_positive(), ConstChoice::FALSE); 82 | 83 | let random_positive = I128::from_be_hex("0badc0dedeadc0decafebabedeadcafe"); 84 | assert_eq!(random_positive.is_positive(), ConstChoice::TRUE); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/int/types.rs: -------------------------------------------------------------------------------- 1 | //! Selection of [`Int`] types. 2 | //! todo: replace with macro implementation once serde is set up. 3 | 4 | use crate::Int; 5 | 6 | #[cfg(target_pointer_width = "64")] 7 | /// Signed bit integer. 8 | pub type I64 = Int<1>; 9 | 10 | #[cfg(target_pointer_width = "64")] 11 | /// Signed bit integer. 12 | pub type I128 = Int<2>; 13 | 14 | #[cfg(target_pointer_width = "64")] 15 | /// Signed bit integer. 16 | pub type I256 = Int<4>; 17 | 18 | #[cfg(target_pointer_width = "64")] 19 | /// Signed bit integer. 20 | pub type I512 = Int<8>; 21 | 22 | #[cfg(target_pointer_width = "64")] 23 | /// Signed bit integer. 24 | pub type I1024 = Int<16>; 25 | 26 | #[cfg(target_pointer_width = "64")] 27 | /// Signed bit integer. 28 | pub type I2048 = Int<32>; 29 | 30 | #[cfg(target_pointer_width = "64")] 31 | /// Signed bit integer. 32 | pub type I4096 = Int<64>; 33 | 34 | #[cfg(target_pointer_width = "32")] 35 | /// Signed bit integer. 36 | pub type I64 = Int<2>; 37 | 38 | #[cfg(target_pointer_width = "32")] 39 | /// Signed bit integer. 40 | pub type I128 = Int<4>; 41 | 42 | #[cfg(target_pointer_width = "32")] 43 | /// Signed bit integer. 44 | pub type I256 = Int<8>; 45 | 46 | #[cfg(target_pointer_width = "32")] 47 | /// Signed bit integer. 48 | pub type I512 = Int<16>; 49 | 50 | #[cfg(target_pointer_width = "32")] 51 | /// Signed bit integer. 52 | pub type I1024 = Int<32>; 53 | 54 | #[cfg(target_pointer_width = "32")] 55 | /// Signed bit integer. 56 | pub type I2048 = Int<64>; 57 | 58 | #[cfg(target_pointer_width = "32")] 59 | /// Signed bit integer. 60 | pub type I4096 = Int<128>; 61 | -------------------------------------------------------------------------------- /src/limb/add.rs: -------------------------------------------------------------------------------- 1 | //! Limb addition 2 | 3 | use crate::{ 4 | Checked, CheckedAdd, Limb, Wrapping, WrappingAdd, Zero, 5 | primitives::{carrying_add, overflowing_add}, 6 | }; 7 | use core::ops::{Add, AddAssign}; 8 | use subtle::CtOption; 9 | 10 | impl Limb { 11 | /// Computes `self + rhs`, returning the result along with the carry. 12 | #[inline(always)] 13 | pub const fn overflowing_add(self, rhs: Limb) -> (Limb, Limb) { 14 | let (res, carry) = overflowing_add(self.0, rhs.0); 15 | (Limb(res), Limb(carry)) 16 | } 17 | 18 | /// Computes `self + rhs + carry`, returning the result along with the new carry. 19 | #[deprecated(since = "0.7.0", note = "please use `carrying_add` instead")] 20 | pub const fn adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb) { 21 | self.carrying_add(rhs, carry) 22 | } 23 | 24 | /// Computes `self + rhs + carry`, returning the result along with the new carry. 25 | #[inline(always)] 26 | pub const fn carrying_add(self, rhs: Limb, carry: Limb) -> (Limb, Limb) { 27 | let (res, carry) = carrying_add(self.0, rhs.0, carry.0); 28 | (Limb(res), Limb(carry)) 29 | } 30 | 31 | /// Perform saturating addition. 32 | #[inline] 33 | pub const fn saturating_add(&self, rhs: Self) -> Self { 34 | Limb(self.0.saturating_add(rhs.0)) 35 | } 36 | 37 | /// Perform wrapping addition, discarding overflow. 38 | #[inline(always)] 39 | pub const fn wrapping_add(&self, rhs: Self) -> Self { 40 | Limb(self.0.wrapping_add(rhs.0)) 41 | } 42 | } 43 | 44 | impl Add for Limb { 45 | type Output = Self; 46 | 47 | #[inline] 48 | fn add(self, rhs: Self) -> Self { 49 | self.checked_add(&rhs) 50 | .expect("attempted to add with overflow") 51 | } 52 | } 53 | 54 | impl AddAssign for Wrapping { 55 | #[inline] 56 | fn add_assign(&mut self, other: Self) { 57 | *self = *self + other; 58 | } 59 | } 60 | 61 | impl AddAssign<&Wrapping> for Wrapping { 62 | #[inline] 63 | fn add_assign(&mut self, other: &Self) { 64 | *self = *self + other; 65 | } 66 | } 67 | 68 | impl AddAssign for Checked { 69 | #[inline] 70 | fn add_assign(&mut self, other: Self) { 71 | *self = *self + other; 72 | } 73 | } 74 | 75 | impl AddAssign<&Checked> for Checked { 76 | #[inline] 77 | fn add_assign(&mut self, other: &Self) { 78 | *self = *self + other; 79 | } 80 | } 81 | 82 | impl CheckedAdd for Limb { 83 | #[inline] 84 | fn checked_add(&self, rhs: &Self) -> CtOption { 85 | let (result, carry) = self.overflowing_add(*rhs); 86 | CtOption::new(result, carry.is_zero()) 87 | } 88 | } 89 | 90 | impl WrappingAdd for Limb { 91 | #[inline] 92 | fn wrapping_add(&self, v: &Self) -> Self { 93 | self.wrapping_add(*v) 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests { 99 | use crate::{CheckedAdd, Limb}; 100 | 101 | #[test] 102 | fn carrying_add_no_carry() { 103 | let (res, carry) = Limb::ZERO.overflowing_add(Limb::ONE); 104 | assert_eq!(res, Limb::ONE); 105 | assert_eq!(carry, Limb::ZERO); 106 | } 107 | 108 | #[test] 109 | fn carrying_add_with_carry() { 110 | let (res, carry) = Limb::MAX.overflowing_add(Limb::ONE); 111 | assert_eq!(res, Limb::ZERO); 112 | assert_eq!(carry, Limb::ONE); 113 | } 114 | 115 | #[test] 116 | fn wrapping_add_no_carry() { 117 | assert_eq!(Limb::ZERO.wrapping_add(Limb::ONE), Limb::ONE); 118 | } 119 | 120 | #[test] 121 | fn wrapping_add_with_carry() { 122 | assert_eq!(Limb::MAX.wrapping_add(Limb::ONE), Limb::ZERO); 123 | } 124 | 125 | #[test] 126 | fn checked_add_ok() { 127 | let result = Limb::ZERO.checked_add(&Limb::ONE); 128 | assert_eq!(result.unwrap(), Limb::ONE); 129 | } 130 | 131 | #[test] 132 | fn checked_add_overflow() { 133 | let result = Limb::MAX.checked_add(&Limb::ONE); 134 | assert!(!bool::from(result.is_some())); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/limb/bit_and.rs: -------------------------------------------------------------------------------- 1 | //! Limb bit and operations. 2 | 3 | use super::Limb; 4 | use core::ops::{BitAnd, BitAndAssign}; 5 | 6 | impl Limb { 7 | /// Calculates `a & b`. 8 | #[inline(always)] 9 | pub const fn bitand(self, rhs: Self) -> Self { 10 | Limb(self.0 & rhs.0) 11 | } 12 | } 13 | 14 | impl BitAnd for Limb { 15 | type Output = Limb; 16 | 17 | #[inline(always)] 18 | fn bitand(self, rhs: Self) -> Self::Output { 19 | self.bitand(rhs) 20 | } 21 | } 22 | 23 | impl BitAndAssign for Limb { 24 | fn bitand_assign(&mut self, rhs: Self) { 25 | self.0 &= rhs.0; 26 | } 27 | } 28 | 29 | impl BitAndAssign<&Limb> for Limb { 30 | fn bitand_assign(&mut self, rhs: &Limb) { 31 | self.0 &= rhs.0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/limb/bit_not.rs: -------------------------------------------------------------------------------- 1 | //! Limb bit not operations. 2 | 3 | use super::Limb; 4 | use core::ops::Not; 5 | 6 | impl Limb { 7 | /// Calculates `!a`. 8 | #[inline(always)] 9 | pub const fn not(self) -> Self { 10 | Limb(!self.0) 11 | } 12 | } 13 | 14 | impl Not for Limb { 15 | type Output = Limb; 16 | 17 | fn not(self) -> ::Output { 18 | self.not() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/limb/bit_or.rs: -------------------------------------------------------------------------------- 1 | //! Limb bit or operations. 2 | 3 | use super::Limb; 4 | use core::ops::{BitOr, BitOrAssign}; 5 | 6 | impl Limb { 7 | /// Calculates `a | b`. 8 | #[inline(always)] 9 | pub const fn bitor(self, rhs: Self) -> Self { 10 | Limb(self.0 | rhs.0) 11 | } 12 | } 13 | 14 | impl BitOr for Limb { 15 | type Output = Limb; 16 | 17 | fn bitor(self, rhs: Self) -> Self::Output { 18 | self.bitor(rhs) 19 | } 20 | } 21 | 22 | impl BitOrAssign for Limb { 23 | fn bitor_assign(&mut self, other: Self) { 24 | *self = self.bitor(other); 25 | } 26 | } 27 | 28 | impl BitOrAssign<&Limb> for Limb { 29 | fn bitor_assign(&mut self, other: &Self) { 30 | *self = self.bitor(*other); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/limb/bit_xor.rs: -------------------------------------------------------------------------------- 1 | //! Limb bit xor operations. 2 | 3 | use super::Limb; 4 | use core::ops::{BitXor, BitXorAssign}; 5 | 6 | impl Limb { 7 | /// Calculates `a ^ b`. 8 | #[inline(always)] 9 | pub const fn bitxor(self, rhs: Self) -> Self { 10 | Limb(self.0 ^ rhs.0) 11 | } 12 | } 13 | 14 | impl BitXor for Limb { 15 | type Output = Limb; 16 | 17 | fn bitxor(self, rhs: Self) -> Self::Output { 18 | self.bitxor(rhs) 19 | } 20 | } 21 | 22 | impl BitXorAssign for Limb { 23 | fn bitxor_assign(&mut self, rhs: Self) { 24 | self.0 ^= rhs.0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/limb/bits.rs: -------------------------------------------------------------------------------- 1 | use super::Limb; 2 | 3 | impl Limb { 4 | /// Calculate the number of bits needed to represent this number. 5 | #[inline(always)] 6 | pub const fn bits(self) -> u32 { 7 | Limb::BITS - self.0.leading_zeros() 8 | } 9 | 10 | /// Calculate the number of leading zeros in the binary representation of this number. 11 | #[inline(always)] 12 | pub const fn leading_zeros(self) -> u32 { 13 | self.0.leading_zeros() 14 | } 15 | 16 | /// Calculate the number of trailing zeros in the binary representation of this number. 17 | #[inline(always)] 18 | pub const fn trailing_zeros(self) -> u32 { 19 | self.0.trailing_zeros() 20 | } 21 | 22 | /// Calculate the number of trailing ones the binary representation of this number. 23 | #[inline(always)] 24 | pub const fn trailing_ones(self) -> u32 { 25 | self.0.trailing_ones() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/limb/encoding.rs: -------------------------------------------------------------------------------- 1 | //! Limb encoding 2 | 3 | use super::{Limb, Word}; 4 | use crate::Encoding; 5 | 6 | impl Encoding for Limb { 7 | #[cfg(target_pointer_width = "32")] 8 | type Repr = [u8; 4]; 9 | #[cfg(target_pointer_width = "64")] 10 | type Repr = [u8; 8]; 11 | 12 | #[inline] 13 | fn from_be_bytes(bytes: Self::Repr) -> Self { 14 | Limb(Word::from_be_bytes(bytes)) 15 | } 16 | 17 | #[inline] 18 | fn from_le_bytes(bytes: Self::Repr) -> Self { 19 | Limb(Word::from_le_bytes(bytes)) 20 | } 21 | 22 | #[inline] 23 | fn to_be_bytes(&self) -> Self::Repr { 24 | self.0.to_be_bytes() 25 | } 26 | 27 | #[inline] 28 | fn to_le_bytes(&self) -> Self::Repr { 29 | self.0.to_le_bytes() 30 | } 31 | } 32 | 33 | #[cfg(feature = "alloc")] 34 | impl Limb { 35 | /// Decode limb from a big endian byte slice. 36 | /// 37 | /// Panics if the slice is larger than [`Limb::Repr`]. 38 | pub(crate) fn from_be_slice(bytes: &[u8]) -> Self { 39 | let mut repr = Self::ZERO.to_be_bytes(); 40 | let repr_len = repr.len(); 41 | assert!( 42 | bytes.len() <= repr_len, 43 | "The given slice is larger than the limb size" 44 | ); 45 | repr[(repr_len - bytes.len())..].copy_from_slice(bytes); 46 | Self::from_be_bytes(repr) 47 | } 48 | 49 | /// Decode limb from a little endian byte slice. 50 | /// 51 | /// Panics if the slice is not the same size as [`Limb::Repr`]. 52 | pub(crate) fn from_le_slice(bytes: &[u8]) -> Self { 53 | let mut repr = Self::ZERO.to_le_bytes(); 54 | let repr_len = repr.len(); 55 | assert!( 56 | bytes.len() <= repr_len, 57 | "The given slice is larger than the limb size" 58 | ); 59 | repr[..bytes.len()].copy_from_slice(bytes); 60 | Self::from_le_bytes(repr) 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod test { 66 | use super::*; 67 | 68 | #[cfg(target_pointer_width = "32")] 69 | const LIMB: Limb = Limb(0x7654_3210); 70 | 71 | #[cfg(target_pointer_width = "64")] 72 | const LIMB: Limb = Limb(0xFEDCBA9876543210); 73 | 74 | #[test] 75 | fn roundtrip() { 76 | assert_eq!(LIMB, Limb::from_be_bytes(LIMB.to_be_bytes())); 77 | assert_eq!(LIMB, Limb::from_le_bytes(LIMB.to_le_bytes())); 78 | } 79 | 80 | #[test] 81 | fn reverse() { 82 | let mut bytes = LIMB.to_be_bytes(); 83 | bytes.reverse(); 84 | assert_eq!(LIMB, Limb::from_le_bytes(bytes)); 85 | 86 | let mut bytes = LIMB.to_le_bytes(); 87 | bytes.reverse(); 88 | assert_eq!(LIMB, Limb::from_be_bytes(bytes)); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/limb/from.rs: -------------------------------------------------------------------------------- 1 | //! `From`-like conversions for [`Limb`]. 2 | 3 | use super::{Limb, WideWord, Word}; 4 | 5 | impl Limb { 6 | /// Create a [`Limb`] from a `u8` integer (const-friendly) 7 | // TODO(tarcieri): replace with `const impl From` when stable 8 | pub const fn from_u8(n: u8) -> Self { 9 | Limb(n as Word) 10 | } 11 | 12 | /// Create a [`Limb`] from a `u16` integer (const-friendly) 13 | // TODO(tarcieri): replace with `const impl From` when stable 14 | pub const fn from_u16(n: u16) -> Self { 15 | Limb(n as Word) 16 | } 17 | 18 | /// Create a [`Limb`] from a `u32` integer (const-friendly) 19 | // TODO(tarcieri): replace with `const impl From` when stable 20 | pub const fn from_u32(n: u32) -> Self { 21 | #[allow(trivial_numeric_casts)] 22 | Limb(n as Word) 23 | } 24 | 25 | /// Create a [`Limb`] from a `u64` integer (const-friendly) 26 | // TODO(tarcieri): replace with `const impl From` when stable 27 | #[cfg(target_pointer_width = "64")] 28 | pub const fn from_u64(n: u64) -> Self { 29 | Limb(n) 30 | } 31 | } 32 | 33 | impl From for Limb { 34 | #[inline] 35 | fn from(n: u8) -> Limb { 36 | Limb(n.into()) 37 | } 38 | } 39 | 40 | impl From for Limb { 41 | #[inline] 42 | fn from(n: u16) -> Limb { 43 | Limb(n.into()) 44 | } 45 | } 46 | 47 | impl From for Limb { 48 | #[inline] 49 | fn from(n: u32) -> Limb { 50 | Limb(n.into()) 51 | } 52 | } 53 | 54 | #[cfg(target_pointer_width = "64")] 55 | impl From for Limb { 56 | #[inline] 57 | fn from(n: u64) -> Limb { 58 | Limb(n) 59 | } 60 | } 61 | 62 | impl From for Word { 63 | #[inline] 64 | fn from(limb: Limb) -> Word { 65 | limb.0 66 | } 67 | } 68 | 69 | impl From for WideWord { 70 | #[inline] 71 | fn from(limb: Limb) -> WideWord { 72 | limb.0.into() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/limb/mul.rs: -------------------------------------------------------------------------------- 1 | //! Limb multiplication 2 | 3 | use crate::{ 4 | Checked, CheckedMul, Limb, Wrapping, Zero, 5 | primitives::{carrying_mul_add, widening_mul}, 6 | }; 7 | use core::ops::{Mul, MulAssign}; 8 | use num_traits::WrappingMul; 9 | use subtle::CtOption; 10 | 11 | impl Limb { 12 | /// Computes `self + (b * c) + carry`, returning the result along with the new carry. 13 | #[deprecated( 14 | since = "0.7.0", 15 | note = "please use `carrying_mul_add` instead (ordering of arguments changes)" 16 | )] 17 | pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) { 18 | b.carrying_mul_add(c, self, carry) 19 | } 20 | 21 | /// Computes `(self * rhs) + addend + carry`, returning the result along with the new carry. 22 | #[inline(always)] 23 | pub const fn carrying_mul_add(self, rhs: Limb, addend: Limb, carry: Limb) -> (Limb, Limb) { 24 | let (res, carry) = carrying_mul_add(self.0, rhs.0, addend.0, carry.0); 25 | (Limb(res), Limb(carry)) 26 | } 27 | 28 | /// Perform saturating multiplication. 29 | #[inline(always)] 30 | pub const fn saturating_mul(&self, rhs: Self) -> Self { 31 | Limb(self.0.saturating_mul(rhs.0)) 32 | } 33 | 34 | /// Perform wrapping multiplication, discarding overflow. 35 | #[inline(always)] 36 | pub const fn wrapping_mul(&self, rhs: Self) -> Self { 37 | Limb(self.0.wrapping_mul(rhs.0)) 38 | } 39 | 40 | /// Compute "wide" multiplication, with a product twice the size of the input. 41 | pub(crate) const fn widening_mul(&self, rhs: Self) -> (Self, Self) { 42 | let (lo, hi) = widening_mul(self.0, rhs.0); 43 | (Limb(lo), Limb(hi)) 44 | } 45 | } 46 | 47 | impl CheckedMul for Limb { 48 | #[inline] 49 | fn checked_mul(&self, rhs: &Self) -> CtOption { 50 | let (lo, hi) = self.widening_mul(*rhs); 51 | CtOption::new(lo, hi.is_zero()) 52 | } 53 | } 54 | 55 | impl Mul for Limb { 56 | type Output = Limb; 57 | 58 | #[inline] 59 | fn mul(self, rhs: Limb) -> Self { 60 | self.checked_mul(&rhs) 61 | .expect("attempted to multiply with overflow") 62 | } 63 | } 64 | 65 | impl Mul<&Limb> for Limb { 66 | type Output = Limb; 67 | 68 | #[inline] 69 | fn mul(self, rhs: &Limb) -> Self { 70 | self * *rhs 71 | } 72 | } 73 | 74 | impl Mul for &Limb { 75 | type Output = Limb; 76 | 77 | #[inline] 78 | fn mul(self, rhs: Limb) -> Self::Output { 79 | *self * rhs 80 | } 81 | } 82 | 83 | impl Mul<&Limb> for &Limb { 84 | type Output = Limb; 85 | 86 | #[inline] 87 | fn mul(self, rhs: &Limb) -> Self::Output { 88 | *self * *rhs 89 | } 90 | } 91 | 92 | impl MulAssign for Wrapping { 93 | #[inline] 94 | fn mul_assign(&mut self, other: Self) { 95 | *self = *self * other; 96 | } 97 | } 98 | 99 | impl MulAssign<&Wrapping> for Wrapping { 100 | #[inline] 101 | fn mul_assign(&mut self, other: &Self) { 102 | *self = *self * other; 103 | } 104 | } 105 | 106 | impl MulAssign for Checked { 107 | #[inline] 108 | fn mul_assign(&mut self, other: Self) { 109 | *self = *self * other; 110 | } 111 | } 112 | 113 | impl MulAssign<&Checked> for Checked { 114 | #[inline] 115 | fn mul_assign(&mut self, other: &Self) { 116 | *self = *self * other; 117 | } 118 | } 119 | 120 | impl WrappingMul for Limb { 121 | #[inline] 122 | fn wrapping_mul(&self, v: &Self) -> Self { 123 | self.wrapping_mul(*v) 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod tests { 129 | use super::{CheckedMul, Limb}; 130 | 131 | #[test] 132 | #[cfg(target_pointer_width = "32")] 133 | fn checked_mul_ok() { 134 | let n = Limb::from_u16(0xffff); 135 | assert_eq!(n.checked_mul(&n).unwrap(), Limb::from_u32(0xfffe_0001)); 136 | } 137 | 138 | #[test] 139 | #[cfg(target_pointer_width = "64")] 140 | fn checked_mul_ok() { 141 | let n = Limb::from_u32(0xffff_ffff); 142 | assert_eq!( 143 | n.checked_mul(&n).unwrap(), 144 | Limb::from_u64(0xffff_fffe_0000_0001) 145 | ); 146 | } 147 | 148 | #[test] 149 | fn checked_mul_overflow() { 150 | let n = Limb::MAX; 151 | assert!(bool::from(n.checked_mul(&n).is_none())); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/limb/neg.rs: -------------------------------------------------------------------------------- 1 | //! Limb negation 2 | 3 | use crate::Limb; 4 | use num_traits::WrappingNeg; 5 | 6 | impl Limb { 7 | /// Perform wrapping negation. 8 | #[inline(always)] 9 | pub const fn wrapping_neg(self) -> Self { 10 | Limb(self.0.wrapping_neg()) 11 | } 12 | } 13 | 14 | impl WrappingNeg for Limb { 15 | #[inline] 16 | fn wrapping_neg(&self) -> Self { 17 | Self(self.0.wrapping_neg()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/limb/rand.rs: -------------------------------------------------------------------------------- 1 | //! Random number generator support 2 | 3 | use super::Limb; 4 | use crate::{Encoding, NonZero, Random, RandomMod}; 5 | use rand_core::TryRngCore; 6 | use subtle::ConstantTimeLess; 7 | 8 | impl Random for Limb { 9 | fn try_random(rng: &mut R) -> Result { 10 | #[cfg(target_pointer_width = "32")] 11 | let val = rng.try_next_u32()?; 12 | #[cfg(target_pointer_width = "64")] 13 | let val = rng.try_next_u64()?; 14 | 15 | Ok(Self(val)) 16 | } 17 | } 18 | 19 | impl RandomMod for Limb { 20 | fn try_random_mod( 21 | rng: &mut R, 22 | modulus: &NonZero, 23 | ) -> Result { 24 | let mut bytes = ::Repr::default(); 25 | 26 | let n_bits = modulus.bits() as usize; 27 | let n_bytes = n_bits.div_ceil(8); 28 | let mask = 0xffu8 >> (8 * n_bytes - n_bits); 29 | 30 | loop { 31 | rng.try_fill_bytes(&mut bytes[..n_bytes])?; 32 | bytes[n_bytes - 1] &= mask; 33 | 34 | let n = Limb::from_le_bytes(bytes); 35 | if n.ct_lt(modulus).into() { 36 | return Ok(n); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/limb/shl.rs: -------------------------------------------------------------------------------- 1 | //! Limb left bitshift 2 | 3 | use crate::Limb; 4 | use core::ops::{Shl, ShlAssign}; 5 | use num_traits::WrappingShl; 6 | 7 | impl Limb { 8 | /// Computes `self << shift`. 9 | /// Panics if `shift` overflows `Limb::BITS`. 10 | #[inline(always)] 11 | pub const fn shl(self, shift: u32) -> Self { 12 | Limb(self.0 << shift) 13 | } 14 | 15 | /// Computes `self << 1` and return the result and the carry (0 or 1). 16 | #[inline(always)] 17 | pub(crate) const fn shl1(self) -> (Self, Self) { 18 | (Self(self.0 << 1), Self(self.0 >> Self::HI_BIT)) 19 | } 20 | } 21 | 22 | macro_rules! impl_shl { 23 | ($($shift:ty),+) => { 24 | $( 25 | impl Shl<$shift> for Limb { 26 | type Output = Limb; 27 | 28 | #[inline] 29 | fn shl(self, shift: $shift) -> Limb { 30 | Self::shl(self, u32::try_from(shift).expect("invalid shift")) 31 | } 32 | } 33 | 34 | impl Shl<$shift> for &Limb { 35 | type Output = Limb; 36 | 37 | #[inline] 38 | fn shl(self, shift: $shift) -> Limb { 39 | *self << shift 40 | } 41 | } 42 | 43 | impl ShlAssign<$shift> for Limb { 44 | #[inline] 45 | fn shl_assign(&mut self, shift: $shift) { 46 | *self = *self << shift; 47 | } 48 | } 49 | )+ 50 | }; 51 | } 52 | 53 | impl_shl!(i32, u32, usize); 54 | 55 | impl WrappingShl for Limb { 56 | #[inline] 57 | fn wrapping_shl(&self, shift: u32) -> Limb { 58 | Self(self.0.wrapping_shl(shift)) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | use crate::Limb; 65 | 66 | #[test] 67 | fn shl1() { 68 | assert_eq!(Limb(1) << 1, Limb(2)); 69 | } 70 | 71 | #[test] 72 | fn shl2() { 73 | assert_eq!(Limb(1) << 2, Limb(4)); 74 | } 75 | 76 | #[test] 77 | fn shl_assign1() { 78 | let mut l = Limb(1); 79 | l <<= 1; 80 | assert_eq!(l, Limb(2)); 81 | } 82 | 83 | #[test] 84 | fn shl_assign2() { 85 | let mut l = Limb(1); 86 | l <<= 2; 87 | assert_eq!(l, Limb(4)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/limb/shr.rs: -------------------------------------------------------------------------------- 1 | //! Limb right bitshift 2 | 3 | use crate::{Limb, WrappingShr}; 4 | use core::ops::{Shr, ShrAssign}; 5 | 6 | impl Limb { 7 | /// Computes `self >> shift`. 8 | /// Panics if `shift` overflows `Limb::BITS`. 9 | #[inline(always)] 10 | pub const fn shr(self, shift: u32) -> Self { 11 | Limb(self.0 >> shift) 12 | } 13 | 14 | /// Computes `self >> 1` and return the result and the carry (0 or `1 << HI_BIT`). 15 | #[inline(always)] 16 | pub(crate) const fn shr1(self) -> (Self, Self) { 17 | (Self(self.0 >> 1), Self(self.0 << Self::HI_BIT)) 18 | } 19 | } 20 | 21 | macro_rules! impl_shr { 22 | ($($shift:ty),+) => { 23 | $( 24 | impl Shr<$shift> for Limb { 25 | type Output = Limb; 26 | 27 | #[inline] 28 | fn shr(self, shift: $shift) -> Limb { 29 | Self::shr(self, u32::try_from(shift).expect("invalid shift")) 30 | } 31 | } 32 | 33 | impl Shr<$shift> for &Limb { 34 | type Output = Limb; 35 | 36 | #[inline] 37 | fn shr(self, shift: $shift) -> Limb { 38 | *self >> shift 39 | } 40 | } 41 | 42 | impl ShrAssign<$shift> for Limb { 43 | #[inline] 44 | fn shr_assign(&mut self, shift: $shift) { 45 | *self = *self >> shift; 46 | } 47 | } 48 | )+ 49 | }; 50 | } 51 | 52 | impl_shr!(i32, u32, usize); 53 | 54 | impl WrappingShr for Limb { 55 | #[inline] 56 | fn wrapping_shr(&self, shift: u32) -> Limb { 57 | Self(self.0.wrapping_shr(shift)) 58 | } 59 | } 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use crate::Limb; 64 | 65 | #[test] 66 | fn shr1() { 67 | assert_eq!(Limb(2) >> 1, Limb(1)); 68 | } 69 | 70 | #[test] 71 | fn shr2() { 72 | assert_eq!(Limb(16) >> 2, Limb(4)); 73 | } 74 | 75 | #[test] 76 | fn shr_assign1() { 77 | let mut l = Limb::ONE; 78 | l >>= 1; 79 | assert_eq!(l, Limb::ZERO); 80 | } 81 | 82 | #[test] 83 | fn shr_assign2() { 84 | let mut l = Limb(32); 85 | l >>= 2; 86 | assert_eq!(l, Limb(8)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/limb/sub.rs: -------------------------------------------------------------------------------- 1 | //! Limb subtraction 2 | 3 | use crate::{Checked, CheckedSub, Limb, Wrapping, WrappingSub, Zero, primitives::borrowing_sub}; 4 | use core::ops::{Sub, SubAssign}; 5 | use subtle::CtOption; 6 | 7 | impl Limb { 8 | /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow. 9 | #[deprecated(since = "0.7.0", note = "please use `borrowing_sub` instead")] 10 | pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) { 11 | self.borrowing_sub(rhs, borrow) 12 | } 13 | 14 | /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow. 15 | #[inline(always)] 16 | pub const fn borrowing_sub(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) { 17 | let (res, borrow) = borrowing_sub(self.0, rhs.0, borrow.0); 18 | (Limb(res), Limb(borrow)) 19 | } 20 | 21 | /// Perform saturating subtraction. 22 | #[inline] 23 | pub const fn saturating_sub(&self, rhs: Self) -> Self { 24 | Limb(self.0.saturating_sub(rhs.0)) 25 | } 26 | 27 | /// Perform wrapping subtraction, discarding underflow and wrapping around 28 | /// the boundary of the type. 29 | #[inline(always)] 30 | pub const fn wrapping_sub(&self, rhs: Self) -> Self { 31 | Limb(self.0.wrapping_sub(rhs.0)) 32 | } 33 | } 34 | 35 | impl CheckedSub for Limb { 36 | #[inline] 37 | fn checked_sub(&self, rhs: &Self) -> CtOption { 38 | let (result, underflow) = self.borrowing_sub(*rhs, Limb::ZERO); 39 | CtOption::new(result, underflow.is_zero()) 40 | } 41 | } 42 | 43 | impl Sub for Limb { 44 | type Output = Self; 45 | 46 | #[inline] 47 | fn sub(self, rhs: Self) -> Self { 48 | self.checked_sub(&rhs) 49 | .expect("attempted to subtract with underflow") 50 | } 51 | } 52 | 53 | impl Sub<&Self> for Limb { 54 | type Output = Self; 55 | 56 | #[inline] 57 | fn sub(self, rhs: &Self) -> Self { 58 | self - *rhs 59 | } 60 | } 61 | 62 | impl SubAssign for Wrapping { 63 | #[inline] 64 | fn sub_assign(&mut self, other: Self) { 65 | *self = *self - other; 66 | } 67 | } 68 | 69 | impl SubAssign<&Wrapping> for Wrapping { 70 | #[inline] 71 | fn sub_assign(&mut self, other: &Self) { 72 | *self = *self - other; 73 | } 74 | } 75 | 76 | impl SubAssign for Checked { 77 | #[inline] 78 | fn sub_assign(&mut self, other: Self) { 79 | *self = *self - other; 80 | } 81 | } 82 | 83 | impl SubAssign<&Checked> for Checked { 84 | #[inline] 85 | fn sub_assign(&mut self, other: &Self) { 86 | *self = *self - other; 87 | } 88 | } 89 | 90 | impl WrappingSub for Limb { 91 | #[inline] 92 | fn wrapping_sub(&self, v: &Self) -> Self { 93 | self.wrapping_sub(*v) 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests { 99 | use crate::{CheckedSub, Limb}; 100 | 101 | #[test] 102 | fn borrowing_sub_no_borrow() { 103 | let (res, borrow) = Limb::ONE.borrowing_sub(Limb::ONE, Limb::ZERO); 104 | assert_eq!(res, Limb::ZERO); 105 | assert_eq!(borrow, Limb::ZERO); 106 | } 107 | 108 | #[test] 109 | fn borrowing_sub_with_borrow() { 110 | let (res, borrow) = Limb::ZERO.borrowing_sub(Limb::ONE, Limb::ZERO); 111 | 112 | assert_eq!(res, Limb::MAX); 113 | assert_eq!(borrow, Limb::MAX); 114 | } 115 | 116 | #[test] 117 | fn wrapping_sub_no_borrow() { 118 | assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO); 119 | } 120 | 121 | #[test] 122 | fn wrapping_sub_with_borrow() { 123 | assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX); 124 | } 125 | 126 | #[test] 127 | fn checked_sub_ok() { 128 | let result = Limb::ONE.checked_sub(&Limb::ONE); 129 | assert_eq!(result.unwrap(), Limb::ZERO); 130 | } 131 | 132 | #[test] 133 | fn checked_sub_overflow() { 134 | let result = Limb::ZERO.checked_sub(&Limb::ONE); 135 | assert!(!bool::from(result.is_some())); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macro definitions which are a part of the public API. 2 | 3 | /// Calculate the number of limbs required to represent the given number of bits. 4 | // TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable 5 | #[macro_export] 6 | macro_rules! nlimbs { 7 | ($bits:expr) => { 8 | u32::div_ceil($bits, $crate::Limb::BITS) as usize 9 | }; 10 | } 11 | 12 | /// Calculate the number of 62-bit unsaturated limbs required to represent the given number of bits when performing 13 | /// Bernstein-Yang inversions. 14 | /// 15 | /// We need to ensure that: 16 | /// 17 | /// ```text 18 | /// $bits <= (safegcd_nlimbs($bits) * 62) - 64 19 | /// ``` 20 | // TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable 21 | macro_rules! safegcd_nlimbs { 22 | ($bits:expr) => { 23 | ($bits + 64).div_ceil(62) 24 | }; 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | #[cfg(target_pointer_width = "32")] 30 | #[test] 31 | fn nlimbs_for_bits_macro() { 32 | assert_eq!(nlimbs!(64), 2); 33 | assert_eq!(nlimbs!(128), 4); 34 | assert_eq!(nlimbs!(192), 6); 35 | assert_eq!(nlimbs!(256), 8); 36 | } 37 | 38 | #[cfg(target_pointer_width = "64")] 39 | #[test] 40 | fn nlimbs_for_bits_macro() { 41 | assert_eq!(nlimbs!(64), 1); 42 | assert_eq!(nlimbs!(128), 2); 43 | assert_eq!(nlimbs!(192), 3); 44 | assert_eq!(nlimbs!(256), 4); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/modular/add.rs: -------------------------------------------------------------------------------- 1 | use crate::{Odd, Uint}; 2 | 3 | pub(crate) const fn add_montgomery_form( 4 | a: &Uint, 5 | b: &Uint, 6 | modulus: &Odd>, 7 | ) -> Uint { 8 | a.add_mod(b, &modulus.0) 9 | } 10 | 11 | pub(crate) const fn double_montgomery_form( 12 | a: &Uint, 13 | modulus: &Odd>, 14 | ) -> Uint { 15 | a.double_mod(&modulus.0) 16 | } 17 | -------------------------------------------------------------------------------- /src/modular/boxed_monty_form/add.rs: -------------------------------------------------------------------------------- 1 | //! Additions between boxed Montgoemery form integers. 2 | 3 | use super::BoxedMontyForm; 4 | use core::ops::{Add, AddAssign}; 5 | 6 | impl BoxedMontyForm { 7 | /// Adds `rhs`. 8 | pub fn add(&self, rhs: &Self) -> Self { 9 | debug_assert_eq!(self.params, rhs.params); 10 | 11 | Self { 12 | montgomery_form: self 13 | .montgomery_form 14 | .add_mod(&rhs.montgomery_form, self.params.modulus()), 15 | params: self.params.clone(), 16 | } 17 | } 18 | 19 | /// Double `self`. 20 | pub fn double(&self) -> Self { 21 | Self { 22 | montgomery_form: self.montgomery_form.double_mod(self.params.modulus()), 23 | params: self.params.clone(), 24 | } 25 | } 26 | } 27 | 28 | impl Add<&BoxedMontyForm> for &BoxedMontyForm { 29 | type Output = BoxedMontyForm; 30 | fn add(self, rhs: &BoxedMontyForm) -> BoxedMontyForm { 31 | self.add(rhs) 32 | } 33 | } 34 | 35 | impl Add for &BoxedMontyForm { 36 | type Output = BoxedMontyForm; 37 | #[allow(clippy::op_ref)] 38 | fn add(self, rhs: BoxedMontyForm) -> BoxedMontyForm { 39 | self + &rhs 40 | } 41 | } 42 | 43 | impl Add<&BoxedMontyForm> for BoxedMontyForm { 44 | type Output = BoxedMontyForm; 45 | #[allow(clippy::op_ref)] 46 | fn add(self, rhs: &BoxedMontyForm) -> BoxedMontyForm { 47 | &self + rhs 48 | } 49 | } 50 | 51 | impl Add for BoxedMontyForm { 52 | type Output = BoxedMontyForm; 53 | fn add(self, rhs: BoxedMontyForm) -> BoxedMontyForm { 54 | &self + &rhs 55 | } 56 | } 57 | 58 | impl AddAssign<&BoxedMontyForm> for BoxedMontyForm { 59 | fn add_assign(&mut self, rhs: &BoxedMontyForm) { 60 | debug_assert_eq!(self.params, rhs.params); 61 | self.montgomery_form 62 | .add_mod_assign(&rhs.montgomery_form, self.params.modulus()); 63 | } 64 | } 65 | 66 | impl AddAssign for BoxedMontyForm { 67 | fn add_assign(&mut self, rhs: BoxedMontyForm) { 68 | *self += &rhs; 69 | } 70 | } 71 | 72 | #[cfg(test)] 73 | mod tests { 74 | use crate::{ 75 | BoxedUint, 76 | modular::{BoxedMontyForm, BoxedMontyParams}, 77 | }; 78 | use hex_literal::hex; 79 | 80 | #[test] 81 | fn add_overflow() { 82 | let modulus = BoxedUint::from_be_slice( 83 | &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), 84 | 256, 85 | ) 86 | .unwrap(); 87 | let params = BoxedMontyParams::new(modulus.to_odd().unwrap()); 88 | 89 | let x = BoxedUint::from_be_slice( 90 | &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), 91 | 256, 92 | ) 93 | .unwrap(); 94 | let mut x_mod = BoxedMontyForm::new(x, params.clone()); 95 | 96 | let y = BoxedUint::from_be_slice( 97 | &hex!("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"), 98 | 256, 99 | ) 100 | .unwrap(); 101 | let y_mod = BoxedMontyForm::new(y, params.clone()); 102 | 103 | x_mod += &y_mod; 104 | 105 | let expected = BoxedUint::from_be_slice( 106 | &hex!("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"), 107 | 256, 108 | ) 109 | .unwrap(); 110 | 111 | assert_eq!(expected, x_mod.retrieve()); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/modular/boxed_monty_form/invert.rs: -------------------------------------------------------------------------------- 1 | //! Multiplicative inverses of boxed integers in Montgomery form. 2 | 3 | use super::{BoxedMontyForm, BoxedMontyParams}; 4 | use crate::{ 5 | Invert, Inverter, PrecomputeInverter, PrecomputeInverterWithAdjuster, 6 | modular::BoxedSafeGcdInverter, 7 | }; 8 | use core::fmt; 9 | use subtle::CtOption; 10 | 11 | impl BoxedMontyForm { 12 | /// Computes `self^-1` representing the multiplicative inverse of `self`, 13 | /// i.e. `self * self^-1 = 1`. 14 | pub fn invert(&self) -> CtOption { 15 | self.params.precompute_inverter().invert(self) 16 | } 17 | 18 | /// Computes `self^-1` representing the multiplicative inverse of `self`, 19 | /// i.e. `self * self^-1 = 1`. 20 | /// 21 | /// This version is variable-time with respect to the value of `self`, but constant-time with 22 | /// respect to `self`'s `params`. 23 | pub fn invert_vartime(&self) -> CtOption { 24 | self.params.precompute_inverter().invert_vartime(self) 25 | } 26 | } 27 | 28 | impl Invert for BoxedMontyForm { 29 | type Output = CtOption; 30 | 31 | fn invert(&self) -> Self::Output { 32 | self.invert() 33 | } 34 | 35 | fn invert_vartime(&self) -> Self::Output { 36 | self.invert_vartime() 37 | } 38 | } 39 | 40 | impl PrecomputeInverter for BoxedMontyParams { 41 | type Inverter = BoxedMontyFormInverter; 42 | type Output = BoxedMontyForm; 43 | 44 | fn precompute_inverter(&self) -> BoxedMontyFormInverter { 45 | BoxedMontyFormInverter { 46 | inverter: self.modulus().precompute_inverter_with_adjuster(self.r2()), 47 | params: self.clone(), 48 | } 49 | } 50 | } 51 | 52 | /// Bernstein-Yang inverter which inverts [`DynResidue`] types. 53 | pub struct BoxedMontyFormInverter { 54 | /// Precomputed Bernstein-Yang inverter. 55 | inverter: BoxedSafeGcdInverter, 56 | 57 | /// Residue parameters. 58 | params: BoxedMontyParams, 59 | } 60 | 61 | impl Inverter for BoxedMontyFormInverter { 62 | type Output = BoxedMontyForm; 63 | 64 | fn invert(&self, value: &BoxedMontyForm) -> CtOption { 65 | debug_assert_eq!(self.params, value.params); 66 | 67 | let montgomery_form = self.inverter.invert(&value.montgomery_form); 68 | let is_some = montgomery_form.is_some(); 69 | let montgomery_form2 = value.montgomery_form.clone(); 70 | let ret = BoxedMontyForm { 71 | montgomery_form: Option::from(montgomery_form).unwrap_or(montgomery_form2), 72 | params: value.params.clone(), 73 | }; 74 | 75 | CtOption::new(ret, is_some) 76 | } 77 | 78 | fn invert_vartime(&self, value: &BoxedMontyForm) -> CtOption { 79 | debug_assert_eq!(self.params, value.params); 80 | 81 | let montgomery_form = self.inverter.invert_vartime(&value.montgomery_form); 82 | let is_some = montgomery_form.is_some(); 83 | let montgomery_form2 = value.montgomery_form.clone(); 84 | let ret = BoxedMontyForm { 85 | montgomery_form: Option::from(montgomery_form).unwrap_or(montgomery_form2), 86 | params: value.params.clone(), 87 | }; 88 | 89 | CtOption::new(ret, is_some) 90 | } 91 | } 92 | 93 | impl fmt::Debug for BoxedMontyFormInverter { 94 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 95 | f.debug_struct("BoxedMontyFormInverter") 96 | .field("modulus", &self.inverter.modulus) 97 | .finish() 98 | } 99 | } 100 | 101 | #[cfg(test)] 102 | mod tests { 103 | use crate::{ 104 | BoxedUint, 105 | modular::{BoxedMontyForm, BoxedMontyParams}, 106 | }; 107 | use hex_literal::hex; 108 | 109 | fn monty_params() -> BoxedMontyParams { 110 | BoxedMontyParams::new( 111 | BoxedUint::from_be_slice( 112 | &hex!("15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409"), 113 | 256, 114 | ) 115 | .unwrap() 116 | .to_odd() 117 | .unwrap(), 118 | ) 119 | } 120 | 121 | #[test] 122 | fn test_self_inverse() { 123 | let params = monty_params(); 124 | let x = BoxedUint::from_be_slice( 125 | &hex!("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"), 126 | 256, 127 | ) 128 | .unwrap(); 129 | let x_mod = BoxedMontyForm::new(x, params); 130 | 131 | let inv = x_mod.invert().unwrap(); 132 | let res = x_mod * inv; 133 | 134 | assert!(bool::from(res.retrieve().is_one())); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/modular/boxed_monty_form/lincomb.rs: -------------------------------------------------------------------------------- 1 | //! Linear combinations of integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::BoxedMontyForm; 4 | use crate::modular::lincomb::lincomb_boxed_monty_form; 5 | 6 | impl BoxedMontyForm { 7 | /// Calculate the sum of products of pairs `(a, b)` in `products`. 8 | /// 9 | /// This method is variable time only with the value of the modulus. 10 | /// For a modulus with leading zeros, this method is more efficient than a naive sum of products. 11 | /// 12 | /// This method will panic if `products` is empty. All terms must be associated 13 | /// with equivalent `MontyParams`. 14 | pub fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self { 15 | assert!(!products.is_empty(), "empty products"); 16 | let params = &products[0].0.params; 17 | Self { 18 | montgomery_form: lincomb_boxed_monty_form( 19 | products, 20 | params.modulus(), 21 | params.mod_neg_inv(), 22 | params.mod_leading_zeros(), 23 | ), 24 | params: products[0].0.params.clone(), 25 | } 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | 32 | #[cfg(feature = "rand")] 33 | #[test] 34 | fn lincomb_expected() { 35 | use crate::modular::{BoxedMontyForm, BoxedMontyParams}; 36 | use crate::{BoxedUint, Odd, RandomMod}; 37 | use rand_core::SeedableRng; 38 | 39 | const SIZE: u32 = 511; 40 | 41 | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); 42 | for n in 0..100 { 43 | let modulus = Odd::::random(&mut rng, SIZE); 44 | let params = BoxedMontyParams::new(modulus.clone()); 45 | let a = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 46 | let b = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 47 | let c = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 48 | let d = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 49 | let e = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 50 | let f = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); 51 | 52 | let std = a 53 | .mul_mod(&b, &modulus) 54 | .add_mod(&c.mul_mod(&d, &modulus), &modulus) 55 | .add_mod(&e.mul_mod(&f, &modulus), &modulus); 56 | 57 | let lincomb = BoxedMontyForm::lincomb_vartime(&[ 58 | ( 59 | &BoxedMontyForm::new(a, params.clone()), 60 | &BoxedMontyForm::new(b, params.clone()), 61 | ), 62 | ( 63 | &BoxedMontyForm::new(c, params.clone()), 64 | &BoxedMontyForm::new(d, params.clone()), 65 | ), 66 | ( 67 | &BoxedMontyForm::new(e, params.clone()), 68 | &BoxedMontyForm::new(f, params.clone()), 69 | ), 70 | ]); 71 | 72 | assert_eq!(std, lincomb.retrieve(), "n={n}"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/modular/boxed_monty_form/neg.rs: -------------------------------------------------------------------------------- 1 | //! Negations of boxed integers in Montgomery form. 2 | 3 | use super::BoxedMontyForm; 4 | use core::ops::Neg; 5 | 6 | impl BoxedMontyForm { 7 | /// Negates the number. 8 | pub fn neg(&self) -> Self { 9 | Self { 10 | montgomery_form: self.montgomery_form.neg_mod(self.params.modulus()), 11 | params: self.params.clone(), 12 | } 13 | } 14 | } 15 | 16 | impl Neg for BoxedMontyForm { 17 | type Output = Self; 18 | fn neg(self) -> Self { 19 | BoxedMontyForm::neg(&self) 20 | } 21 | } 22 | 23 | impl Neg for &BoxedMontyForm { 24 | type Output = BoxedMontyForm; 25 | fn neg(self) -> BoxedMontyForm { 26 | BoxedMontyForm::neg(self) 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use crate::{ 33 | BoxedUint, 34 | modular::{BoxedMontyForm, BoxedMontyParams}, 35 | }; 36 | use hex_literal::hex; 37 | 38 | #[test] 39 | fn neg_expected() { 40 | let modulus = BoxedUint::from_be_slice( 41 | &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), 42 | 256, 43 | ) 44 | .expect("error creating modulus"); 45 | let params = BoxedMontyParams::new(modulus.to_odd().unwrap()); 46 | 47 | let x = BoxedUint::from_be_slice( 48 | &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), 49 | 256, 50 | ) 51 | .expect("error creating boxeduint"); 52 | let x_mod = BoxedMontyForm::new(x, params.clone()); 53 | 54 | assert!(bool::from((x_mod.neg() + x_mod).is_zero())); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/modular/boxed_monty_form/sub.rs: -------------------------------------------------------------------------------- 1 | //! Subtractions between boxed integers in Montgomery form. 2 | 3 | use super::BoxedMontyForm; 4 | use crate::Limb; 5 | use core::ops::{Sub, SubAssign}; 6 | 7 | impl BoxedMontyForm { 8 | /// Subtracts `rhs`. 9 | pub fn sub(&self, rhs: &Self) -> Self { 10 | debug_assert_eq!(self.params, rhs.params); 11 | 12 | Self { 13 | montgomery_form: self 14 | .montgomery_form 15 | .sub_mod(&rhs.montgomery_form, self.params.modulus()), 16 | params: self.params.clone(), 17 | } 18 | } 19 | } 20 | 21 | impl Sub<&BoxedMontyForm> for &BoxedMontyForm { 22 | type Output = BoxedMontyForm; 23 | fn sub(self, rhs: &BoxedMontyForm) -> BoxedMontyForm { 24 | debug_assert_eq!(self.params, rhs.params); 25 | self.sub(rhs) 26 | } 27 | } 28 | 29 | impl Sub for &BoxedMontyForm { 30 | type Output = BoxedMontyForm; 31 | #[allow(clippy::op_ref)] 32 | fn sub(self, rhs: BoxedMontyForm) -> BoxedMontyForm { 33 | self - &rhs 34 | } 35 | } 36 | 37 | impl Sub<&BoxedMontyForm> for BoxedMontyForm { 38 | type Output = BoxedMontyForm; 39 | #[allow(clippy::op_ref)] 40 | fn sub(self, rhs: &BoxedMontyForm) -> BoxedMontyForm { 41 | &self - rhs 42 | } 43 | } 44 | 45 | impl Sub for BoxedMontyForm { 46 | type Output = BoxedMontyForm; 47 | fn sub(self, rhs: BoxedMontyForm) -> BoxedMontyForm { 48 | &self - &rhs 49 | } 50 | } 51 | 52 | impl SubAssign<&BoxedMontyForm> for BoxedMontyForm { 53 | fn sub_assign(&mut self, rhs: &BoxedMontyForm) { 54 | debug_assert_eq!(self.params, rhs.params); 55 | self.montgomery_form.sub_assign_mod_with_carry( 56 | Limb::ZERO, 57 | &rhs.montgomery_form, 58 | self.params.modulus(), 59 | ); 60 | } 61 | } 62 | 63 | impl SubAssign for BoxedMontyForm { 64 | fn sub_assign(&mut self, rhs: BoxedMontyForm) { 65 | *self -= &rhs; 66 | } 67 | } 68 | 69 | #[cfg(test)] 70 | mod tests { 71 | use crate::{ 72 | BoxedUint, 73 | modular::{BoxedMontyForm, BoxedMontyParams}, 74 | }; 75 | use hex_literal::hex; 76 | 77 | #[test] 78 | fn sub_overflow() { 79 | let modulus = BoxedUint::from_be_slice( 80 | &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), 81 | 256, 82 | ) 83 | .unwrap(); 84 | let params = BoxedMontyParams::new(modulus.to_odd().unwrap()); 85 | 86 | let x = BoxedUint::from_be_slice( 87 | &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), 88 | 256, 89 | ) 90 | .unwrap(); 91 | let mut x_mod = BoxedMontyForm::new(x, params.clone()); 92 | 93 | let y = BoxedUint::from_be_slice( 94 | &hex!("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"), 95 | 256, 96 | ) 97 | .unwrap(); 98 | let y_mod = BoxedMontyForm::new(y, params); 99 | 100 | x_mod -= &y_mod; 101 | 102 | let expected = BoxedUint::from_be_slice( 103 | &hex!("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"), 104 | 256, 105 | ) 106 | .unwrap(); 107 | 108 | assert_eq!(expected, x_mod.retrieve()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/add.rs: -------------------------------------------------------------------------------- 1 | //! Additions between integers in Montgomery form with a constant modulus. 2 | 3 | use super::{ConstMontyForm, ConstMontyParams}; 4 | use crate::modular::add::{add_montgomery_form, double_montgomery_form}; 5 | use core::ops::{Add, AddAssign}; 6 | 7 | impl, const LIMBS: usize> ConstMontyForm { 8 | /// Adds `rhs`. 9 | pub const fn add(&self, rhs: &ConstMontyForm) -> Self { 10 | Self { 11 | montgomery_form: add_montgomery_form( 12 | &self.montgomery_form, 13 | &rhs.montgomery_form, 14 | &MOD::MODULUS, 15 | ), 16 | phantom: core::marker::PhantomData, 17 | } 18 | } 19 | 20 | /// Double `self`. 21 | pub const fn double(&self) -> Self { 22 | Self { 23 | montgomery_form: double_montgomery_form(&self.montgomery_form, &MOD::MODULUS), 24 | phantom: core::marker::PhantomData, 25 | } 26 | } 27 | } 28 | 29 | impl, const LIMBS: usize> Add<&ConstMontyForm> 30 | for &ConstMontyForm 31 | { 32 | type Output = ConstMontyForm; 33 | fn add(self, rhs: &ConstMontyForm) -> ConstMontyForm { 34 | self.add(rhs) 35 | } 36 | } 37 | 38 | impl, const LIMBS: usize> Add> 39 | for &ConstMontyForm 40 | { 41 | type Output = ConstMontyForm; 42 | #[allow(clippy::op_ref)] 43 | fn add(self, rhs: ConstMontyForm) -> ConstMontyForm { 44 | self + &rhs 45 | } 46 | } 47 | 48 | impl, const LIMBS: usize> Add<&ConstMontyForm> 49 | for ConstMontyForm 50 | { 51 | type Output = ConstMontyForm; 52 | #[allow(clippy::op_ref)] 53 | fn add(self, rhs: &ConstMontyForm) -> ConstMontyForm { 54 | &self + rhs 55 | } 56 | } 57 | 58 | impl, const LIMBS: usize> Add> 59 | for ConstMontyForm 60 | { 61 | type Output = ConstMontyForm; 62 | fn add(self, rhs: ConstMontyForm) -> ConstMontyForm { 63 | &self + &rhs 64 | } 65 | } 66 | 67 | impl, const LIMBS: usize> AddAssign<&Self> 68 | for ConstMontyForm 69 | { 70 | fn add_assign(&mut self, rhs: &Self) { 71 | *self = *self + rhs; 72 | } 73 | } 74 | 75 | impl, const LIMBS: usize> AddAssign 76 | for ConstMontyForm 77 | { 78 | fn add_assign(&mut self, rhs: Self) { 79 | *self += &rhs; 80 | } 81 | } 82 | 83 | #[cfg(test)] 84 | mod tests { 85 | use crate::{ 86 | U256, const_monty_form, impl_modulus, modular::const_monty_form::ConstMontyParams, 87 | }; 88 | 89 | impl_modulus!( 90 | Modulus, 91 | U256, 92 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" 93 | ); 94 | 95 | #[test] 96 | fn add_overflow() { 97 | let x = 98 | U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); 99 | let mut x_mod = const_monty_form!(x, Modulus); 100 | 101 | let y = 102 | U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); 103 | let y_mod = const_monty_form!(y, Modulus); 104 | 105 | x_mod += &y_mod; 106 | 107 | let expected = 108 | U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); 109 | 110 | assert_eq!(expected, x_mod.retrieve()); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/lincomb.rs: -------------------------------------------------------------------------------- 1 | //! Linear combinations of integers n Montgomery form with a constant modulus. 2 | 3 | use core::marker::PhantomData; 4 | 5 | use super::{ConstMontyForm, ConstMontyParams}; 6 | use crate::modular::lincomb::lincomb_const_monty_form; 7 | 8 | impl, const LIMBS: usize> ConstMontyForm { 9 | /// Calculate the sum of products of pairs `(a, b)` in `products`. 10 | /// 11 | /// This method is variable time only with the value of the modulus. 12 | /// For a modulus with leading zeros, this method is more efficient than a naive sum of products. 13 | pub const fn lincomb_vartime(products: &[(Self, Self)]) -> Self { 14 | Self { 15 | montgomery_form: lincomb_const_monty_form(products, &MOD::MODULUS, MOD::MOD_NEG_INV), 16 | phantom: PhantomData, 17 | } 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | 24 | #[cfg(feature = "rand")] 25 | #[test] 26 | fn lincomb_expected() { 27 | use super::{ConstMontyForm, ConstMontyParams}; 28 | use crate::{RandomMod, U256, impl_modulus}; 29 | use rand_core::SeedableRng; 30 | impl_modulus!( 31 | P, 32 | U256, 33 | "7fffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" 34 | ); 35 | let modulus = P::MODULUS.as_nz_ref(); 36 | 37 | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); 38 | for n in 0..1000 { 39 | let a = U256::random_mod(&mut rng, modulus); 40 | let b = U256::random_mod(&mut rng, modulus); 41 | let c = U256::random_mod(&mut rng, modulus); 42 | let d = U256::random_mod(&mut rng, modulus); 43 | let e = U256::random_mod(&mut rng, modulus); 44 | let f = U256::random_mod(&mut rng, modulus); 45 | 46 | assert_eq!( 47 | a.mul_mod(&b, modulus) 48 | .add_mod(&c.mul_mod(&d, modulus), modulus) 49 | .add_mod(&e.mul_mod(&f, modulus), modulus), 50 | ConstMontyForm::::lincomb_vartime(&[ 51 | (ConstMontyForm::new(&a), ConstMontyForm::new(&b)), 52 | (ConstMontyForm::new(&c), ConstMontyForm::new(&d)), 53 | (ConstMontyForm::new(&e), ConstMontyForm::new(&f)), 54 | ]) 55 | .retrieve(), 56 | "n={n}" 57 | ) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macro support. 2 | 3 | /// Implements a modulus with the given name, type, and value, in that specific order. Please 4 | /// `use crypto_bigint::traits::Encoding` to make this work. 5 | /// 6 | /// For example, 7 | /// `impl_modulus!(MyModulus, U256, "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");` 8 | /// implements a 256-bit modulus named `MyModulus`. 9 | /// 10 | /// The modulus _must_ be odd, or this will panic. 11 | // TODO: Use `adt_const_params` once stabilized to make a `ConstMontyForm` generic around a modulus rather 12 | // than having to implement a ZST + trait 13 | #[macro_export] 14 | macro_rules! impl_modulus { 15 | ($name:ident, $uint_type:ty, $value:expr) => { 16 | $crate::impl_modulus!( 17 | $name, 18 | $uint_type, 19 | $value, 20 | "Modulus which impls `ConstMontyParams`" 21 | ); 22 | }; 23 | ($name:ident, $uint_type:ty, $value:expr, $doc:expr) => { 24 | #[doc = $doc] 25 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 26 | pub struct $name; 27 | impl $crate::modular::ConstMontyParams<{ <$uint_type>::LIMBS }> 28 | for $name 29 | where 30 | $uint_type: $crate::ConcatMixed>, 31 | { 32 | const LIMBS: usize = <$uint_type>::LIMBS; 33 | const MODULUS: $crate::Odd<$uint_type> = $crate::Odd::<$uint_type>::from_be_hex($value); 34 | 35 | // `R mod MODULUS` where `R = 2^BITS`. 36 | // Represents 1 in Montgomery form. 37 | const ONE: $uint_type = $crate::Uint::MAX 38 | .rem_vartime(Self::MODULUS.as_nz_ref()) 39 | .wrapping_add(&$crate::Uint::ONE); 40 | 41 | // `R^2 mod MODULUS`, used to convert integers to Montgomery form. 42 | const R2: $uint_type = 43 | $crate::Uint::rem_wide_vartime(Self::ONE.square_wide(), Self::MODULUS.as_nz_ref()); 44 | 45 | const MOD_NEG_INV: $crate::Limb = $crate::Limb( 46 | $crate::Word::MIN.wrapping_sub( 47 | Self::MODULUS 48 | .as_ref() 49 | .invert_mod2k_vartime($crate::Word::BITS) 50 | .expect("modulus ensured odd") 51 | .as_limbs()[0] 52 | .0, 53 | ), 54 | ); 55 | 56 | // Leading zeros in the modulus, used to choose optimized algorithms. 57 | const MOD_LEADING_ZEROS: u32 = { 58 | let z = Self::MODULUS.as_ref().leading_zeros(); 59 | if z >= $crate::Word::BITS { 60 | $crate::Word::BITS - 1 61 | } else { 62 | z 63 | } 64 | }; 65 | 66 | const R3: $uint_type = $crate::modular::montgomery_reduction( 67 | &Self::R2.square_wide(), 68 | &Self::MODULUS, 69 | Self::MOD_NEG_INV, 70 | ); 71 | } 72 | }; 73 | } 74 | 75 | /// Creates a `ConstMontyForm` with the given value for a specific modulus. 76 | /// 77 | /// For example, `const_monty_form!(U256::from(105u64), MyModulus);` 78 | /// creates a `ConstMontyForm` for 105 mod `MyModulus`. 79 | /// 80 | /// The modulus _must_ be odd, or this will panic. 81 | #[macro_export] 82 | macro_rules! const_monty_form { 83 | ($variable:ident, $modulus:ident) => { 84 | $crate::modular::ConstMontyForm::<$modulus, { $modulus::LIMBS }>::new(&$variable) 85 | }; 86 | } 87 | 88 | #[cfg(test)] 89 | mod tests { 90 | use crate::modular::ConstMontyParams; 91 | use crate::{Limb, U64}; 92 | 93 | #[test] 94 | fn new_params_with_valid_modulus() { 95 | impl_modulus!(Mod, U64, "0000000000000003"); 96 | 97 | assert_eq!(Mod::MOD_LEADING_ZEROS, core::cmp::min(Limb::BITS - 1, 62)); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/mul.rs: -------------------------------------------------------------------------------- 1 | //! Multiplications between integers in Montgomery form with a constant modulus. 2 | 3 | use core::{ 4 | marker::PhantomData, 5 | ops::{Mul, MulAssign}, 6 | }; 7 | 8 | use crate::{ 9 | modular::mul::{mul_montgomery_form, square_montgomery_form}, 10 | traits::Square, 11 | }; 12 | 13 | use super::{ConstMontyForm, ConstMontyParams}; 14 | 15 | impl, const LIMBS: usize> ConstMontyForm { 16 | /// Multiplies by `rhs`. 17 | pub const fn mul(&self, rhs: &Self) -> Self { 18 | Self { 19 | montgomery_form: mul_montgomery_form( 20 | &self.montgomery_form, 21 | &rhs.montgomery_form, 22 | &MOD::MODULUS, 23 | MOD::MOD_NEG_INV, 24 | ), 25 | phantom: PhantomData, 26 | } 27 | } 28 | 29 | /// Computes the (reduced) square. 30 | pub const fn square(&self) -> Self { 31 | Self { 32 | montgomery_form: square_montgomery_form( 33 | &self.montgomery_form, 34 | &MOD::MODULUS, 35 | MOD::MOD_NEG_INV, 36 | ), 37 | phantom: PhantomData, 38 | } 39 | } 40 | } 41 | 42 | impl, const LIMBS: usize> Mul<&ConstMontyForm> 43 | for &ConstMontyForm 44 | { 45 | type Output = ConstMontyForm; 46 | fn mul(self, rhs: &ConstMontyForm) -> ConstMontyForm { 47 | self.mul(rhs) 48 | } 49 | } 50 | 51 | impl, const LIMBS: usize> Mul> 52 | for &ConstMontyForm 53 | { 54 | type Output = ConstMontyForm; 55 | #[allow(clippy::op_ref)] 56 | fn mul(self, rhs: ConstMontyForm) -> ConstMontyForm { 57 | self * &rhs 58 | } 59 | } 60 | 61 | impl, const LIMBS: usize> Mul<&ConstMontyForm> 62 | for ConstMontyForm 63 | { 64 | type Output = ConstMontyForm; 65 | #[allow(clippy::op_ref)] 66 | fn mul(self, rhs: &ConstMontyForm) -> ConstMontyForm { 67 | &self * rhs 68 | } 69 | } 70 | 71 | impl, const LIMBS: usize> Mul> 72 | for ConstMontyForm 73 | { 74 | type Output = ConstMontyForm; 75 | fn mul(self, rhs: ConstMontyForm) -> ConstMontyForm { 76 | &self * &rhs 77 | } 78 | } 79 | 80 | impl, const LIMBS: usize> MulAssign<&Self> 81 | for ConstMontyForm 82 | { 83 | fn mul_assign(&mut self, rhs: &ConstMontyForm) { 84 | *self = *self * rhs; 85 | } 86 | } 87 | 88 | impl, const LIMBS: usize> MulAssign 89 | for ConstMontyForm 90 | { 91 | fn mul_assign(&mut self, rhs: Self) { 92 | *self *= &rhs; 93 | } 94 | } 95 | 96 | impl, const LIMBS: usize> Square for ConstMontyForm { 97 | fn square(&self) -> Self { 98 | ConstMontyForm::square(self) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/neg.rs: -------------------------------------------------------------------------------- 1 | //! Negations of integers in Montgomery form with a constant modulus. 2 | 3 | use super::{ConstMontyForm, ConstMontyParams}; 4 | use core::ops::Neg; 5 | 6 | impl, const LIMBS: usize> ConstMontyForm { 7 | /// Negates the number. 8 | pub const fn neg(&self) -> Self { 9 | Self { 10 | montgomery_form: self.montgomery_form.neg_mod(MOD::MODULUS.as_ref()), 11 | phantom: self.phantom, 12 | } 13 | } 14 | } 15 | 16 | impl, const LIMBS: usize> Neg for ConstMontyForm { 17 | type Output = Self; 18 | fn neg(self) -> Self { 19 | ConstMontyForm::neg(&self) 20 | } 21 | } 22 | 23 | impl, const LIMBS: usize> Neg for &ConstMontyForm { 24 | type Output = ConstMontyForm; 25 | fn neg(self) -> ConstMontyForm { 26 | ConstMontyForm::neg(self) 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use crate::{ 33 | U256, const_monty_form, impl_modulus, modular::const_monty_form::ConstMontyParams, 34 | }; 35 | 36 | impl_modulus!( 37 | Modulus, 38 | U256, 39 | "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409" 40 | ); 41 | 42 | #[test] 43 | fn test_negate() { 44 | let x = 45 | U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); 46 | let x_mod = const_monty_form!(x, Modulus); 47 | 48 | let res = -x_mod; 49 | let expected = 50 | U256::from_be_hex("089B67BB2C124F084701AD76E8750D321385E35044C74CE457301A2A9BE061B1"); 51 | 52 | assert_eq!(res.retrieve(), expected); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/modular/const_monty_form/sub.rs: -------------------------------------------------------------------------------- 1 | //! Subtractions between integers in Montgomery form with a constant modulus. 2 | 3 | use super::{ConstMontyForm, ConstMontyParams}; 4 | use crate::modular::sub::sub_montgomery_form; 5 | use core::ops::{Sub, SubAssign}; 6 | 7 | impl, const LIMBS: usize> ConstMontyForm { 8 | /// Subtracts `rhs`. 9 | pub const fn sub(&self, rhs: &Self) -> Self { 10 | Self { 11 | montgomery_form: sub_montgomery_form( 12 | &self.montgomery_form, 13 | &rhs.montgomery_form, 14 | &MOD::MODULUS, 15 | ), 16 | phantom: core::marker::PhantomData, 17 | } 18 | } 19 | } 20 | 21 | impl, const LIMBS: usize> Sub<&ConstMontyForm> 22 | for &ConstMontyForm 23 | { 24 | type Output = ConstMontyForm; 25 | fn sub(self, rhs: &ConstMontyForm) -> ConstMontyForm { 26 | self.sub(rhs) 27 | } 28 | } 29 | 30 | impl, const LIMBS: usize> Sub> 31 | for &ConstMontyForm 32 | { 33 | type Output = ConstMontyForm; 34 | #[allow(clippy::op_ref)] 35 | fn sub(self, rhs: ConstMontyForm) -> ConstMontyForm { 36 | self - &rhs 37 | } 38 | } 39 | 40 | impl, const LIMBS: usize> Sub<&ConstMontyForm> 41 | for ConstMontyForm 42 | { 43 | type Output = ConstMontyForm; 44 | #[allow(clippy::op_ref)] 45 | fn sub(self, rhs: &ConstMontyForm) -> ConstMontyForm { 46 | &self - rhs 47 | } 48 | } 49 | 50 | impl, const LIMBS: usize> Sub> 51 | for ConstMontyForm 52 | { 53 | type Output = ConstMontyForm; 54 | fn sub(self, rhs: ConstMontyForm) -> ConstMontyForm { 55 | &self - &rhs 56 | } 57 | } 58 | 59 | impl, const LIMBS: usize> SubAssign<&Self> 60 | for ConstMontyForm 61 | { 62 | fn sub_assign(&mut self, rhs: &Self) { 63 | *self = *self - rhs; 64 | } 65 | } 66 | 67 | impl, const LIMBS: usize> SubAssign 68 | for ConstMontyForm 69 | { 70 | fn sub_assign(&mut self, rhs: Self) { 71 | *self -= &rhs; 72 | } 73 | } 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | use crate::{ 78 | U256, const_monty_form, impl_modulus, modular::const_monty_form::ConstMontyParams, 79 | }; 80 | 81 | impl_modulus!( 82 | Modulus, 83 | U256, 84 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" 85 | ); 86 | 87 | #[test] 88 | fn sub_overflow() { 89 | let x = 90 | U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); 91 | let mut x_mod = const_monty_form!(x, Modulus); 92 | 93 | let y = 94 | U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); 95 | let y_mod = const_monty_form!(y, Modulus); 96 | 97 | x_mod -= &y_mod; 98 | 99 | let expected = 100 | U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); 101 | 102 | assert_eq!(expected, x_mod.retrieve()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/modular/div_by_2.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alloc")] 2 | use crate::{BoxedUint, Integer}; 3 | use crate::{Limb, Odd, Uint}; 4 | 5 | pub(crate) const fn div_by_2( 6 | a: &Uint, 7 | modulus: &Odd>, 8 | ) -> Uint { 9 | // We are looking for such `b` that `b + b = a mod modulus`. 10 | // Two possibilities: 11 | // - if `a` is even, we can just divide by 2; 12 | // - if `a` is odd, we divide `(a + modulus)` by 2. 13 | 14 | // Note that this also works if `a` is a Montgomery representation modulo `modulus` 15 | // of some integer `x`. 16 | // If `b + b = a mod modulus` it means that `y + y = x mod modulus` where `y` is the integer 17 | // whose Montgomery representation is `b`. 18 | 19 | let is_odd = a.is_odd(); 20 | let (if_odd, carry) = a.carrying_add(&modulus.0, Limb::ZERO); 21 | let carry = Limb::select(Limb::ZERO, carry, is_odd); 22 | Uint::::select(a, &if_odd, is_odd) 23 | .shr1() 24 | .set_bit(Uint::::BITS - 1, carry.is_nonzero()) 25 | } 26 | 27 | #[cfg(feature = "alloc")] 28 | pub(crate) fn div_by_2_boxed(a: &BoxedUint, modulus: &Odd) -> BoxedUint { 29 | let mut result = a.clone(); 30 | div_by_2_boxed_assign(&mut result, modulus); 31 | result 32 | } 33 | 34 | #[cfg(feature = "alloc")] 35 | pub(crate) fn div_by_2_boxed_assign(a: &mut BoxedUint, modulus: &Odd) { 36 | debug_assert_eq!(a.bits_precision(), modulus.bits_precision()); 37 | 38 | let is_odd = a.is_odd(); 39 | let carry = a.conditional_carrying_add_assign(modulus, is_odd); 40 | a.shr1_assign(); 41 | a.set_bit(a.bits_precision() - 1, carry); 42 | } 43 | -------------------------------------------------------------------------------- /src/modular/monty_form/add.rs: -------------------------------------------------------------------------------- 1 | //! Additions between integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use crate::modular::add::{add_montgomery_form, double_montgomery_form}; 5 | use core::ops::{Add, AddAssign}; 6 | 7 | impl MontyForm { 8 | /// Adds `rhs`. 9 | pub const fn add(&self, rhs: &Self) -> Self { 10 | Self { 11 | montgomery_form: add_montgomery_form( 12 | &self.montgomery_form, 13 | &rhs.montgomery_form, 14 | &self.params.modulus, 15 | ), 16 | params: self.params, 17 | } 18 | } 19 | 20 | /// Double `self`. 21 | pub const fn double(&self) -> Self { 22 | Self { 23 | montgomery_form: double_montgomery_form(&self.montgomery_form, &self.params.modulus), 24 | params: self.params, 25 | } 26 | } 27 | } 28 | 29 | impl Add<&MontyForm> for &MontyForm { 30 | type Output = MontyForm; 31 | fn add(self, rhs: &MontyForm) -> MontyForm { 32 | debug_assert_eq!(self.params, rhs.params); 33 | self.add(rhs) 34 | } 35 | } 36 | 37 | impl Add> for &MontyForm { 38 | type Output = MontyForm; 39 | #[allow(clippy::op_ref)] 40 | fn add(self, rhs: MontyForm) -> MontyForm { 41 | self + &rhs 42 | } 43 | } 44 | 45 | impl Add<&MontyForm> for MontyForm { 46 | type Output = MontyForm; 47 | #[allow(clippy::op_ref)] 48 | fn add(self, rhs: &MontyForm) -> MontyForm { 49 | &self + rhs 50 | } 51 | } 52 | 53 | impl Add> for MontyForm { 54 | type Output = MontyForm; 55 | fn add(self, rhs: MontyForm) -> MontyForm { 56 | &self + &rhs 57 | } 58 | } 59 | 60 | impl AddAssign<&MontyForm> for MontyForm { 61 | fn add_assign(&mut self, rhs: &MontyForm) { 62 | *self = *self + rhs; 63 | } 64 | } 65 | 66 | impl AddAssign> for MontyForm { 67 | fn add_assign(&mut self, rhs: MontyForm) { 68 | *self += &rhs; 69 | } 70 | } 71 | 72 | #[cfg(test)] 73 | mod tests { 74 | use crate::{ 75 | Odd, U256, 76 | modular::{MontyForm, MontyParams}, 77 | }; 78 | 79 | #[test] 80 | fn add_overflow() { 81 | let params = MontyParams::new_vartime(Odd::::from_be_hex( 82 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 83 | )); 84 | 85 | let x = 86 | U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); 87 | let mut x_mod = MontyForm::new(&x, params); 88 | 89 | let y = 90 | U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); 91 | let y_mod = MontyForm::new(&y, params); 92 | 93 | x_mod += &y_mod; 94 | 95 | let expected = 96 | U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); 97 | 98 | assert_eq!(expected, x_mod.retrieve()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/modular/monty_form/lincomb.rs: -------------------------------------------------------------------------------- 1 | //! Linear combinations of integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use crate::modular::lincomb::lincomb_monty_form; 5 | 6 | impl MontyForm { 7 | /// Calculate the sum of products of pairs `(a, b)` in `products`. 8 | /// 9 | /// This method is variable time only with the value of the modulus. 10 | /// For a modulus with leading zeros, this method is more efficient than a naive sum of products. 11 | /// 12 | /// This method will panic if `products` is empty. All terms must be associated 13 | /// with equivalent `MontyParams`. 14 | pub const fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self { 15 | assert!(!products.is_empty(), "empty products"); 16 | let params = &products[0].0.params; 17 | Self { 18 | montgomery_form: lincomb_monty_form( 19 | products, 20 | ¶ms.modulus, 21 | params.mod_neg_inv, 22 | params.mod_leading_zeros, 23 | ), 24 | params: products[0].0.params, 25 | } 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | #[cfg(feature = "rand")] 32 | #[test] 33 | fn lincomb_expected() { 34 | use crate::U256; 35 | use crate::{ 36 | Odd, Random, RandomMod, 37 | modular::{MontyForm, MontyParams}, 38 | }; 39 | use rand_core::SeedableRng; 40 | 41 | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); 42 | for n in 0..1500 { 43 | let modulus = Odd::::random(&mut rng); 44 | let params = MontyParams::new_vartime(modulus); 45 | let m = modulus.as_nz_ref(); 46 | let a = U256::random_mod(&mut rng, m); 47 | let b = U256::random_mod(&mut rng, m); 48 | let c = U256::random_mod(&mut rng, m); 49 | let d = U256::random_mod(&mut rng, m); 50 | 51 | assert_eq!( 52 | a.mul_mod(&b, m).add_mod(&c.mul_mod(&d, m), m), 53 | MontyForm::lincomb_vartime(&[ 54 | (&MontyForm::new(&a, params), &MontyForm::new(&b, params)), 55 | (&MontyForm::new(&c, params), &MontyForm::new(&d, params)), 56 | ]) 57 | .retrieve(), 58 | "n={n}, a={a}, b={b}, c={c}, d={d}" 59 | ) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/modular/monty_form/mul.rs: -------------------------------------------------------------------------------- 1 | //! Multiplications between integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use crate::{ 5 | MontyMultiplier, Square, SquareAssign, 6 | modular::{ 7 | MontyParams, 8 | mul::{mul_montgomery_form, square_montgomery_form}, 9 | }, 10 | }; 11 | use core::ops::{Mul, MulAssign}; 12 | 13 | impl MontyForm { 14 | /// Multiplies by `rhs`. 15 | pub const fn mul(&self, rhs: &Self) -> Self { 16 | Self { 17 | montgomery_form: mul_montgomery_form( 18 | &self.montgomery_form, 19 | &rhs.montgomery_form, 20 | &self.params.modulus, 21 | self.params.mod_neg_inv, 22 | ), 23 | params: self.params, 24 | } 25 | } 26 | 27 | /// Computes the (reduced) square. 28 | pub const fn square(&self) -> Self { 29 | Self { 30 | montgomery_form: square_montgomery_form( 31 | &self.montgomery_form, 32 | &self.params.modulus, 33 | self.params.mod_neg_inv, 34 | ), 35 | params: self.params, 36 | } 37 | } 38 | } 39 | 40 | impl Mul<&MontyForm> for &MontyForm { 41 | type Output = MontyForm; 42 | fn mul(self, rhs: &MontyForm) -> MontyForm { 43 | debug_assert_eq!(self.params, rhs.params); 44 | self.mul(rhs) 45 | } 46 | } 47 | 48 | impl Mul> for &MontyForm { 49 | type Output = MontyForm; 50 | #[allow(clippy::op_ref)] 51 | fn mul(self, rhs: MontyForm) -> MontyForm { 52 | self * &rhs 53 | } 54 | } 55 | 56 | impl Mul<&MontyForm> for MontyForm { 57 | type Output = MontyForm; 58 | #[allow(clippy::op_ref)] 59 | fn mul(self, rhs: &MontyForm) -> MontyForm { 60 | &self * rhs 61 | } 62 | } 63 | 64 | impl Mul> for MontyForm { 65 | type Output = MontyForm; 66 | fn mul(self, rhs: MontyForm) -> MontyForm { 67 | &self * &rhs 68 | } 69 | } 70 | 71 | impl MulAssign<&MontyForm> for MontyForm { 72 | fn mul_assign(&mut self, rhs: &MontyForm) { 73 | *self = *self * rhs; 74 | } 75 | } 76 | 77 | impl MulAssign> for MontyForm { 78 | fn mul_assign(&mut self, rhs: MontyForm) { 79 | *self *= &rhs; 80 | } 81 | } 82 | 83 | impl Square for MontyForm { 84 | fn square(&self) -> Self { 85 | MontyForm::square(self) 86 | } 87 | } 88 | 89 | impl SquareAssign for MontyForm { 90 | fn square_assign(&mut self) { 91 | *self = self.square() 92 | } 93 | } 94 | 95 | #[derive(Debug, Clone, Copy)] 96 | pub struct DynMontyMultiplier<'a, const LIMBS: usize>(&'a MontyParams); 97 | 98 | impl<'a, const LIMBS: usize> From<&'a MontyParams> for DynMontyMultiplier<'a, LIMBS> { 99 | fn from(source: &'a MontyParams) -> Self { 100 | Self(source) 101 | } 102 | } 103 | 104 | impl<'a, const LIMBS: usize> MontyMultiplier<'a> for DynMontyMultiplier<'a, LIMBS> { 105 | type Monty = MontyForm; 106 | 107 | /// Performs a Montgomery multiplication, assigning a fully reduced result to `lhs`. 108 | fn mul_assign(&mut self, lhs: &mut Self::Monty, rhs: &Self::Monty) { 109 | let product = mul_montgomery_form( 110 | &lhs.montgomery_form, 111 | &rhs.montgomery_form, 112 | &self.0.modulus, 113 | self.0.mod_neg_inv, 114 | ); 115 | lhs.montgomery_form = product; 116 | } 117 | 118 | /// Performs a Montgomery squaring, assigning a fully reduced result to `lhs`. 119 | fn square_assign(&mut self, lhs: &mut Self::Monty) { 120 | let product = 121 | square_montgomery_form(&lhs.montgomery_form, &self.0.modulus, self.0.mod_neg_inv); 122 | lhs.montgomery_form = product; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/modular/monty_form/neg.rs: -------------------------------------------------------------------------------- 1 | //! Negations of integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use core::ops::Neg; 5 | 6 | impl MontyForm { 7 | /// Negates the number. 8 | pub const fn neg(&self) -> Self { 9 | Self { 10 | montgomery_form: self.montgomery_form.neg_mod(self.params.modulus.as_ref()), 11 | params: self.params, 12 | } 13 | } 14 | } 15 | 16 | impl Neg for MontyForm { 17 | type Output = Self; 18 | fn neg(self) -> Self { 19 | MontyForm::neg(&self) 20 | } 21 | } 22 | 23 | impl Neg for &MontyForm { 24 | type Output = MontyForm; 25 | fn neg(self) -> MontyForm { 26 | MontyForm::neg(self) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/modular/monty_form/pow.rs: -------------------------------------------------------------------------------- 1 | //! Exponentiation of integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use crate::{ 5 | MultiExponentiateBoundedExp, PowBoundedExp, Uint, 6 | modular::pow::{multi_exponentiate_montgomery_form_array, pow_montgomery_form}, 7 | }; 8 | 9 | #[cfg(feature = "alloc")] 10 | use {crate::modular::pow::multi_exponentiate_montgomery_form_slice, alloc::vec::Vec}; 11 | 12 | impl MontyForm { 13 | /// Raises to the `exponent` power. 14 | pub const fn pow( 15 | &self, 16 | exponent: &Uint, 17 | ) -> MontyForm { 18 | self.pow_bounded_exp(exponent, Uint::::BITS) 19 | } 20 | 21 | /// Raises to the `exponent` power, 22 | /// with `exponent_bits` representing the number of (least significant) bits 23 | /// to take into account for the exponent. 24 | /// 25 | /// NOTE: `exponent_bits` may be leaked in the time pattern. 26 | pub const fn pow_bounded_exp( 27 | &self, 28 | exponent: &Uint, 29 | exponent_bits: u32, 30 | ) -> Self { 31 | Self { 32 | montgomery_form: pow_montgomery_form( 33 | &self.montgomery_form, 34 | exponent, 35 | exponent_bits, 36 | &self.params.modulus, 37 | &self.params.one, 38 | self.params.mod_neg_inv, 39 | ), 40 | params: self.params, 41 | } 42 | } 43 | } 44 | 45 | impl PowBoundedExp> 46 | for MontyForm 47 | { 48 | fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: u32) -> Self { 49 | self.pow_bounded_exp(exponent, exponent_bits) 50 | } 51 | } 52 | 53 | impl 54 | MultiExponentiateBoundedExp, [(Self, Uint); N]> 55 | for MontyForm 56 | { 57 | fn multi_exponentiate_bounded_exp( 58 | bases_and_exponents: &[(Self, Uint); N], 59 | exponent_bits: u32, 60 | ) -> Self { 61 | assert!(N != 0, "bases_and_exponents must not be empty"); 62 | let params = bases_and_exponents[0].0.params; 63 | 64 | let mut bases_and_exponents_montgomery_form = 65 | [(Uint::::ZERO, Uint::::ZERO); N]; 66 | 67 | let mut i = 0; 68 | while i < N { 69 | let (base, exponent) = bases_and_exponents[i]; 70 | bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent); 71 | i += 1; 72 | } 73 | 74 | Self { 75 | montgomery_form: multi_exponentiate_montgomery_form_array( 76 | &bases_and_exponents_montgomery_form, 77 | exponent_bits, 78 | ¶ms.modulus, 79 | ¶ms.one, 80 | params.mod_neg_inv, 81 | ), 82 | params, 83 | } 84 | } 85 | } 86 | 87 | #[cfg(feature = "alloc")] 88 | impl 89 | MultiExponentiateBoundedExp, [(Self, Uint)]> for MontyForm 90 | { 91 | fn multi_exponentiate_bounded_exp( 92 | bases_and_exponents: &[(Self, Uint)], 93 | exponent_bits: u32, 94 | ) -> Self { 95 | assert!( 96 | !bases_and_exponents.is_empty(), 97 | "bases_and_exponents must not be empty" 98 | ); 99 | let params = bases_and_exponents[0].0.params; 100 | 101 | let bases_and_exponents: Vec<(Uint, Uint)> = bases_and_exponents 102 | .iter() 103 | .map(|(base, exp)| (base.montgomery_form, *exp)) 104 | .collect(); 105 | Self { 106 | montgomery_form: multi_exponentiate_montgomery_form_slice( 107 | &bases_and_exponents, 108 | exponent_bits, 109 | ¶ms.modulus, 110 | ¶ms.one, 111 | params.mod_neg_inv, 112 | ), 113 | params, 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/modular/monty_form/sub.rs: -------------------------------------------------------------------------------- 1 | //! Subtractions between integers in Montgomery form with a modulus set at runtime. 2 | 3 | use super::MontyForm; 4 | use crate::modular::sub::sub_montgomery_form; 5 | use core::ops::{Sub, SubAssign}; 6 | 7 | impl MontyForm { 8 | /// Subtracts `rhs`. 9 | pub const fn sub(&self, rhs: &Self) -> Self { 10 | Self { 11 | montgomery_form: sub_montgomery_form( 12 | &self.montgomery_form, 13 | &rhs.montgomery_form, 14 | &self.params.modulus, 15 | ), 16 | params: self.params, 17 | } 18 | } 19 | } 20 | 21 | impl Sub<&MontyForm> for &MontyForm { 22 | type Output = MontyForm; 23 | fn sub(self, rhs: &MontyForm) -> MontyForm { 24 | debug_assert_eq!(self.params, rhs.params); 25 | self.sub(rhs) 26 | } 27 | } 28 | 29 | impl Sub> for &MontyForm { 30 | type Output = MontyForm; 31 | #[allow(clippy::op_ref)] 32 | fn sub(self, rhs: MontyForm) -> MontyForm { 33 | self - &rhs 34 | } 35 | } 36 | 37 | impl Sub<&MontyForm> for MontyForm { 38 | type Output = MontyForm; 39 | #[allow(clippy::op_ref)] 40 | fn sub(self, rhs: &MontyForm) -> MontyForm { 41 | &self - rhs 42 | } 43 | } 44 | 45 | impl Sub> for MontyForm { 46 | type Output = MontyForm; 47 | fn sub(self, rhs: MontyForm) -> MontyForm { 48 | &self - &rhs 49 | } 50 | } 51 | 52 | impl SubAssign<&MontyForm> for MontyForm { 53 | fn sub_assign(&mut self, rhs: &MontyForm) { 54 | *self = *self - rhs; 55 | } 56 | } 57 | 58 | impl SubAssign> for MontyForm { 59 | fn sub_assign(&mut self, rhs: MontyForm) { 60 | *self -= &rhs; 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use crate::{ 67 | Odd, U256, 68 | modular::{MontyForm, MontyParams}, 69 | }; 70 | 71 | #[test] 72 | fn sub_overflow() { 73 | let params = MontyParams::new_vartime(Odd::::from_be_hex( 74 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 75 | )); 76 | 77 | let x = 78 | U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); 79 | let mut x_mod = MontyForm::new(&x, params); 80 | 81 | let y = 82 | U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); 83 | let y_mod = MontyForm::new(&y, params); 84 | 85 | x_mod -= &y_mod; 86 | 87 | let expected = 88 | U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); 89 | 90 | assert_eq!(expected, x_mod.retrieve()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/modular/mul.rs: -------------------------------------------------------------------------------- 1 | use super::reduction::montgomery_reduction; 2 | use crate::{Limb, Odd, Uint}; 3 | 4 | pub(crate) const fn mul_montgomery_form( 5 | a: &Uint, 6 | b: &Uint, 7 | modulus: &Odd>, 8 | mod_neg_inv: Limb, 9 | ) -> Uint { 10 | let product = a.widening_mul(b); 11 | montgomery_reduction::(&product, modulus, mod_neg_inv) 12 | } 13 | 14 | pub(crate) const fn square_montgomery_form( 15 | a: &Uint, 16 | modulus: &Odd>, 17 | mod_neg_inv: Limb, 18 | ) -> Uint { 19 | let product = a.square_wide(); 20 | montgomery_reduction::(&product, modulus, mod_neg_inv) 21 | } 22 | -------------------------------------------------------------------------------- /src/modular/reduction.rs: -------------------------------------------------------------------------------- 1 | //! Modular reduction implementation. 2 | 3 | use crate::{Limb, Odd, Uint}; 4 | 5 | /// Algorithm 14.32 in Handbook of Applied Cryptography 6 | #[inline(always)] 7 | const fn montgomery_reduction_inner( 8 | upper: &mut [Limb], 9 | lower: &mut [Limb], 10 | modulus: &[Limb], 11 | mod_neg_inv: Limb, 12 | ) -> Limb { 13 | let nlimbs = modulus.len(); 14 | debug_assert!(nlimbs == upper.len()); 15 | debug_assert!(nlimbs == lower.len()); 16 | 17 | let mut meta_carry = Limb::ZERO; 18 | let mut new_sum; 19 | 20 | let mut i = 0; 21 | while i < nlimbs { 22 | let u = lower[i].wrapping_mul(mod_neg_inv); 23 | 24 | let (_, mut carry) = u.carrying_mul_add(modulus[0], lower[i], Limb::ZERO); 25 | let mut new_limb; 26 | 27 | let mut j = 1; 28 | while j < (nlimbs - i) { 29 | (new_limb, carry) = u.carrying_mul_add(modulus[j], lower[i + j], carry); 30 | lower[i + j] = new_limb; 31 | j += 1; 32 | } 33 | while j < nlimbs { 34 | (new_limb, carry) = u.carrying_mul_add(modulus[j], upper[i + j - nlimbs], carry); 35 | upper[i + j - nlimbs] = new_limb; 36 | j += 1; 37 | } 38 | 39 | (new_sum, meta_carry) = upper[i].carrying_add(carry, meta_carry); 40 | upper[i] = new_sum; 41 | 42 | i += 1; 43 | } 44 | 45 | meta_carry 46 | } 47 | 48 | /// Algorithm 14.32 in Handbook of Applied Cryptography 49 | pub const fn montgomery_reduction( 50 | lower_upper: &(Uint, Uint), 51 | modulus: &Odd>, 52 | mod_neg_inv: Limb, 53 | ) -> Uint { 54 | let (mut lower, mut upper) = *lower_upper; 55 | let meta_carry = montgomery_reduction_inner( 56 | &mut upper.limbs, 57 | &mut lower.limbs, 58 | &modulus.0.limbs, 59 | mod_neg_inv, 60 | ); 61 | 62 | // Division is simply taking the upper half of the limbs 63 | // Final reduction (at this point, the value is at most 2 * modulus, 64 | // so `meta_carry` is either 0 or 1) 65 | upper.sub_mod_with_carry(meta_carry, &modulus.0, &modulus.0) 66 | } 67 | -------------------------------------------------------------------------------- /src/modular/safegcd/macros.rs: -------------------------------------------------------------------------------- 1 | //! Bernstein-Yang macros. 2 | 3 | /// Write an impl of a limb conversion function. 4 | /// 5 | /// Workaround for making this function generic around limb types while still allowing it to be 6 | /// `const fn`. 7 | macro_rules! impl_limb_convert { 8 | ($input_type:ty, $input_bits:expr, $input:expr, $output_type:ty, $output_bits:expr, $output:expr) => {{ 9 | // This function is defined because the method "min" of the usize type is not constant 10 | const fn min(a: usize, b: usize) -> usize { 11 | if a > b { 12 | b 13 | } else { 14 | a 15 | } 16 | } 17 | 18 | let total = min($input.len() * $input_bits, $output.len() * $output_bits); 19 | let mut bits = 0; 20 | 21 | while bits < total { 22 | let (i, o) = (bits % $input_bits, bits % $output_bits); 23 | $output[bits / $output_bits] |= ($input[bits / $input_bits] >> i) as $output_type << o; 24 | bits += min($input_bits - i, $output_bits - o); 25 | } 26 | 27 | let mask = (<$output_type>::MAX as $output_type) >> (<$output_type>::BITS as usize - $output_bits); 28 | let mut filled = total / $output_bits + if total % $output_bits > 0 { 1 } else { 0 }; 29 | 30 | while filled > 0 { 31 | filled -= 1; 32 | $output[filled] &= mask; 33 | } 34 | }}; 35 | } 36 | -------------------------------------------------------------------------------- /src/modular/sub.rs: -------------------------------------------------------------------------------- 1 | use crate::{Odd, Uint}; 2 | 3 | pub(crate) const fn sub_montgomery_form( 4 | a: &Uint, 5 | b: &Uint, 6 | modulus: &Odd>, 7 | ) -> Uint { 8 | a.sub_mod(b, &modulus.0) 9 | } 10 | -------------------------------------------------------------------------------- /src/primitives.rs: -------------------------------------------------------------------------------- 1 | use crate::{WideWord, Word}; 2 | 3 | /// Adds wide numbers represented by pairs of (least significant word, most significant word) 4 | /// and returns the result in the same format `(lo, hi)`. 5 | #[inline(always)] 6 | pub(crate) const fn addhilo(x_lo: Word, x_hi: Word, y_lo: Word, y_hi: Word) -> (Word, Word) { 7 | let res = (((x_hi as WideWord) << Word::BITS) | (x_lo as WideWord)) 8 | + (((y_hi as WideWord) << Word::BITS) | (y_lo as WideWord)); 9 | (res as Word, (res >> Word::BITS) as Word) 10 | } 11 | 12 | /// Computes `lhs + rhs + carry`, returning the result along with the new carry (0, 1, or 2). 13 | #[inline(always)] 14 | pub(crate) const fn carrying_add(lhs: Word, rhs: Word, carry: Word) -> (Word, Word) { 15 | // We could use `Word::overflowing_add()` here analogous to `overflowing_add()`, 16 | // but this version seems to produce a slightly better assembly. 17 | let a = lhs as WideWord; 18 | let b = rhs as WideWord; 19 | let carry = carry as WideWord; 20 | let ret = a + b + carry; 21 | (ret as Word, (ret >> Word::BITS) as Word) 22 | } 23 | 24 | /// Computes `lhs + rhs`, returning the result along with the carry (0 or 1). 25 | #[inline(always)] 26 | pub(crate) const fn overflowing_add(lhs: Word, rhs: Word) -> (Word, Word) { 27 | let (res, carry) = lhs.overflowing_add(rhs); 28 | (res, carry as Word) 29 | } 30 | 31 | /// Computes `lhs - (rhs + borrow)`, returning the result along with the new borrow. 32 | #[inline(always)] 33 | pub(crate) const fn borrowing_sub(lhs: Word, rhs: Word, borrow: Word) -> (Word, Word) { 34 | let a = lhs as WideWord; 35 | let b = rhs as WideWord; 36 | let borrow = (borrow >> (Word::BITS - 1)) as WideWord; 37 | let ret = a.wrapping_sub(b + borrow); 38 | (ret as Word, (ret >> Word::BITS) as Word) 39 | } 40 | 41 | /// Computes `lhs * rhs`, returning the low and the high words of the result. 42 | #[inline(always)] 43 | pub(crate) const fn widening_mul(lhs: Word, rhs: Word) -> (Word, Word) { 44 | let a = lhs as WideWord; 45 | let b = rhs as WideWord; 46 | let ret = a * b; 47 | (ret as Word, (ret >> Word::BITS) as Word) 48 | } 49 | 50 | /// Computes `(lhs * rhs) + addend + carry`, returning the result along with the new carry. 51 | #[inline(always)] 52 | pub(crate) const fn carrying_mul_add( 53 | lhs: Word, 54 | rhs: Word, 55 | addend: Word, 56 | carry: Word, 57 | ) -> (Word, Word) { 58 | let lhs = lhs as WideWord; 59 | let rhs = rhs as WideWord; 60 | let addend = addend as WideWord; 61 | let ret = (lhs * rhs) + addend; 62 | let (lo, hi) = (ret as Word, (ret >> Word::BITS) as Word); 63 | 64 | let (lo, c) = lo.overflowing_add(carry); 65 | 66 | // Even if all the arguments are `Word::MAX` we can't overflow `hi`. 67 | let hi = hi.wrapping_add(c as Word); 68 | 69 | (lo, hi) 70 | } 71 | -------------------------------------------------------------------------------- /src/traits/sealed.rs: -------------------------------------------------------------------------------- 1 | //! Sealed traits. 2 | 3 | use super::PrecomputeInverter; 4 | 5 | /// Obtain a precomputed inverter which applies the given adjustment factor, i.e. for Montgomery form. 6 | pub trait PrecomputeInverterWithAdjuster: PrecomputeInverter { 7 | /// Obtain a precomputed inverter for `&self` as the modulus, supplying a custom adjusting parameter (e.g. R^2 for 8 | /// when computing inversions in Montgomery form). 9 | fn precompute_inverter_with_adjuster(&self, adjuster: &Adjuster) -> Self::Inverter; 10 | } 11 | -------------------------------------------------------------------------------- /src/uint/bit_and.rs: -------------------------------------------------------------------------------- 1 | //! [`Uint`] bitwise AND operations. 2 | 3 | use super::Uint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::{BitAnd, BitAndAssign}; 6 | use subtle::{Choice, CtOption}; 7 | 8 | impl Uint { 9 | /// Computes bitwise `a & b`. 10 | #[inline(always)] 11 | pub const fn bitand(&self, rhs: &Self) -> Self { 12 | let mut limbs = [Limb::ZERO; LIMBS]; 13 | let mut i = 0; 14 | 15 | while i < LIMBS { 16 | limbs[i] = self.limbs[i].bitand(rhs.limbs[i]); 17 | i += 1; 18 | } 19 | 20 | Self { limbs } 21 | } 22 | 23 | /// Perform bitwise `AND` between `self` and the given [`Limb`], performing the `AND` operation 24 | /// on every limb of `self`. 25 | pub const fn bitand_limb(&self, rhs: Limb) -> Self { 26 | let mut limbs = [Limb::ZERO; LIMBS]; 27 | let mut i = 0; 28 | 29 | while i < LIMBS { 30 | limbs[i] = self.limbs[i].bitand(rhs); 31 | i += 1; 32 | } 33 | 34 | Self { limbs } 35 | } 36 | 37 | /// Perform wrapping bitwise `AND`. 38 | /// 39 | /// There's no way wrapping could ever happen. 40 | /// This function exists so that all operations are accounted for in the wrapping operations 41 | pub const fn wrapping_and(&self, rhs: &Self) -> Self { 42 | self.bitand(rhs) 43 | } 44 | 45 | /// Perform checked bitwise `AND`, returning a [`CtOption`] which `is_some` always 46 | pub fn checked_and(&self, rhs: &Self) -> CtOption { 47 | let result = self.bitand(rhs); 48 | CtOption::new(result, Choice::from(1)) 49 | } 50 | } 51 | 52 | impl BitAnd for Uint { 53 | type Output = Self; 54 | 55 | fn bitand(self, rhs: Self) -> Uint { 56 | self.bitand(&rhs) 57 | } 58 | } 59 | 60 | impl BitAnd<&Uint> for Uint { 61 | type Output = Uint; 62 | 63 | #[allow(clippy::needless_borrow)] 64 | fn bitand(self, rhs: &Uint) -> Uint { 65 | (&self).bitand(rhs) 66 | } 67 | } 68 | 69 | impl BitAnd> for &Uint { 70 | type Output = Uint; 71 | 72 | fn bitand(self, rhs: Uint) -> Uint { 73 | self.bitand(&rhs) 74 | } 75 | } 76 | 77 | impl BitAnd<&Uint> for &Uint { 78 | type Output = Uint; 79 | 80 | fn bitand(self, rhs: &Uint) -> Uint { 81 | self.bitand(rhs) 82 | } 83 | } 84 | 85 | impl BitAndAssign for Uint { 86 | #[allow(clippy::assign_op_pattern)] 87 | fn bitand_assign(&mut self, other: Self) { 88 | *self = *self & other; 89 | } 90 | } 91 | 92 | impl BitAndAssign<&Uint> for Uint { 93 | #[allow(clippy::assign_op_pattern)] 94 | fn bitand_assign(&mut self, other: &Self) { 95 | *self = *self & other; 96 | } 97 | } 98 | 99 | impl BitAnd for Wrapping> { 100 | type Output = Self; 101 | 102 | fn bitand(self, rhs: Self) -> Wrapping> { 103 | Wrapping(self.0.bitand(&rhs.0)) 104 | } 105 | } 106 | 107 | impl BitAnd<&Wrapping>> for Wrapping> { 108 | type Output = Wrapping>; 109 | 110 | fn bitand(self, rhs: &Wrapping>) -> Wrapping> { 111 | Wrapping(self.0.bitand(&rhs.0)) 112 | } 113 | } 114 | 115 | impl BitAnd>> for &Wrapping> { 116 | type Output = Wrapping>; 117 | 118 | fn bitand(self, rhs: Wrapping>) -> Wrapping> { 119 | Wrapping(self.0.bitand(&rhs.0)) 120 | } 121 | } 122 | 123 | impl BitAnd<&Wrapping>> for &Wrapping> { 124 | type Output = Wrapping>; 125 | 126 | fn bitand(self, rhs: &Wrapping>) -> Wrapping> { 127 | Wrapping(self.0.bitand(&rhs.0)) 128 | } 129 | } 130 | 131 | impl BitAndAssign for Wrapping> { 132 | #[allow(clippy::assign_op_pattern)] 133 | fn bitand_assign(&mut self, other: Self) { 134 | *self = *self & other; 135 | } 136 | } 137 | 138 | impl BitAndAssign<&Wrapping>> for Wrapping> { 139 | #[allow(clippy::assign_op_pattern)] 140 | fn bitand_assign(&mut self, other: &Self) { 141 | *self = *self & other; 142 | } 143 | } 144 | 145 | #[cfg(test)] 146 | mod tests { 147 | use crate::U128; 148 | 149 | #[test] 150 | fn checked_and_ok() { 151 | let result = U128::ZERO.checked_and(&U128::ONE); 152 | assert_eq!(result.unwrap(), U128::ZERO); 153 | } 154 | 155 | #[test] 156 | fn overlapping_and_ok() { 157 | let result = U128::MAX.wrapping_and(&U128::ONE); 158 | assert_eq!(result, U128::ONE); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/uint/bit_not.rs: -------------------------------------------------------------------------------- 1 | //! [`Uint`] bitwise NOT operations. 2 | 3 | use super::Uint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::Not; 6 | 7 | impl Uint { 8 | /// Computes bitwise `!a`. 9 | #[inline(always)] 10 | pub const fn not(&self) -> Self { 11 | let mut limbs = [Limb::ZERO; LIMBS]; 12 | let mut i = 0; 13 | 14 | while i < LIMBS { 15 | limbs[i] = self.limbs[i].not(); 16 | i += 1; 17 | } 18 | 19 | Self { limbs } 20 | } 21 | } 22 | 23 | impl Not for Uint { 24 | type Output = Self; 25 | 26 | fn not(self) -> Self { 27 | Self::not(&self) 28 | } 29 | } 30 | 31 | impl Not for Wrapping> { 32 | type Output = Self; 33 | 34 | fn not(self) -> ::Output { 35 | Wrapping(self.0.not()) 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use crate::U128; 42 | 43 | #[test] 44 | fn bitnot_ok() { 45 | assert_eq!(U128::ZERO.not(), U128::MAX); 46 | assert_eq!(U128::MAX.not(), U128::ZERO); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/uint/bit_or.rs: -------------------------------------------------------------------------------- 1 | //! [`Uint`] bitwise OR operations. 2 | 3 | use super::Uint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::{BitOr, BitOrAssign}; 6 | use subtle::{Choice, CtOption}; 7 | 8 | impl Uint { 9 | /// Computes bitwise `a & b`. 10 | #[inline(always)] 11 | pub const fn bitor(&self, rhs: &Self) -> Self { 12 | let mut limbs = [Limb::ZERO; LIMBS]; 13 | let mut i = 0; 14 | 15 | while i < LIMBS { 16 | limbs[i] = self.limbs[i].bitor(rhs.limbs[i]); 17 | i += 1; 18 | } 19 | 20 | Self { limbs } 21 | } 22 | 23 | /// Perform wrapping bitwise `OR`. 24 | /// 25 | /// There's no way wrapping could ever happen. 26 | /// This function exists so that all operations are accounted for in the wrapping operations 27 | pub const fn wrapping_or(&self, rhs: &Self) -> Self { 28 | self.bitor(rhs) 29 | } 30 | 31 | /// Perform checked bitwise `OR`, returning a [`CtOption`] which `is_some` always 32 | pub fn checked_or(&self, rhs: &Self) -> CtOption { 33 | let result = self.bitor(rhs); 34 | CtOption::new(result, Choice::from(1)) 35 | } 36 | } 37 | 38 | impl BitOr for Uint { 39 | type Output = Self; 40 | 41 | fn bitor(self, rhs: Self) -> Uint { 42 | self.bitor(&rhs) 43 | } 44 | } 45 | 46 | impl BitOr<&Uint> for Uint { 47 | type Output = Uint; 48 | 49 | #[allow(clippy::needless_borrow)] 50 | fn bitor(self, rhs: &Uint) -> Uint { 51 | (&self).bitor(rhs) 52 | } 53 | } 54 | 55 | impl BitOr> for &Uint { 56 | type Output = Uint; 57 | 58 | fn bitor(self, rhs: Uint) -> Uint { 59 | self.bitor(&rhs) 60 | } 61 | } 62 | 63 | impl BitOr<&Uint> for &Uint { 64 | type Output = Uint; 65 | 66 | fn bitor(self, rhs: &Uint) -> Uint { 67 | self.bitor(rhs) 68 | } 69 | } 70 | 71 | impl BitOrAssign for Uint { 72 | fn bitor_assign(&mut self, other: Self) { 73 | *self = *self | other; 74 | } 75 | } 76 | 77 | impl BitOrAssign<&Uint> for Uint { 78 | fn bitor_assign(&mut self, other: &Self) { 79 | *self = *self | other; 80 | } 81 | } 82 | 83 | impl BitOr for Wrapping> { 84 | type Output = Self; 85 | 86 | fn bitor(self, rhs: Self) -> Wrapping> { 87 | Wrapping(self.0.bitor(&rhs.0)) 88 | } 89 | } 90 | 91 | impl BitOr<&Wrapping>> for Wrapping> { 92 | type Output = Wrapping>; 93 | 94 | fn bitor(self, rhs: &Wrapping>) -> Wrapping> { 95 | Wrapping(self.0.bitor(&rhs.0)) 96 | } 97 | } 98 | 99 | impl BitOr>> for &Wrapping> { 100 | type Output = Wrapping>; 101 | 102 | fn bitor(self, rhs: Wrapping>) -> Wrapping> { 103 | Wrapping(self.0.bitor(&rhs.0)) 104 | } 105 | } 106 | 107 | impl BitOr<&Wrapping>> for &Wrapping> { 108 | type Output = Wrapping>; 109 | 110 | fn bitor(self, rhs: &Wrapping>) -> Wrapping> { 111 | Wrapping(self.0.bitor(&rhs.0)) 112 | } 113 | } 114 | 115 | impl BitOrAssign for Wrapping> { 116 | fn bitor_assign(&mut self, other: Self) { 117 | *self = *self | other; 118 | } 119 | } 120 | 121 | impl BitOrAssign<&Wrapping>> for Wrapping> { 122 | fn bitor_assign(&mut self, other: &Self) { 123 | *self = *self | other; 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod tests { 129 | use crate::U128; 130 | 131 | #[test] 132 | fn checked_or_ok() { 133 | let result = U128::ZERO.checked_or(&U128::ONE); 134 | assert_eq!(result.unwrap(), U128::ONE); 135 | } 136 | 137 | #[test] 138 | fn overlapping_or_ok() { 139 | let result = U128::MAX.wrapping_or(&U128::ONE); 140 | assert_eq!(result, U128::MAX); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/uint/bit_xor.rs: -------------------------------------------------------------------------------- 1 | //! [`Uint`] bitwise XOR operations. 2 | 3 | use super::Uint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::{BitXor, BitXorAssign}; 6 | use subtle::{Choice, CtOption}; 7 | 8 | impl Uint { 9 | /// Computes bitwise `a ^ b`. 10 | #[inline(always)] 11 | pub const fn bitxor(&self, rhs: &Self) -> Self { 12 | let mut limbs = [Limb::ZERO; LIMBS]; 13 | let mut i = 0; 14 | 15 | while i < LIMBS { 16 | limbs[i] = self.limbs[i].bitxor(rhs.limbs[i]); 17 | i += 1; 18 | } 19 | 20 | Self { limbs } 21 | } 22 | 23 | /// Perform wrapping bitwise `XOR`. 24 | /// 25 | /// There's no way wrapping could ever happen. 26 | /// This function exists so that all operations are accounted for in the wrapping operations 27 | pub const fn wrapping_xor(&self, rhs: &Self) -> Self { 28 | self.bitxor(rhs) 29 | } 30 | 31 | /// Perform checked bitwise `XOR`, returning a [`CtOption`] which `is_some` always 32 | pub fn checked_xor(&self, rhs: &Self) -> CtOption { 33 | let result = self.bitxor(rhs); 34 | CtOption::new(result, Choice::from(1)) 35 | } 36 | } 37 | 38 | impl BitXor for Uint { 39 | type Output = Self; 40 | 41 | fn bitxor(self, rhs: Self) -> Uint { 42 | self.bitxor(&rhs) 43 | } 44 | } 45 | 46 | impl BitXor<&Uint> for Uint { 47 | type Output = Uint; 48 | 49 | #[allow(clippy::needless_borrow)] 50 | fn bitxor(self, rhs: &Uint) -> Uint { 51 | (&self).bitxor(rhs) 52 | } 53 | } 54 | 55 | impl BitXor> for &Uint { 56 | type Output = Uint; 57 | 58 | fn bitxor(self, rhs: Uint) -> Uint { 59 | self.bitxor(&rhs) 60 | } 61 | } 62 | 63 | impl BitXor<&Uint> for &Uint { 64 | type Output = Uint; 65 | 66 | fn bitxor(self, rhs: &Uint) -> Uint { 67 | self.bitxor(rhs) 68 | } 69 | } 70 | 71 | impl BitXorAssign for Uint { 72 | fn bitxor_assign(&mut self, other: Self) { 73 | *self = *self ^ other; 74 | } 75 | } 76 | 77 | impl BitXorAssign<&Uint> for Uint { 78 | fn bitxor_assign(&mut self, other: &Self) { 79 | *self = *self ^ other; 80 | } 81 | } 82 | 83 | impl BitXor for Wrapping> { 84 | type Output = Self; 85 | 86 | fn bitxor(self, rhs: Self) -> Wrapping> { 87 | Wrapping(self.0.bitxor(&rhs.0)) 88 | } 89 | } 90 | 91 | impl BitXor<&Wrapping>> for Wrapping> { 92 | type Output = Wrapping>; 93 | 94 | fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { 95 | Wrapping(self.0.bitxor(&rhs.0)) 96 | } 97 | } 98 | 99 | impl BitXor>> for &Wrapping> { 100 | type Output = Wrapping>; 101 | 102 | fn bitxor(self, rhs: Wrapping>) -> Wrapping> { 103 | Wrapping(self.0.bitxor(&rhs.0)) 104 | } 105 | } 106 | 107 | impl BitXor<&Wrapping>> for &Wrapping> { 108 | type Output = Wrapping>; 109 | 110 | fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { 111 | Wrapping(self.0.bitxor(&rhs.0)) 112 | } 113 | } 114 | 115 | impl BitXorAssign for Wrapping> { 116 | fn bitxor_assign(&mut self, other: Self) { 117 | *self = *self ^ other; 118 | } 119 | } 120 | 121 | impl BitXorAssign<&Wrapping>> for Wrapping> { 122 | fn bitxor_assign(&mut self, other: &Self) { 123 | *self = *self ^ other; 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod tests { 129 | use crate::U128; 130 | 131 | #[test] 132 | fn checked_xor_ok() { 133 | let result = U128::ZERO.checked_xor(&U128::ONE); 134 | assert_eq!(result.unwrap(), U128::ONE); 135 | } 136 | 137 | #[test] 138 | fn overlapping_xor_ok() { 139 | let result = U128::ZERO.wrapping_xor(&U128::ONE); 140 | assert_eq!(result, U128::ONE); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/uint/boxed/add_mod.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] modular addition operations. 2 | 3 | use crate::{AddMod, BoxedUint, Limb, Zero}; 4 | 5 | impl BoxedUint { 6 | /// Computes `self + rhs mod p`. 7 | /// 8 | /// Assumes `self + rhs` as unbounded integer is `< 2p`. 9 | pub fn add_mod(&self, rhs: &Self, p: &Self) -> Self { 10 | let mut result = self.clone(); 11 | result.add_mod_assign(rhs, p); 12 | result 13 | } 14 | 15 | /// Computes `self + rhs mod p` and writes the result in `self`. 16 | /// 17 | /// Assumes `self + rhs` as unbounded integer is `< 2p`. 18 | pub fn add_mod_assign(&mut self, rhs: &Self, p: &Self) { 19 | debug_assert_eq!(self.bits_precision(), p.bits_precision()); 20 | debug_assert_eq!(rhs.bits_precision(), p.bits_precision()); 21 | debug_assert!(&*self < p); 22 | debug_assert!(rhs < p); 23 | 24 | let carry = self.carrying_add_assign(rhs, Limb::ZERO); 25 | 26 | // Attempt to subtract the modulus, to ensure the result is in the field. 27 | let borrow = self.borrowing_sub_assign(p, Limb::ZERO); 28 | let (_, borrow) = carry.borrowing_sub(Limb::ZERO, borrow); 29 | 30 | // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise 31 | // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the 32 | // modulus. 33 | self.conditional_carrying_add_assign(p, !borrow.is_zero()); 34 | } 35 | 36 | /// Computes `self + self mod p`. 37 | /// 38 | /// Assumes `self` as unbounded integer is `< p`. 39 | pub fn double_mod(&self, p: &Self) -> Self { 40 | let (mut w, carry) = self.overflowing_shl1(); 41 | 42 | // Attempt to subtract the modulus, to ensure the result is in the field. 43 | let borrow = w.borrowing_sub_assign(p, Limb::ZERO); 44 | let (_, borrow) = carry.borrowing_sub(Limb::ZERO, borrow); 45 | 46 | // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise 47 | // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the 48 | // modulus. 49 | w.conditional_carrying_add_assign(p, !borrow.is_zero()); 50 | w 51 | } 52 | } 53 | 54 | impl AddMod for BoxedUint { 55 | type Output = Self; 56 | 57 | fn add_mod(&self, rhs: &Self, p: &Self) -> Self { 58 | self.add_mod(rhs, p) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | use super::BoxedUint; 65 | use hex_literal::hex; 66 | 67 | // TODO(tarcieri): proptests 68 | 69 | #[test] 70 | fn add_mod_nist_p256() { 71 | let a = BoxedUint::from_be_slice( 72 | &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), 73 | 256, 74 | ) 75 | .unwrap(); 76 | let b = BoxedUint::from_be_slice( 77 | &hex!("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"), 78 | 256, 79 | ) 80 | .unwrap(); 81 | let n = BoxedUint::from_be_slice( 82 | &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), 83 | 256, 84 | ) 85 | .unwrap(); 86 | 87 | let actual = a.add_mod(&b, &n); 88 | let expected = BoxedUint::from_be_slice( 89 | &hex!("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"), 90 | 256, 91 | ) 92 | .unwrap(); 93 | 94 | assert_eq!(expected, actual); 95 | } 96 | 97 | #[test] 98 | fn double_mod_expected() { 99 | let a = BoxedUint::from_be_hex( 100 | "44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56", 101 | 256, 102 | ) 103 | .unwrap(); 104 | let n = BoxedUint::from_be_hex( 105 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 106 | 256, 107 | ) 108 | .unwrap(); 109 | 110 | assert_eq!(a.add_mod(&a, &n), a.double_mod(&n)); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/uint/boxed/bit_and.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] bitwise AND operations. 2 | 3 | use super::BoxedUint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::{BitAnd, BitAndAssign}; 6 | use subtle::{Choice, CtOption}; 7 | 8 | impl BoxedUint { 9 | /// Computes bitwise `a & b`. 10 | #[inline(always)] 11 | pub fn bitand(&self, rhs: &Self) -> Self { 12 | Self::map_limbs(self, rhs, |a, b| a.bitand(b)) 13 | } 14 | 15 | /// Perform bitwise `AND` between `self` and the given [`Limb`], performing the `AND` operation 16 | /// on every limb of `self`. 17 | pub fn bitand_limb(&self, rhs: Limb) -> Self { 18 | Self { 19 | limbs: self.limbs.iter().map(|limb| limb.bitand(rhs)).collect(), 20 | } 21 | } 22 | 23 | /// Perform wrapping bitwise `AND`. 24 | /// 25 | /// There's no way wrapping could ever happen. 26 | /// This function exists so that all operations are accounted for in the wrapping operations 27 | pub fn wrapping_and(&self, rhs: &Self) -> Self { 28 | self.bitand(rhs) 29 | } 30 | 31 | /// Perform checked bitwise `AND`, returning a [`CtOption`] which `is_some` always 32 | pub fn checked_and(&self, rhs: &Self) -> CtOption { 33 | let result = self.bitand(rhs); 34 | CtOption::new(result, Choice::from(1)) 35 | } 36 | } 37 | 38 | impl BitAnd for BoxedUint { 39 | type Output = Self; 40 | 41 | fn bitand(self, rhs: Self) -> BoxedUint { 42 | self.bitand(&rhs) 43 | } 44 | } 45 | 46 | impl BitAnd<&BoxedUint> for BoxedUint { 47 | type Output = BoxedUint; 48 | 49 | #[allow(clippy::needless_borrow)] 50 | fn bitand(self, rhs: &BoxedUint) -> BoxedUint { 51 | (&self).bitand(rhs) 52 | } 53 | } 54 | 55 | impl BitAnd for &BoxedUint { 56 | type Output = BoxedUint; 57 | 58 | fn bitand(self, rhs: BoxedUint) -> BoxedUint { 59 | self.bitand(&rhs) 60 | } 61 | } 62 | 63 | impl BitAnd<&BoxedUint> for &BoxedUint { 64 | type Output = BoxedUint; 65 | 66 | fn bitand(self, rhs: &BoxedUint) -> BoxedUint { 67 | self.bitand(rhs) 68 | } 69 | } 70 | 71 | impl BitAndAssign for BoxedUint { 72 | #[allow(clippy::assign_op_pattern)] 73 | fn bitand_assign(&mut self, other: Self) { 74 | *self = BoxedUint::bitand(self, &other); 75 | } 76 | } 77 | 78 | impl BitAndAssign<&BoxedUint> for BoxedUint { 79 | #[allow(clippy::assign_op_pattern)] 80 | fn bitand_assign(&mut self, other: &Self) { 81 | *self = BoxedUint::bitand(self, other); 82 | } 83 | } 84 | 85 | impl BitAnd for Wrapping { 86 | type Output = Self; 87 | 88 | fn bitand(self, rhs: Self) -> Wrapping { 89 | Wrapping(self.0.bitand(&rhs.0)) 90 | } 91 | } 92 | 93 | impl BitAnd<&Wrapping> for Wrapping { 94 | type Output = Wrapping; 95 | 96 | fn bitand(self, rhs: &Wrapping) -> Wrapping { 97 | Wrapping(self.0.bitand(&rhs.0)) 98 | } 99 | } 100 | 101 | impl BitAnd> for &Wrapping { 102 | type Output = Wrapping; 103 | 104 | fn bitand(self, rhs: Wrapping) -> Wrapping { 105 | Wrapping(BoxedUint::bitand(&self.0, &rhs.0)) 106 | } 107 | } 108 | 109 | impl BitAnd<&Wrapping> for &Wrapping { 110 | type Output = Wrapping; 111 | 112 | fn bitand(self, rhs: &Wrapping) -> Wrapping { 113 | Wrapping(BoxedUint::bitand(&self.0, &rhs.0)) 114 | } 115 | } 116 | 117 | impl BitAndAssign for Wrapping { 118 | #[allow(clippy::assign_op_pattern)] 119 | fn bitand_assign(&mut self, other: Self) { 120 | *self = Wrapping(BoxedUint::bitand(&self.0, &other.0)) 121 | } 122 | } 123 | 124 | impl BitAndAssign<&Wrapping> for Wrapping { 125 | #[allow(clippy::assign_op_pattern)] 126 | fn bitand_assign(&mut self, other: &Self) { 127 | *self = Wrapping(BoxedUint::bitand(&self.0, &other.0)) 128 | } 129 | } 130 | 131 | #[cfg(test)] 132 | mod tests { 133 | use crate::BoxedUint; 134 | 135 | #[test] 136 | fn checked_and_ok() { 137 | let result = BoxedUint::zero().checked_and(&BoxedUint::one()); 138 | assert_eq!(result.unwrap(), BoxedUint::zero()); 139 | } 140 | 141 | #[test] 142 | fn overlapping_and_ok() { 143 | let result = BoxedUint::max(128).wrapping_and(&BoxedUint::one()); 144 | assert_eq!(result, BoxedUint::one()); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/uint/boxed/bit_not.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] bitwise NOT operations. 2 | 3 | use super::BoxedUint; 4 | use crate::{Limb, Wrapping}; 5 | use core::ops::Not; 6 | 7 | impl BoxedUint { 8 | /// Computes bitwise `!a`. 9 | pub fn not(&self) -> Self { 10 | let mut limbs = vec![Limb::ZERO; self.nlimbs()]; 11 | 12 | for i in 0..self.nlimbs() { 13 | limbs[i] = self.limbs[i].not(); 14 | } 15 | 16 | limbs.into() 17 | } 18 | } 19 | 20 | impl Not for BoxedUint { 21 | type Output = Self; 22 | 23 | fn not(self) -> Self { 24 | BoxedUint::not(&self) 25 | } 26 | } 27 | 28 | impl Not for Wrapping { 29 | type Output = Self; 30 | 31 | fn not(self) -> ::Output { 32 | Wrapping(self.0.not()) 33 | } 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use crate::BoxedUint; 39 | 40 | #[test] 41 | fn bitnot_ok() { 42 | assert_eq!( 43 | BoxedUint::zero_with_precision(128).not(), 44 | BoxedUint::max(128) 45 | ); 46 | assert_eq!( 47 | BoxedUint::max(128).not(), 48 | BoxedUint::zero_with_precision(128) 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/uint/boxed/bit_or.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] bitwise OR operations. 2 | 3 | use crate::{BoxedUint, Wrapping}; 4 | use core::ops::{BitOr, BitOrAssign}; 5 | use subtle::{Choice, CtOption}; 6 | 7 | impl BoxedUint { 8 | /// Computes bitwise `a & b`. 9 | #[inline(always)] 10 | pub fn bitor(&self, rhs: &Self) -> Self { 11 | Self::map_limbs(self, rhs, |a, b| a.bitor(b)) 12 | } 13 | 14 | /// Perform wrapping bitwise `OR`. 15 | /// 16 | /// There's no way wrapping could ever happen. 17 | /// This function exists so that all operations are accounted for in the wrapping operations 18 | pub fn wrapping_or(&self, rhs: &Self) -> Self { 19 | self.bitor(rhs) 20 | } 21 | 22 | /// Perform checked bitwise `OR`, returning a [`CtOption`] which `is_some` always 23 | pub fn checked_or(&self, rhs: &Self) -> CtOption { 24 | let result = self.bitor(rhs); 25 | CtOption::new(result, Choice::from(1)) 26 | } 27 | } 28 | 29 | impl BitOr for BoxedUint { 30 | type Output = Self; 31 | 32 | fn bitor(self, rhs: Self) -> BoxedUint { 33 | self.bitor(&rhs) 34 | } 35 | } 36 | 37 | impl BitOr<&BoxedUint> for BoxedUint { 38 | type Output = BoxedUint; 39 | 40 | #[allow(clippy::needless_borrow)] 41 | fn bitor(self, rhs: &BoxedUint) -> BoxedUint { 42 | (&self).bitor(rhs) 43 | } 44 | } 45 | 46 | impl BitOr for &BoxedUint { 47 | type Output = BoxedUint; 48 | 49 | fn bitor(self, rhs: BoxedUint) -> BoxedUint { 50 | self.bitor(&rhs) 51 | } 52 | } 53 | 54 | impl BitOr<&BoxedUint> for &BoxedUint { 55 | type Output = BoxedUint; 56 | 57 | fn bitor(self, rhs: &BoxedUint) -> BoxedUint { 58 | self.bitor(rhs) 59 | } 60 | } 61 | 62 | impl BitOrAssign for BoxedUint { 63 | fn bitor_assign(&mut self, other: Self) { 64 | Self::bitor_assign(self, &other) 65 | } 66 | } 67 | 68 | impl BitOrAssign<&BoxedUint> for BoxedUint { 69 | fn bitor_assign(&mut self, other: &Self) { 70 | for (a, b) in self.limbs.iter_mut().zip(other.limbs.iter()) { 71 | *a |= *b; 72 | } 73 | } 74 | } 75 | 76 | impl BitOr for Wrapping { 77 | type Output = Self; 78 | 79 | fn bitor(self, rhs: Self) -> Wrapping { 80 | Wrapping(self.0.bitor(&rhs.0)) 81 | } 82 | } 83 | 84 | impl BitOr<&Wrapping> for Wrapping { 85 | type Output = Wrapping; 86 | 87 | fn bitor(self, rhs: &Wrapping) -> Wrapping { 88 | Wrapping(self.0.bitor(&rhs.0)) 89 | } 90 | } 91 | 92 | impl BitOr> for &Wrapping { 93 | type Output = Wrapping; 94 | 95 | fn bitor(self, rhs: Wrapping) -> Wrapping { 96 | Wrapping(BoxedUint::bitor(&self.0, &rhs.0)) 97 | } 98 | } 99 | 100 | impl BitOr<&Wrapping> for &Wrapping { 101 | type Output = Wrapping; 102 | 103 | fn bitor(self, rhs: &Wrapping) -> Wrapping { 104 | Wrapping(BoxedUint::bitor(&self.0, &rhs.0)) 105 | } 106 | } 107 | 108 | impl BitOrAssign for Wrapping { 109 | fn bitor_assign(&mut self, other: Self) { 110 | self.0.bitor_assign(&other.0) 111 | } 112 | } 113 | 114 | impl BitOrAssign<&Wrapping> for Wrapping { 115 | fn bitor_assign(&mut self, other: &Self) { 116 | self.0.bitor_assign(&other.0) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/uint/boxed/bit_xor.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] bitwise XOR operations. 2 | 3 | use super::BoxedUint; 4 | use crate::Wrapping; 5 | use core::ops::{BitXor, BitXorAssign}; 6 | use subtle::{Choice, CtOption}; 7 | 8 | impl BoxedUint { 9 | /// Computes bitwise `a ^ b`. 10 | #[inline(always)] 11 | pub fn bitxor(&self, rhs: &Self) -> Self { 12 | Self::map_limbs(self, rhs, |a, b| a.bitxor(b)) 13 | } 14 | 15 | /// Perform wrapping bitwise `XOR``. 16 | /// 17 | /// There's no way wrapping could ever happen. 18 | /// This function exists so that all operations are accounted for in the wrapping operations 19 | pub fn wrapping_xor(&self, rhs: &Self) -> Self { 20 | self.bitxor(rhs) 21 | } 22 | 23 | /// Perform checked bitwise `XOR`, returning a [`CtOption`] which `is_some` always 24 | pub fn checked_xor(&self, rhs: &Self) -> CtOption { 25 | let result = self.bitxor(rhs); 26 | CtOption::new(result, Choice::from(1)) 27 | } 28 | } 29 | 30 | impl BitXor for BoxedUint { 31 | type Output = Self; 32 | 33 | fn bitxor(self, rhs: Self) -> BoxedUint { 34 | self.bitxor(&rhs) 35 | } 36 | } 37 | 38 | impl BitXor<&BoxedUint> for BoxedUint { 39 | type Output = BoxedUint; 40 | 41 | fn bitxor(self, rhs: &BoxedUint) -> BoxedUint { 42 | Self::bitxor(&self, rhs) 43 | } 44 | } 45 | 46 | impl BitXor for &BoxedUint { 47 | type Output = BoxedUint; 48 | 49 | fn bitxor(self, rhs: BoxedUint) -> BoxedUint { 50 | self.bitxor(&rhs) 51 | } 52 | } 53 | 54 | impl BitXor<&BoxedUint> for &BoxedUint { 55 | type Output = BoxedUint; 56 | 57 | fn bitxor(self, rhs: &BoxedUint) -> BoxedUint { 58 | self.bitxor(rhs) 59 | } 60 | } 61 | 62 | impl BitXorAssign for BoxedUint { 63 | fn bitxor_assign(&mut self, other: Self) { 64 | *self = Self::bitxor(self, &other); 65 | } 66 | } 67 | 68 | impl BitXorAssign<&BoxedUint> for BoxedUint { 69 | fn bitxor_assign(&mut self, other: &Self) { 70 | *self = Self::bitxor(self, other); 71 | } 72 | } 73 | 74 | impl BitXor for Wrapping { 75 | type Output = Self; 76 | 77 | fn bitxor(self, rhs: Self) -> Wrapping { 78 | Wrapping(self.0.bitxor(&rhs.0)) 79 | } 80 | } 81 | 82 | impl BitXor<&Wrapping> for Wrapping { 83 | type Output = Wrapping; 84 | 85 | fn bitxor(self, rhs: &Wrapping) -> Wrapping { 86 | Wrapping(self.0.bitxor(&rhs.0)) 87 | } 88 | } 89 | 90 | impl BitXor> for &Wrapping { 91 | type Output = Wrapping; 92 | 93 | fn bitxor(self, rhs: Wrapping) -> Wrapping { 94 | Wrapping(BoxedUint::bitxor(&self.0, &rhs.0)) 95 | } 96 | } 97 | 98 | impl BitXor<&Wrapping> for &Wrapping { 99 | type Output = Wrapping; 100 | 101 | fn bitxor(self, rhs: &Wrapping) -> Wrapping { 102 | Wrapping(BoxedUint::bitxor(&self.0, &rhs.0)) 103 | } 104 | } 105 | 106 | impl BitXorAssign for Wrapping { 107 | fn bitxor_assign(&mut self, other: Self) { 108 | *self = Wrapping(BoxedUint::bitxor(&self.0, &other.0)); 109 | } 110 | } 111 | 112 | impl BitXorAssign<&Wrapping> for Wrapping { 113 | fn bitxor_assign(&mut self, other: &Self) { 114 | *self = Wrapping(BoxedUint::bitxor(&self.0, &other.0)); 115 | } 116 | } 117 | 118 | #[cfg(test)] 119 | mod tests { 120 | use crate::U128; 121 | 122 | #[test] 123 | fn checked_xor_ok() { 124 | let result = U128::ZERO.checked_xor(&U128::ONE); 125 | assert_eq!(result.unwrap(), U128::ONE); 126 | } 127 | 128 | #[test] 129 | fn overlapping_xor_ok() { 130 | let result = U128::ZERO.wrapping_xor(&U128::ONE); 131 | assert_eq!(result, U128::ONE); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/uint/boxed/ct.rs: -------------------------------------------------------------------------------- 1 | //! Constant-time helper functions. 2 | 3 | use super::BoxedUint; 4 | use crate::{ConstantTimeSelect, Limb}; 5 | use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable}; 6 | 7 | /// NOTE: can't impl `subtle`'s [`ConditionallySelectable`] trait due to its `Copy` bound 8 | impl ConstantTimeSelect for BoxedUint { 9 | #[inline] 10 | fn ct_select(a: &Self, b: &Self, choice: Choice) -> Self { 11 | debug_assert_eq!(a.bits_precision(), b.bits_precision()); 12 | let mut limbs = vec![Limb::ZERO; a.nlimbs()].into_boxed_slice(); 13 | 14 | for i in 0..a.nlimbs() { 15 | limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice); 16 | } 17 | 18 | Self { limbs } 19 | } 20 | 21 | #[inline] 22 | fn ct_assign(&mut self, other: &Self, choice: Choice) { 23 | debug_assert_eq!(self.bits_precision(), other.bits_precision()); 24 | 25 | for i in 0..self.nlimbs() { 26 | self.limbs[i].conditional_assign(&other.limbs[i], choice); 27 | } 28 | } 29 | 30 | #[inline] 31 | fn ct_swap(a: &mut Self, b: &mut Self, choice: Choice) { 32 | debug_assert_eq!(a.bits_precision(), b.bits_precision()); 33 | 34 | for i in 0..a.nlimbs() { 35 | Limb::conditional_swap(&mut a.limbs[i], &mut b.limbs[i], choice); 36 | } 37 | } 38 | } 39 | 40 | impl ConditionallyNegatable for BoxedUint { 41 | #[inline] 42 | fn conditional_negate(&mut self, choice: Choice) { 43 | let self_neg = self.wrapping_neg(); 44 | self.ct_assign(&self_neg, choice) 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | use crate::{BoxedUint, ConstantTimeSelect}; 51 | use subtle::{Choice, ConditionallyNegatable}; 52 | 53 | #[test] 54 | fn conditional_select() { 55 | let a = BoxedUint::zero_with_precision(128); 56 | let b = BoxedUint::max(128); 57 | 58 | assert_eq!(a, BoxedUint::ct_select(&a, &b, Choice::from(0))); 59 | assert_eq!(b, BoxedUint::ct_select(&a, &b, Choice::from(1))); 60 | } 61 | 62 | #[test] 63 | fn conditional_negate() { 64 | let mut a = BoxedUint::from(123u64); 65 | let control = a.clone(); 66 | 67 | a.conditional_negate(Choice::from(0)); 68 | assert_eq!(a, control); 69 | 70 | a.conditional_negate(Choice::from(1)); 71 | assert_ne!(a, control); 72 | assert_eq!(a, control.wrapping_neg()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/uint/boxed/div_limb.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of constant-time division via reciprocal precomputation, as described in 2 | //! "Improved Division by Invariant Integers" by Niels Möller and Torbjorn Granlund 3 | //! (DOI: 10.1109/TC.2010.143, ). 4 | use crate::{BoxedUint, ConstChoice, Limb, Reciprocal, uint::div_limb::div2by1}; 5 | 6 | /// Divides `u` by the divisor encoded in the `reciprocal`, and returns 7 | /// the quotient and the remainder. 8 | #[inline(always)] 9 | pub(crate) fn div_rem_limb_with_reciprocal( 10 | u: &BoxedUint, 11 | reciprocal: &Reciprocal, 12 | ) -> (BoxedUint, Limb) { 13 | let (mut q, mut r) = u.shl_limb(reciprocal.shift()); 14 | let mut j = u.limbs.len(); 15 | while j > 0 { 16 | j -= 1; 17 | (q.limbs[j].0, r.0) = div2by1(r.0, q.limbs[j].0, reciprocal); 18 | } 19 | (q, r >> reciprocal.shift()) 20 | } 21 | 22 | /// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder. 23 | #[inline(always)] 24 | pub(crate) fn rem_limb_with_reciprocal(u: &BoxedUint, reciprocal: &Reciprocal) -> Limb { 25 | let lshift = reciprocal.shift(); 26 | let nz = ConstChoice::from_u32_nonzero(lshift); 27 | let rshift = nz.if_true_u32(Limb::BITS - lshift); 28 | let mut hi = nz.if_true_word( 29 | u.limbs[u.limbs.len() - 1] 30 | .0 31 | .wrapping_shr(Limb::BITS - lshift), 32 | ); 33 | let mut lo; 34 | let mut j = u.limbs.len(); 35 | while j > 1 { 36 | j -= 1; 37 | lo = u.limbs[j].0 << lshift; 38 | lo |= nz.if_true_word(u.limbs[j - 1].0 >> rshift); 39 | (_, hi) = div2by1(hi, lo, reciprocal); 40 | } 41 | (_, hi) = div2by1(hi, u.limbs[0].0 << lshift, reciprocal); 42 | Limb(hi >> reciprocal.shift()) 43 | } 44 | -------------------------------------------------------------------------------- /src/uint/boxed/from.rs: -------------------------------------------------------------------------------- 1 | //! `From`-like conversions for [`BoxedUint`]. 2 | 3 | use crate::{BoxedUint, Limb, Odd, U64, U128, Uint, Word}; 4 | use alloc::{boxed::Box, vec::Vec}; 5 | use core::mem; 6 | 7 | impl From for BoxedUint { 8 | fn from(n: u8) -> Self { 9 | vec![Limb::from(n); 1].into() 10 | } 11 | } 12 | 13 | impl From for BoxedUint { 14 | fn from(n: u16) -> Self { 15 | vec![Limb::from(n); 1].into() 16 | } 17 | } 18 | 19 | impl From for BoxedUint { 20 | fn from(n: u32) -> Self { 21 | vec![Limb::from(n); 1].into() 22 | } 23 | } 24 | 25 | impl From for BoxedUint { 26 | fn from(n: u64) -> Self { 27 | U64::from(n).into() 28 | } 29 | } 30 | 31 | impl From for BoxedUint { 32 | fn from(n: u128) -> Self { 33 | U128::from(n).into() 34 | } 35 | } 36 | 37 | impl From for BoxedUint { 38 | fn from(limb: Limb) -> Self { 39 | vec![limb; 1].into() 40 | } 41 | } 42 | 43 | impl From<&[Limb]> for BoxedUint { 44 | fn from(limbs: &[Limb]) -> BoxedUint { 45 | Self { 46 | limbs: limbs.into(), 47 | } 48 | } 49 | } 50 | 51 | impl From> for BoxedUint { 52 | fn from(limbs: Box<[Limb]>) -> BoxedUint { 53 | Vec::from(limbs).into() 54 | } 55 | } 56 | 57 | impl From> for BoxedUint { 58 | fn from(mut limbs: Vec) -> BoxedUint { 59 | if limbs.is_empty() { 60 | limbs.push(Limb::ZERO); 61 | } 62 | 63 | Self { 64 | limbs: limbs.into_boxed_slice(), 65 | } 66 | } 67 | } 68 | 69 | impl From> for BoxedUint { 70 | fn from(mut words: Vec) -> BoxedUint { 71 | // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` 72 | #[allow(unsafe_code)] 73 | unsafe { 74 | let ptr = words.as_mut_ptr() as *mut Limb; 75 | let len = words.len(); 76 | let capacity = words.capacity(); 77 | mem::forget(words); 78 | Vec::::from_raw_parts(ptr, len, capacity) 79 | } 80 | .into() 81 | } 82 | } 83 | 84 | impl From> for BoxedUint { 85 | #[inline] 86 | fn from(uint: Uint) -> BoxedUint { 87 | Self::from(&uint) 88 | } 89 | } 90 | 91 | impl From<&Uint> for BoxedUint { 92 | #[inline] 93 | fn from(uint: &Uint) -> BoxedUint { 94 | Vec::from(uint.to_limbs()).into() 95 | } 96 | } 97 | 98 | impl From>> for BoxedUint { 99 | #[inline] 100 | fn from(uint: Odd>) -> BoxedUint { 101 | Self::from(&uint.0) 102 | } 103 | } 104 | 105 | impl From<&Odd>> for BoxedUint { 106 | #[inline] 107 | fn from(uint: &Odd>) -> BoxedUint { 108 | Self::from(&uint.0) 109 | } 110 | } 111 | 112 | impl From>> for Odd { 113 | #[inline] 114 | fn from(uint: Odd>) -> Odd { 115 | Odd(BoxedUint::from(&uint.0)) 116 | } 117 | } 118 | 119 | impl From<&Odd>> for Odd { 120 | #[inline] 121 | fn from(uint: &Odd>) -> Odd { 122 | Odd(BoxedUint::from(&uint.0)) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/uint/boxed/gcd.rs: -------------------------------------------------------------------------------- 1 | //! Support for computing greatest common divisor of two `BoxedUint`s. 2 | 3 | use super::BoxedUint; 4 | use crate::{ConstantTimeSelect, Gcd, Integer, Odd, modular::safegcd}; 5 | use subtle::{ConditionallySelectable, ConstantTimeLess}; 6 | 7 | impl Gcd for BoxedUint { 8 | type Output = Self; 9 | 10 | /// Compute the greatest common divisor (GCD) of this number and another. 11 | fn gcd(&self, rhs: &Self) -> Self { 12 | let k1 = self.trailing_zeros(); 13 | let k2 = rhs.trailing_zeros(); 14 | 15 | // Select the smaller of the two `k` values, making 2^k the common even divisor 16 | let k = u32::conditional_select(&k1, &k2, u32::ct_lt(&k2, &k1)); 17 | 18 | // Decompose `self` and `rhs` into `s{1, 2} * 2^k` where either `s1` or `s2` is odd 19 | let s1 = self.overflowing_shr(k).0; 20 | let s2 = rhs.overflowing_shr(k).0; 21 | 22 | let f = Self::ct_select(&s1, &s2, !s2.is_odd()); 23 | let g = Self::ct_select(&s1, &s2, s2.is_odd()); 24 | safegcd::boxed::gcd(&f, &g).overflowing_shl(k).0 25 | } 26 | 27 | fn gcd_vartime(&self, rhs: &Self) -> Self::Output { 28 | match Odd::::new(self.clone()).into_option() { 29 | Some(odd) => odd.gcd_vartime(rhs), 30 | None => self.gcd(rhs), // TODO(tarcieri): vartime support for even `self`? 31 | } 32 | } 33 | } 34 | 35 | impl Gcd for Odd { 36 | type Output = BoxedUint; 37 | 38 | fn gcd(&self, rhs: &BoxedUint) -> BoxedUint { 39 | safegcd::boxed::gcd(self, rhs) 40 | } 41 | 42 | fn gcd_vartime(&self, rhs: &BoxedUint) -> Self::Output { 43 | safegcd::boxed::gcd_vartime(self, rhs) 44 | } 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use crate::{BoxedUint, Gcd, Resize}; 50 | 51 | #[test] 52 | fn gcd_relatively_prime() { 53 | // Two semiprimes with no common factors 54 | let f = BoxedUint::from(59u32 * 67).to_odd().unwrap(); 55 | let g = BoxedUint::from(61u32 * 71); 56 | let gcd = f.gcd(&g); 57 | assert_eq!(gcd, BoxedUint::one()); 58 | } 59 | 60 | #[test] 61 | fn gcd_nonprime() { 62 | let f = BoxedUint::from(4391633u32).to_odd().unwrap(); 63 | let g = BoxedUint::from(2022161u32); 64 | let gcd = f.gcd(&g); 65 | assert_eq!(gcd, BoxedUint::from(1763u32)); 66 | } 67 | 68 | #[test] 69 | fn gcd_zero() { 70 | let zero = BoxedUint::from(0u32); 71 | let one = BoxedUint::from(1u32); 72 | 73 | assert_eq!(zero.gcd(&zero), zero); 74 | assert_eq!(zero.gcd(&one), one); 75 | assert_eq!(one.gcd(&zero), one); 76 | } 77 | 78 | #[test] 79 | fn gcd_one() { 80 | let f = BoxedUint::from(1u32); 81 | assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(1u32))); 82 | assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(2u8))); 83 | } 84 | 85 | #[test] 86 | fn gcd_two() { 87 | let f = BoxedUint::from(2u32); 88 | assert_eq!(f, f.gcd(&f)); 89 | 90 | let g = BoxedUint::from(4u32); 91 | assert_eq!(f, f.gcd(&g)); 92 | assert_eq!(f, g.gcd(&f)); 93 | } 94 | 95 | #[test] 96 | fn gcd_different_sizes() { 97 | // Test that gcd works for boxed Uints with different numbers of limbs 98 | let f = BoxedUint::from(4391633u32).resize(128).to_odd().unwrap(); 99 | let g = BoxedUint::from(2022161u32); 100 | let gcd = f.gcd(&g); 101 | assert_eq!(gcd, BoxedUint::from(1763u32)); 102 | } 103 | 104 | #[test] 105 | fn gcd_vartime_different_sizes() { 106 | // Test that gcd works for boxed Uints with different numbers of limbs 107 | let f = BoxedUint::from(4391633u32).resize(128).to_odd().unwrap(); 108 | let g = BoxedUint::from(2022161u32); 109 | let gcd = f.gcd_vartime(&g); 110 | assert_eq!(gcd, BoxedUint::from(1763u32)); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/uint/boxed/neg.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] negation operations. 2 | 3 | use crate::{BoxedUint, Limb, WideWord, Word, WrappingNeg}; 4 | 5 | impl BoxedUint { 6 | /// Perform wrapping negation. 7 | pub fn wrapping_neg(&self) -> Self { 8 | let mut ret = vec![Limb::ZERO; self.nlimbs()]; 9 | let mut carry = 1; 10 | 11 | for i in 0..self.nlimbs() { 12 | let r = (!self.limbs[i].0 as WideWord) + carry; 13 | ret[i] = Limb(r as Word); 14 | carry = r >> Limb::BITS; 15 | } 16 | 17 | ret.into() 18 | } 19 | } 20 | 21 | impl WrappingNeg for BoxedUint { 22 | fn wrapping_neg(&self) -> Self { 23 | self.wrapping_neg() 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use crate::BoxedUint; 30 | 31 | #[test] 32 | fn wrapping_neg() { 33 | assert_eq!(BoxedUint::zero().wrapping_neg(), BoxedUint::zero()); 34 | assert_eq!(BoxedUint::max(64).wrapping_neg(), BoxedUint::one()); 35 | // assert_eq!( 36 | // BoxedUint::from(13u64).wrapping_neg(), 37 | // BoxedUint::from(13u64).not().saturating_add(&BoxedUint::one()) 38 | // ); 39 | // assert_eq!( 40 | // BoxedUint::from(42u64).wrapping_neg(), 41 | // BoxedUint::from(42u64).saturating_sub(&BoxedUint::one()).not() 42 | // ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/uint/boxed/neg_mod.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] modular negation operations. 2 | 3 | use crate::{BoxedUint, Limb, NegMod}; 4 | use subtle::ConditionallySelectable; 5 | 6 | impl BoxedUint { 7 | /// Computes `-a mod p`. 8 | /// Assumes `self` is in `[0, p)`. 9 | pub fn neg_mod(&self, p: &Self) -> Self { 10 | debug_assert_eq!(self.bits_precision(), p.bits_precision()); 11 | let is_zero = self.is_zero(); 12 | let mut ret = p.borrowing_sub(self, Limb::ZERO).0; 13 | 14 | for i in 0..self.nlimbs() { 15 | // Set ret to 0 if the original value was 0, in which 16 | // case ret would be p. 17 | ret.limbs[i].conditional_assign(&Limb::ZERO, is_zero); 18 | } 19 | 20 | ret 21 | } 22 | 23 | /// Computes `-a mod p` for the special modulus 24 | /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. 25 | pub fn neg_mod_special(&self, c: Limb) -> Self { 26 | Self::zero_with_precision(self.bits_precision()).sub_mod_special(self, c) 27 | } 28 | } 29 | 30 | impl NegMod for BoxedUint { 31 | type Output = Self; 32 | 33 | fn neg_mod(&self, p: &Self) -> Self { 34 | debug_assert!(self < p); 35 | self.neg_mod(p) 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use crate::BoxedUint; 42 | use hex_literal::hex; 43 | 44 | #[test] 45 | fn neg_mod_random() { 46 | let x = BoxedUint::from_be_slice( 47 | &hex!("8d16e171674b4e6d8529edba4593802bf30b8cb161dd30aa8e550d41380007c2"), 48 | 256, 49 | ) 50 | .unwrap(); 51 | let p = BoxedUint::from_be_slice( 52 | &hex!("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"), 53 | 256, 54 | ) 55 | .unwrap(); 56 | 57 | let actual = x.neg_mod(&p); 58 | let expected = BoxedUint::from_be_slice( 59 | &hex!("056c53337d72b9d666f86c9256ce5f08cabc1b63b207864ce0d6ecf010e2d9f3"), 60 | 256, 61 | ) 62 | .unwrap(); 63 | 64 | assert_eq!(expected, actual); 65 | } 66 | 67 | #[test] 68 | fn neg_mod_zero() { 69 | let x = BoxedUint::from_be_slice( 70 | &hex!("0000000000000000000000000000000000000000000000000000000000000000"), 71 | 256, 72 | ) 73 | .unwrap(); 74 | let p = BoxedUint::from_be_slice( 75 | &hex!("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"), 76 | 256, 77 | ) 78 | .unwrap(); 79 | 80 | let actual = x.neg_mod(&p); 81 | let expected = BoxedUint::from_be_slice( 82 | &hex!("0000000000000000000000000000000000000000000000000000000000000000"), 83 | 256, 84 | ) 85 | .unwrap(); 86 | 87 | assert_eq!(expected, actual); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/uint/boxed/rand.rs: -------------------------------------------------------------------------------- 1 | //! Random number generator support. 2 | 3 | use super::BoxedUint; 4 | use crate::{ 5 | NonZero, RandomBits, RandomBitsError, RandomMod, 6 | uint::rand::{random_bits_core, random_mod_core}, 7 | }; 8 | use rand_core::{RngCore, TryRngCore}; 9 | 10 | impl RandomBits for BoxedUint { 11 | fn try_random_bits( 12 | rng: &mut R, 13 | bit_length: u32, 14 | ) -> Result> { 15 | Self::try_random_bits_with_precision(rng, bit_length, bit_length) 16 | } 17 | 18 | fn try_random_bits_with_precision( 19 | rng: &mut R, 20 | bit_length: u32, 21 | bits_precision: u32, 22 | ) -> Result> { 23 | if bit_length > bits_precision { 24 | return Err(RandomBitsError::BitLengthTooLarge { 25 | bit_length, 26 | bits_precision, 27 | }); 28 | } 29 | 30 | let mut ret = BoxedUint::zero_with_precision(bits_precision); 31 | random_bits_core(rng, &mut ret.limbs, bit_length)?; 32 | Ok(ret) 33 | } 34 | } 35 | 36 | impl RandomMod for BoxedUint { 37 | fn random_mod(rng: &mut R, modulus: &NonZero) -> Self { 38 | let mut n = BoxedUint::zero_with_precision(modulus.bits_precision()); 39 | let Ok(()) = random_mod_core(rng, &mut n, modulus, modulus.bits()); 40 | n 41 | } 42 | 43 | fn try_random_mod( 44 | rng: &mut R, 45 | modulus: &NonZero, 46 | ) -> Result { 47 | let mut n = BoxedUint::zero_with_precision(modulus.bits_precision()); 48 | random_mod_core(rng, &mut n, modulus, modulus.bits())?; 49 | Ok(n) 50 | } 51 | } 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | use crate::{BoxedUint, NonZero, RandomBits, RandomMod}; 56 | use rand_core::SeedableRng; 57 | 58 | #[test] 59 | fn random() { 60 | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); 61 | 62 | let r = BoxedUint::random_bits(&mut rng, 256); 63 | assert!(r.bits_precision() == 256); 64 | 65 | let r = BoxedUint::random_bits(&mut rng, 256 - 32 + 1); 66 | assert!(r.bits_precision() == 256); 67 | assert!(r < BoxedUint::one_with_precision(256) << (256 - 32 + 1)); 68 | } 69 | 70 | #[test] 71 | fn random_mod() { 72 | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); 73 | 74 | // Ensure `random_mod` runs in a reasonable amount of time 75 | let modulus = NonZero::new(BoxedUint::from(42u8)).unwrap(); 76 | let res = BoxedUint::random_mod(&mut rng, &modulus); 77 | 78 | // Check that the value is in range 79 | assert!(res < BoxedUint::from(42u8)); 80 | 81 | // Ensure `random_mod` runs in a reasonable amount of time 82 | // when the modulus is larger than 1 limb 83 | let modulus = NonZero::new(BoxedUint::from(0x10000000000000001u128)).unwrap(); 84 | let res = BoxedUint::random_mod(&mut rng, &modulus); 85 | 86 | // Check that the value is in range 87 | assert!(res < BoxedUint::from(0x10000000000000001u128)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/uint/boxed/sub_mod.rs: -------------------------------------------------------------------------------- 1 | //! [`BoxedUint`] modular subtraction operations. 2 | 3 | use crate::{BoxedUint, Limb, SubMod, Zero}; 4 | 5 | impl BoxedUint { 6 | /// Computes `self - rhs mod p`. 7 | /// 8 | /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. 9 | pub fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { 10 | debug_assert_eq!(self.bits_precision(), p.bits_precision()); 11 | debug_assert_eq!(rhs.bits_precision(), p.bits_precision()); 12 | debug_assert!(self < p); 13 | debug_assert!(rhs < p); 14 | 15 | let (mut out, borrow) = self.borrowing_sub(rhs, Limb::ZERO); 16 | 17 | // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise 18 | // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. 19 | out.conditional_carrying_add_assign(p, !borrow.is_zero()); 20 | out 21 | } 22 | 23 | /// Returns `(self..., carry) - (rhs...) mod (p...)`, where `carry <= 1`. 24 | /// Assumes `-(p...) <= (self..., carry) - (rhs...) < (p...)`. 25 | #[inline(always)] 26 | pub(crate) fn sub_assign_mod_with_carry(&mut self, carry: Limb, rhs: &Self, p: &Self) { 27 | debug_assert!(carry.0 <= 1); 28 | 29 | let borrow = self.borrowing_sub_assign(rhs, Limb::ZERO); 30 | 31 | // The new `borrow = Word::MAX` iff `carry == 0` and `borrow == Word::MAX`. 32 | let mask = carry.wrapping_neg().not().bitand(borrow); 33 | 34 | // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise 35 | // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. 36 | self.conditional_carrying_add_assign(p, !mask.is_zero()); 37 | } 38 | 39 | /// Computes `self - rhs mod p` for the special modulus 40 | /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. 41 | /// 42 | /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. 43 | pub fn sub_mod_special(&self, rhs: &Self, c: Limb) -> Self { 44 | let (out, borrow) = self.borrowing_sub(rhs, Limb::ZERO); 45 | 46 | // If underflow occurred, then we need to subtract `c` to account for 47 | // the underflow. This cannot underflow due to the assumption 48 | // `self - rhs >= -p`. 49 | let l = borrow.0 & c.0; 50 | out.wrapping_sub(&Self::from(l)) 51 | } 52 | } 53 | 54 | impl SubMod for BoxedUint { 55 | type Output = Self; 56 | 57 | fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { 58 | self.sub_mod(rhs, p) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | use super::BoxedUint; 65 | use hex_literal::hex; 66 | 67 | #[test] 68 | fn sub_mod_nist_p256() { 69 | let a = BoxedUint::from_be_slice( 70 | &hex!("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"), 71 | 256, 72 | ) 73 | .unwrap(); 74 | let b = BoxedUint::from_be_slice( 75 | &hex!("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"), 76 | 256, 77 | ) 78 | .unwrap(); 79 | let n = BoxedUint::from_be_slice( 80 | &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), 81 | 256, 82 | ) 83 | .unwrap(); 84 | 85 | let actual = a.sub_mod(&b, &n); 86 | let expected = BoxedUint::from_be_slice( 87 | &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), 88 | 256, 89 | ) 90 | .unwrap(); 91 | 92 | assert_eq!(expected, actual); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/uint/concat.rs: -------------------------------------------------------------------------------- 1 | use crate::{Concat, ConcatMixed, Limb, Uint}; 2 | 3 | impl Uint { 4 | /// Concatenate the two values, with `self` as least significant and `hi` as the most 5 | /// significant. 6 | pub const fn concat(&self, hi: &Self) -> Uint 7 | where 8 | Self: Concat>, 9 | { 10 | Uint::concat_mixed(self, hi) 11 | } 12 | 13 | /// Concatenate the two values, with `lo` as least significant and `hi` 14 | /// as the most significant. 15 | #[inline] 16 | pub const fn concat_mixed(lo: &Uint, hi: &Uint) -> Uint 17 | where 18 | Self: ConcatMixed, MixedOutput = Uint>, 19 | { 20 | let top = L + H; 21 | let top = if top < O { top } else { O }; 22 | let mut limbs = [Limb::ZERO; O]; 23 | let mut i = 0; 24 | 25 | while i < top { 26 | if i < L { 27 | limbs[i] = lo.limbs[i]; 28 | } else { 29 | limbs[i] = hi.limbs[i - L]; 30 | } 31 | i += 1; 32 | } 33 | 34 | Uint { limbs } 35 | } 36 | } 37 | 38 | impl Concat for T 39 | where 40 | T: ConcatMixed, 41 | { 42 | type Output = Self::MixedOutput; 43 | } 44 | 45 | #[cfg(test)] 46 | mod tests { 47 | use crate::{ConcatMixed, U64, U128, U192}; 48 | 49 | #[test] 50 | fn concat() { 51 | let hi = U64::from_u64(0x0011223344556677); 52 | let lo = U64::from_u64(0x8899aabbccddeeff); 53 | assert_eq!( 54 | lo.concat(&hi), 55 | U128::from_be_hex("00112233445566778899aabbccddeeff") 56 | ); 57 | } 58 | 59 | #[test] 60 | fn concat_mixed() { 61 | let hi = U64::from_u64(0x0011223344556677); 62 | let lo = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff); 63 | assert_eq!( 64 | lo.concat_mixed(&hi), 65 | U192::from_be_hex("00112233445566778899aabbccddeeff8899aabbccddeeff") 66 | ); 67 | assert_eq!( 68 | hi.concat_mixed(&lo), 69 | U192::from_be_hex("8899aabbccddeeff8899aabbccddeeff0011223344556677") 70 | ); 71 | } 72 | 73 | #[test] 74 | fn convert() { 75 | let res: U128 = U64::ONE.widening_mul(&U64::ONE).into(); 76 | assert_eq!(res, U128::ONE); 77 | 78 | let res: U128 = U64::ONE.square_wide().into(); 79 | assert_eq!(res, U128::ONE); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/uint/encoding/der.rs: -------------------------------------------------------------------------------- 1 | //! Support for decoding/encoding [`Uint`] as an ASN.1 DER `INTEGER`. 2 | 3 | use crate::{ArrayEncoding, Uint, hybrid_array::Array}; 4 | use ::der::{ 5 | DecodeValue, EncodeValue, FixedTag, Length, Tag, 6 | asn1::{AnyRef, UintRef}, 7 | }; 8 | 9 | impl<'a, const LIMBS: usize> TryFrom> for Uint 10 | where 11 | Uint: ArrayEncoding, 12 | { 13 | type Error = der::Error; 14 | 15 | fn try_from(any: AnyRef<'a>) -> der::Result> { 16 | UintRef::try_from(any)?.try_into() 17 | } 18 | } 19 | 20 | impl<'a, const LIMBS: usize> TryFrom> for Uint 21 | where 22 | Uint: ArrayEncoding, 23 | { 24 | type Error = der::Error; 25 | 26 | fn try_from(bytes: UintRef<'a>) -> der::Result> { 27 | let mut array = Array::default(); 28 | let offset = array.len().saturating_sub(bytes.len().try_into()?); 29 | array[offset..].copy_from_slice(bytes.as_bytes()); 30 | Ok(Uint::from_be_byte_array(array)) 31 | } 32 | } 33 | 34 | impl<'a, const LIMBS: usize> DecodeValue<'a> for Uint 35 | where 36 | Uint: ArrayEncoding, 37 | { 38 | type Error = der::Error; 39 | 40 | fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { 41 | UintRef::decode_value(reader, header)?.try_into() 42 | } 43 | } 44 | 45 | impl EncodeValue for Uint 46 | where 47 | Uint: ArrayEncoding, 48 | { 49 | fn value_len(&self) -> der::Result { 50 | // TODO(tarcieri): more efficient length calculation 51 | let array = self.to_be_byte_array(); 52 | UintRef::new(&array)?.value_len() 53 | } 54 | 55 | fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> { 56 | let array = self.to_be_byte_array(); 57 | UintRef::new(&array)?.encode_value(encoder) 58 | } 59 | } 60 | 61 | impl FixedTag for Uint 62 | where 63 | Uint: ArrayEncoding, 64 | { 65 | const TAG: Tag = Tag::Integer; 66 | } 67 | -------------------------------------------------------------------------------- /src/uint/encoding/rlp.rs: -------------------------------------------------------------------------------- 1 | //! Recursive Length Prefix (RLP) encoding support. 2 | 3 | use crate::{Encoding, Uint}; 4 | use rlp::{DecoderError, Rlp, RlpStream}; 5 | 6 | impl rlp::Encodable for Uint 7 | where 8 | Self: Encoding, 9 | { 10 | fn rlp_append(&self, stream: &mut RlpStream) { 11 | let bytes = self.to_be_bytes(); 12 | let mut bytes_stripped = bytes.as_ref(); 13 | 14 | while bytes_stripped.first().cloned() == Some(0) { 15 | bytes_stripped = &bytes_stripped[1..]; 16 | } 17 | 18 | stream.encoder().encode_value(bytes_stripped); 19 | } 20 | } 21 | 22 | impl rlp::Decodable for Uint 23 | where 24 | Self: Encoding, 25 | ::Repr: Default, 26 | { 27 | fn decode(rlp: &Rlp<'_>) -> Result { 28 | rlp.decoder().decode_value(|bytes| { 29 | if bytes.first().cloned() == Some(0) { 30 | Err(DecoderError::RlpInvalidIndirection) 31 | } else { 32 | let mut repr = ::Repr::default(); 33 | let offset = repr 34 | .as_ref() 35 | .len() 36 | .checked_sub(bytes.len()) 37 | .ok_or(DecoderError::RlpIsTooBig)?; 38 | 39 | repr.as_mut()[offset..].copy_from_slice(bytes); 40 | Ok(Self::from_be_bytes(repr)) 41 | } 42 | }) 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | #[allow(clippy::unwrap_used)] 48 | mod tests { 49 | use crate::U256; 50 | use hex_literal::hex; 51 | 52 | /// U256 test vectors from the `rlp` crate. 53 | /// 54 | /// 55 | const U256_VECTORS: &[(U256, &[u8])] = &[ 56 | (U256::ZERO, &hex!("80")), 57 | ( 58 | U256::from_be_hex("0000000000000000000000000000000000000000000000000000000001000000"), 59 | &hex!("8401000000"), 60 | ), 61 | ( 62 | U256::from_be_hex("00000000000000000000000000000000000000000000000000000000ffffffff"), 63 | &hex!("84ffffffff"), 64 | ), 65 | ( 66 | U256::from_be_hex("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), 67 | &hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), 68 | ), 69 | ]; 70 | 71 | #[test] 72 | fn round_trip() { 73 | for &(uint, expected_bytes) in U256_VECTORS { 74 | assert_eq!(rlp::encode(&uint), expected_bytes); 75 | assert_eq!(rlp::decode::(expected_bytes).unwrap(), uint); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/uint/extra_sizes.rs: -------------------------------------------------------------------------------- 1 | //! Support for additional integer sizes beyond the core set which is defined 2 | //! in the toplevel module. 3 | //! 4 | //! These are feature-gated to keep compile times down for applications which 5 | //! do not need them. 6 | // TODO(tarcieri): switch to a fully const generic implementation using `generic_const_exprs` 7 | 8 | use super::*; 9 | 10 | impl_uint_aliases! { 11 | (U1088, 1088, "1088-bit"), 12 | (U1152, 1152, "1152-bit"), 13 | (U1216, 1216, "1216-bit"), 14 | (U1344, 1344, "1344-bit"), 15 | (U1408, 1408, "1408-bit"), 16 | (U1472, 1472, "1472-bit"), 17 | (U1600, 1600, "1600-bit"), 18 | (U1664, 1664, "1664-bit"), 19 | (U1728, 1728, "1728-bit"), 20 | (U1856, 1856, "1856-bit"), 21 | (U1920, 1920, "1920-bit"), 22 | (U1984, 1984, "1984-bit"), 23 | (U2112, 2112, "2112-bit"), 24 | (U2176, 2176, "2176-bit"), 25 | (U2240, 2240, "2240-bit"), 26 | (U2304, 2304, "2304-bit"), 27 | (U2368, 2368, "2368-bit"), 28 | (U2432, 2432, "2432-bit"), 29 | (U2496, 2496, "2496-bit"), 30 | (U2560, 2560, "2560-bit"), 31 | (U2624, 2624, "2624-bit"), 32 | (U2688, 2688, "2688-bit"), 33 | (U2752, 2752, "2752-bit"), 34 | (U2816, 2816, "2816-bit"), 35 | (U2880, 2880, "2880-bit"), 36 | (U2944, 2944, "2944-bit"), 37 | (U3008, 3008, "3008-bit"), 38 | (U3136, 3136, "3136-bit"), 39 | (U3200, 3200, "3200-bit"), 40 | (U3264, 3264, "3264-bit"), 41 | (U3328, 3328, "3328-bit"), 42 | (U3392, 3392, "3392-bit"), 43 | (U3456, 3456, "3456-bit"), 44 | (U3520, 3520, "3520-bit"), 45 | (U3648, 3648, "3648-bit"), 46 | (U3712, 3712, "3712-bit"), 47 | (U3776, 3776, "3776-bit"), 48 | (U3840, 3840, "3840-bit"), 49 | (U3904, 3904, "3904-bit"), 50 | (U3968, 3968, "3968-bit"), 51 | (U4032, 4032, "4032-bit"), 52 | (U4160, 4160, "4160-bit"), 53 | (U4288, 4288, "4288-bit"), 54 | (U4416, 4416, "4416-bit"), 55 | (U4480, 4480, "4480-bit"), 56 | (U4544, 4544, "4544-bit"), 57 | (U4608, 4608, "4608-bit"), 58 | (U4672, 4672, "4672-bit"), 59 | (U4736, 4736, "4736-bit"), 60 | (U4800, 4800, "4800-bit"), 61 | (U4864, 4864, "4864-bit"), 62 | (U4928, 4928, "4928-bit"), 63 | (U4992, 4992, "4992-bit"), 64 | (U5056, 5056, "5056-bit"), 65 | (U5120, 5120, "5120-bit"), 66 | (U5184, 5184, "5184-bit"), 67 | (U5248, 5248, "5248-bit"), 68 | (U5312, 5312, "5312-bit"), 69 | (U5376, 5376, "5376-bit"), 70 | (U5440, 5440, "5440-bit"), 71 | (U5504, 5504, "5504-bit"), 72 | (U5568, 5568, "5568-bit"), 73 | (U5632, 5632, "5632-bit"), 74 | (U5696, 5696, "5696-bit"), 75 | (U5760, 5760, "5760-bit"), 76 | (U5824, 5824, "5824-bit"), 77 | (U5888, 5888, "5888-bit"), 78 | (U5952, 5952, "5952-bit"), 79 | (U6016, 6016, "6016-bit"), 80 | (U6080, 6080, "6080-bit"), 81 | (U6208, 6208, "6208-bit"), 82 | (U6272, 6272, "6272-bit"), 83 | (U6336, 6336, "6336-bit"), 84 | (U6400, 6400, "6400-bit"), 85 | (U6464, 6464, "6464-bit"), 86 | (U6528, 6528, "6528-bit"), 87 | (U6592, 6592, "6592-bit"), 88 | (U6656, 6656, "6656-bit"), 89 | (U6720, 6720, "6720-bit"), 90 | (U6784, 6784, "6784-bit"), 91 | (U6848, 6848, "6848-bit"), 92 | (U6912, 6912, "6912-bit"), 93 | (U6976, 6976, "6976-bit"), 94 | (U7040, 7040, "7040-bit"), 95 | (U7104, 7104, "7104-bit"), 96 | (U7168, 7168, "7168-bit"), 97 | (U7232, 7232, "7232-bit"), 98 | (U7296, 7296, "7296-bit"), 99 | (U7360, 7360, "7360-bit"), 100 | (U7424, 7424, "7424-bit"), 101 | (U7488, 7488, "7488-bit"), 102 | (U7552, 7552, "7552-bit"), 103 | (U7616, 7616, "7616-bit"), 104 | (U7680, 7680, "7680-bit"), 105 | (U7744, 7744, "7744-bit"), 106 | (U7808, 7808, "7808-bit"), 107 | (U7872, 7872, "7872-bit"), 108 | (U7936, 7936, "7936-bit"), 109 | (U8000, 8000, "8000-bit"), 110 | (U8064, 8064, "8064-bit"), 111 | (U8128, 8128, "8128-bit") 112 | } 113 | 114 | impl_uint_concat_split_even! { 115 | U1152, 116 | U1408, 117 | U1664, 118 | U1920, 119 | U2176, 120 | U2304, 121 | U2432, 122 | U2560, 123 | U2688, 124 | U2816, 125 | U2944, 126 | U3200, 127 | U3328, 128 | U3456, 129 | U3712, 130 | U3840, 131 | U3968, 132 | U4480, 133 | U4608, 134 | U4736, 135 | U4864, 136 | U4992, 137 | U5120, 138 | U5248, 139 | U5376, 140 | U5504, 141 | U5632, 142 | U5760, 143 | U5888, 144 | U6016, 145 | U6272, 146 | U6400, 147 | U6528, 148 | U6656, 149 | U6784, 150 | U6912, 151 | U7040, 152 | U7168, 153 | U7296, 154 | U7424, 155 | U7552, 156 | U7680, 157 | U7808, 158 | U7936, 159 | U8064, 160 | } 161 | -------------------------------------------------------------------------------- /src/uint/neg.rs: -------------------------------------------------------------------------------- 1 | use crate::{ConstChoice, Limb, Uint, WideWord, Word, WrappingNeg}; 2 | 3 | impl Uint { 4 | /// Perform wrapping negation. 5 | pub const fn wrapping_neg(&self) -> Self { 6 | self.carrying_neg().0 7 | } 8 | 9 | /// Perform negation: map `self` to `(self ^ 1111...1111) + 0000...0001`. 10 | /// Additionally return whether the carry flag is set on the addition. 11 | /// 12 | /// Note: the carry is set if and only if `self == Self::ZERO`. 13 | pub const fn carrying_neg(&self) -> (Self, ConstChoice) { 14 | let mut ret = [Limb::ZERO; LIMBS]; 15 | let mut carry = 1; 16 | let mut i = 0; 17 | while i < LIMBS { 18 | let r = (!self.limbs[i].0 as WideWord) + carry; 19 | ret[i] = Limb(r as Word); 20 | carry = r >> Limb::BITS; 21 | i += 1; 22 | } 23 | (Uint::new(ret), ConstChoice::from_word_lsb(carry as Word)) 24 | } 25 | 26 | /// Perform wrapping negation, if `negate` is truthy. Otherwise, return `self`. 27 | pub const fn wrapping_neg_if(&self, negate: ConstChoice) -> Self { 28 | Uint::select(self, &self.wrapping_neg(), negate) 29 | } 30 | } 31 | 32 | impl WrappingNeg for Uint { 33 | #[inline] 34 | fn wrapping_neg(&self) -> Self { 35 | self.wrapping_neg() 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use crate::{ConstChoice, U256}; 42 | 43 | #[test] 44 | fn wrapping_neg() { 45 | assert_eq!(U256::ZERO.wrapping_neg(), U256::ZERO); 46 | assert_eq!(U256::MAX.wrapping_neg(), U256::ONE); 47 | assert_eq!( 48 | U256::from_u64(13).wrapping_neg(), 49 | U256::from_u64(13).not().saturating_add(&U256::ONE) 50 | ); 51 | assert_eq!( 52 | U256::from_u64(42).wrapping_neg(), 53 | U256::from_u64(42).saturating_sub(&U256::ONE).not() 54 | ); 55 | } 56 | 57 | #[test] 58 | fn carrying_neg() { 59 | assert_eq!(U256::ZERO.carrying_neg(), (U256::ZERO, ConstChoice::TRUE)); 60 | assert_eq!(U256::ONE.carrying_neg(), (U256::MAX, ConstChoice::FALSE)); 61 | assert_eq!(U256::MAX.carrying_neg(), (U256::ONE, ConstChoice::FALSE)); 62 | } 63 | 64 | #[test] 65 | fn wrapping_neg_if() { 66 | let negate = ConstChoice::TRUE; 67 | assert_eq!(U256::ZERO.wrapping_neg_if(negate), U256::ZERO); 68 | assert_eq!(U256::ONE.wrapping_neg_if(negate), U256::MAX); 69 | assert_eq!(U256::MAX.wrapping_neg_if(negate), U256::ONE); 70 | 71 | let do_not_negate = ConstChoice::FALSE; 72 | assert_eq!(U256::ZERO.wrapping_neg_if(do_not_negate), U256::ZERO); 73 | assert_eq!(U256::ONE.wrapping_neg_if(do_not_negate), U256::ONE); 74 | assert_eq!(U256::MAX.wrapping_neg_if(do_not_negate), U256::MAX); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/uint/neg_mod.rs: -------------------------------------------------------------------------------- 1 | //! [`Uint`] modular negation operations. 2 | 3 | use crate::{Limb, NegMod, Uint}; 4 | 5 | impl Uint { 6 | /// Computes `-a mod p`. 7 | /// Assumes `self` is in `[0, p)`. 8 | pub const fn neg_mod(&self, p: &Self) -> Self { 9 | let z = self.is_nonzero(); 10 | let mut ret = p.borrowing_sub(self, Limb::ZERO).0; 11 | let mut i = 0; 12 | while i < LIMBS { 13 | // Set ret to 0 if the original value was 0, in which 14 | // case ret would be p. 15 | ret.limbs[i].0 = z.if_true_word(ret.limbs[i].0); 16 | i += 1; 17 | } 18 | ret 19 | } 20 | 21 | /// Computes `-a mod p` for the special modulus 22 | /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. 23 | pub const fn neg_mod_special(&self, c: Limb) -> Self { 24 | Self::ZERO.sub_mod_special(self, c) 25 | } 26 | } 27 | 28 | impl NegMod for Uint { 29 | type Output = Self; 30 | 31 | fn neg_mod(&self, p: &Self) -> Self { 32 | debug_assert!(self < p); 33 | self.neg_mod(p) 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use crate::U256; 40 | 41 | #[test] 42 | fn neg_mod_random() { 43 | let x = 44 | U256::from_be_hex("8d16e171674b4e6d8529edba4593802bf30b8cb161dd30aa8e550d41380007c2"); 45 | let p = 46 | U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); 47 | 48 | let actual = x.neg_mod(&p); 49 | let expected = 50 | U256::from_be_hex("056c53337d72b9d666f86c9256ce5f08cabc1b63b207864ce0d6ecf010e2d9f3"); 51 | 52 | assert_eq!(expected, actual); 53 | } 54 | 55 | #[test] 56 | fn neg_mod_zero() { 57 | let x = 58 | U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); 59 | let p = 60 | U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); 61 | 62 | let actual = x.neg_mod(&p); 63 | let expected = 64 | U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); 65 | 66 | assert_eq!(expected, actual); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/uint/resize.rs: -------------------------------------------------------------------------------- 1 | use super::Uint; 2 | 3 | impl Uint { 4 | /// Construct a `Uint` from the unsigned integer value, 5 | /// truncating the upper bits if the value is too large to be 6 | /// represented. 7 | #[inline(always)] 8 | pub const fn resize(&self) -> Uint { 9 | let mut res = Uint::ZERO; 10 | let mut i = 0; 11 | let dim = if T < LIMBS { T } else { LIMBS }; 12 | while i < dim { 13 | res.limbs[i] = self.limbs[i]; 14 | i += 1; 15 | } 16 | res 17 | } 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use crate::{U64, U128}; 23 | 24 | #[test] 25 | fn resize_larger() { 26 | let u = U64::from_be_hex("AAAAAAAABBBBBBBB"); 27 | let u2: U128 = u.resize(); 28 | assert_eq!(u2, U128::from_be_hex("0000000000000000AAAAAAAABBBBBBBB")); 29 | } 30 | 31 | #[test] 32 | fn resize_smaller() { 33 | let u = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"); 34 | let u2: U64 = u.resize(); 35 | assert_eq!(u2, U64::from_be_hex("CCCCCCCCDDDDDDDD")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/uint/split.rs: -------------------------------------------------------------------------------- 1 | use crate::{Limb, Split, SplitMixed, Uint}; 2 | 3 | impl Uint { 4 | /// Split this number in half into low and high components. 5 | pub const fn split(&self) -> (Uint, Uint) 6 | where 7 | Self: Split>, 8 | { 9 | self.split_mixed() 10 | } 11 | 12 | /// Split this number into low and high components respectively. 13 | #[inline] 14 | pub const fn split_mixed(&self) -> (Uint, Uint) 15 | where 16 | Self: SplitMixed, Uint>, 17 | { 18 | let top = L + H; 19 | let top = if top < I { top } else { I }; 20 | let mut lo = [Limb::ZERO; L]; 21 | let mut hi = [Limb::ZERO; H]; 22 | let mut i = 0; 23 | 24 | while i < top { 25 | if i < L { 26 | lo[i] = self.limbs[i]; 27 | } else { 28 | hi[i - L] = self.limbs[i]; 29 | } 30 | i += 1; 31 | } 32 | 33 | (Uint { limbs: lo }, Uint { limbs: hi }) 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use crate::{U64, U128}; 40 | 41 | #[test] 42 | fn split() { 43 | let (lo, hi) = U128::from_be_hex("00112233445566778899aabbccddeeff").split(); 44 | assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff)); 45 | assert_eq!(hi, U64::from_u64(0x0011223344556677)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/boxed_monty_form.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc a2dbf0ee6304db81982e37ad9d9145a0f9de45730b9c41221dbf9fdfb9a246c5 # shrinks to a = BoxedUint(0x0000000000000002), b = BoxedUint(0x0000000000000100), n = BoxedMontyParams { modulus: BoxedUint(0x0000000000000003), one: BoxedUint(0x0000000000000001), r2: BoxedUint(0x0000000000000001), r3: BoxedUint(0x0000000000000001), mod_neg_inv: Limb(0x5555555555555555) } 8 | cc 00f163e6056fad81f0a00e33ff628c3948b7e2f5f2f806d201de874468ec8c57 # shrinks to (a, b) = (BoxedMontyForm { montgomery_form: BoxedUint(0x5A7D315F0CCBDB393E483EE367A05463992BFA5D0EFACB3D2B0FFC152B75B940), params: BoxedMontyParams { modulus: BoxedUint(0xBF645819DA525D921D2D072521783F02155C5BD7158CE3EB49BE89BE58CF3957), one: BoxedUint(0x409BA7E625ADA26DE2D2F8DADE87C0FDEAA3A428EA731C14B6417641A730C6A9), r2: BoxedUint(0x17629F64058CC036FAFFAF9D2EB492A2D85A7DC55FD575A92058DB0582647317), r3: BoxedUint(0x3BF020F12134E941004697534F9D9AA4DD43E7B38509F06A7D3EF62AC227F2B6), mod_neg_inv: Limb(0xD7237775D94B3D99) } }, BoxedMontyForm { montgomery_form: BoxedUint(0x7FFC7CA9B2EFA758EB87DCB0512F5D060503033E8D7D8F8E4478F0B046C9AC94), params: BoxedMontyParams { modulus: BoxedUint(0xBF645819DA525D921D2D072521783F02155C5BD7158CE3EB49BE89BE58CF3957), one: BoxedUint(0x409BA7E625ADA26DE2D2F8DADE87C0FDEAA3A428EA731C14B6417641A730C6A9), r2: BoxedUint(0x17629F64058CC036FAFFAF9D2EB492A2D85A7DC55FD575A92058DB0582647317), r3: BoxedUint(0x3BF020F12134E941004697534F9D9AA4DD43E7B38509F06A7D3EF62AC227F2B6), mod_neg_inv: Limb(0xD7237775D94B3D99) } }) 9 | cc 234544db24f3fa99fbd88776d9d9b03194478068e70719788deb9087d7d955c9 # shrinks to a = BoxedUint(0xAAF6458F8A12304356B649B991D597FC6C455A4B3D3916D7EFDD3087D7127E62666A2FEB411E4F11), b = BoxedUint(0xD092E81F038C1F6E475513DED53DC7CE77ADF51BF3DCC0A7A2C00D0701EDFF368924BF9AC5C52882), n = BoxedMontyParams { modulus: BoxedUint(0x77980BCC1B3AC570148BD14A1EFCCE2A7F866BA64AEE9B92D4FB9C54CB0D990BA9A68664194AA4E9A39CC068AB2EBE87), one: BoxedUint(0x10CFE867C98A751FD6E85D6BC20663AB00F328B36A22C8DA5608C75669E4CDE8ACB2F337CD6AB62CB8C67F2EA9A282F2), r2: BoxedUint(0x6F241F6AFDA802307573B0865EA774EF46CA757D710607B0CC9920AEB106B125A3C5E2742A89CF254D44ABFC66319B45), r3: BoxedUint(0x62D52BBD9502DEEC47467ABDA7C6CF2AA05D58866B78CA2EA948224155046964E3B43F8F8CD01A9A362B66EE34A4D759), mod_neg_inv: Limb(0x9AABE2A2584258C9) } 10 | cc dc095c7c1bbd3ee44794fc7c63db020524efe535a5d8351e3041f6befb05e10b # shrinks to x = BoxedUint(0x0000000000000000), n = BoxedMontyParams { modulus: Odd(BoxedUint(0x0000000000000001)), one: BoxedUint(0x0000000000000001), r2: BoxedUint(0x0000000000000000), r3: BoxedUint(0x0000000000000000), mod_neg_inv: Limb(0xFFFFFFFFFFFFFFFF) } 11 | -------------------------------------------------------------------------------- /tests/boxed_uint.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc eff3d2b6f2f8b4ac0aeb21f361584d6d8d5621d8ffe5d3b72778eaf911666dc0 # shrinks to (mut a, mut b) = (BoxedUint(0x0000000000000000), BoxedUint(0x0000000000000000)) 8 | cc 5f610ffddb9fdeefb931f0a61a66aa07eb9440ae614862ef17901740758f318b # shrinks to (mut a, mut b) = (BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000), BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086)) 9 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | //! Common functionality shared between tests. 2 | 3 | // Different tests may use only a subset of the available functionality 4 | #![allow(dead_code)] 5 | 6 | use crypto_bigint::{Encoding, Limb}; 7 | use num_bigint::BigUint; 8 | 9 | /// `Uint` to `num_bigint::BigUint` 10 | pub fn to_biguint(uint: &T) -> BigUint 11 | where 12 | T: AsRef<[Limb]>, 13 | { 14 | let mut bytes = Vec::with_capacity(uint.as_ref().len() * Limb::BYTES); 15 | 16 | for limb in uint.as_ref() { 17 | bytes.extend_from_slice(&limb.to_le_bytes()); 18 | } 19 | 20 | BigUint::from_bytes_le(&bytes) 21 | } 22 | -------------------------------------------------------------------------------- /tests/const_monty_form.rs: -------------------------------------------------------------------------------- 1 | //! Equivalence tests between `crypto_bigint::ConstMontyForm` and `num-bigint`. 2 | 3 | mod common; 4 | 5 | use common::to_biguint; 6 | use crypto_bigint::{U256, impl_modulus, modular::ConstMontyParams}; 7 | use num_bigint::BigUint; 8 | use num_modular::ModularUnaryOps; 9 | use proptest::prelude::*; 10 | 11 | impl_modulus!( 12 | Modulus, 13 | U256, 14 | "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" 15 | ); 16 | 17 | type ConstMontyForm = crypto_bigint::modular::ConstMontyForm; 18 | 19 | fn retrieve_biguint(monty_form: &ConstMontyForm) -> BigUint { 20 | to_biguint(&monty_form.retrieve()) 21 | } 22 | 23 | fn reduce(n: &U256) -> ConstMontyForm { 24 | ConstMontyForm::new(n) 25 | } 26 | 27 | prop_compose! { 28 | fn uint()(bytes in any::<[u8; 32]>()) -> U256 { 29 | U256::from_le_slice(&bytes) 30 | } 31 | } 32 | 33 | proptest! { 34 | #[test] 35 | fn invert(x in uint()) { 36 | let x = reduce(&x); 37 | let actual = Option::::from(x.invert()); 38 | 39 | let x_bi = retrieve_biguint(&x); 40 | let n_bi = to_biguint(&Modulus::MODULUS); 41 | let expected = x_bi.invm(&n_bi); 42 | 43 | match (expected, actual) { 44 | (Some(exp), Some(act)) => { 45 | let res = x * act; 46 | prop_assert_eq!(res.retrieve(), U256::ONE); 47 | prop_assert_eq!(exp, retrieve_biguint(&act)); 48 | } 49 | (None, None) => (), 50 | (_, _) => panic!("disagreement on if modular inverse exists") 51 | } 52 | } 53 | 54 | #[test] 55 | fn precomputed_invert(x in uint()) { 56 | let x = reduce(&x); 57 | let inverter = Modulus::precompute_inverter(); 58 | let actual = Option::::from(inverter.invert(&x)); 59 | 60 | let x_bi = retrieve_biguint(&x); 61 | let n_bi = to_biguint(&Modulus::MODULUS); 62 | let expected = x_bi.invm(&n_bi); 63 | 64 | match (expected, actual) { 65 | (Some(exp), Some(act)) => { 66 | let res = x * act; 67 | prop_assert_eq!(res.retrieve(), U256::ONE); 68 | prop_assert_eq!(exp, retrieve_biguint(&act)); 69 | } 70 | (None, None) => (), 71 | (_, _) => panic!("disagreement on if modular inverse exists") 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/impl_modulus.rs: -------------------------------------------------------------------------------- 1 | //! Test to ensure that `impl_modulus!` works from outside this crate. 2 | 3 | use crypto_bigint::{U64, impl_modulus}; 4 | 5 | impl_modulus!(TestMod, U64, "30e4b8f030ab42f3"); 6 | -------------------------------------------------------------------------------- /tests/monty_form.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 19eef79040418fc32c4437caa30b98e5676e64e06ddf9afbd3eac59fb144577a # shrinks to n = MontyParams { modulus: Odd(Uint(0x0100000000000000000000000000000000000000000000000000000000000001)), one: Uint(0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01), r2: Uint(0x0000000000000000000000000000000000000000000000000000000000010000), r3: Uint(0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000001), mod_neg_inv: Limb(0xFFFFFFFFFFFFFFFF) } 8 | -------------------------------------------------------------------------------- /tests/safegcd.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 070600f4b9e9a406b4ee112524b52a66822ecae8c9ac74779c2018b4410f34c3 # shrinks to x = Uint(0x0100000000000000000000000000000000000000000000000000000000000000) 8 | cc 0e694a5ca0ec8093d16246b89356f72a440454eddeb5ec7197c98440124ce3f6 # shrinks to x = BoxedUint(0x00000000CBF9350842F498CE441FC2DC23C7BF47D3DE91C327B2157C5E4EED77) 9 | -------------------------------------------------------------------------------- /tests/safegcd.rs: -------------------------------------------------------------------------------- 1 | //! Equivalence tests for Bernstein-Yang inversions. 2 | 3 | mod common; 4 | 5 | use common::to_biguint; 6 | use crypto_bigint::{Odd, PrecomputeInverter, U256}; 7 | use num_bigint::BigUint; 8 | use num_integer::Integer; 9 | use num_traits::One; 10 | use proptest::prelude::*; 11 | 12 | #[cfg(feature = "alloc")] 13 | use crypto_bigint::{BoxedUint, Inverter, Resize}; 14 | 15 | /// Example prime number (NIST P-256 curve order) 16 | const P: Odd = 17 | Odd::::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); 18 | 19 | prop_compose! { 20 | fn uint()(bytes in any::<[u8; 32]>()) -> U256 { 21 | U256::from_le_slice(&bytes) 22 | } 23 | } 24 | 25 | #[cfg(feature = "alloc")] 26 | prop_compose! { 27 | fn boxed_uint()(byte_vec in any::>()) -> BoxedUint { 28 | let mut bytes = byte_vec.as_slice(); 29 | 30 | if bytes.len() > 32 { 31 | bytes = &bytes[..32]; 32 | } 33 | 34 | BoxedUint::from_le_slice(bytes, 256).unwrap() 35 | } 36 | } 37 | 38 | proptest! { 39 | #[test] 40 | fn invert_mod(x in uint()) { 41 | let x_bi = to_biguint(&x); 42 | let p_bi = to_biguint(&P); 43 | 44 | let expected_is_some = x_bi.gcd(&p_bi) == BigUint::one(); 45 | let inverter = P.precompute_inverter(); 46 | let actual = inverter.invert(&x); 47 | 48 | prop_assert_eq!(expected_is_some, bool::from(actual.is_some())); 49 | 50 | if let Some(actual) = Option::::from(actual) { 51 | let inv_bi = to_biguint(&actual); 52 | let res = (inv_bi * x_bi) % p_bi; 53 | prop_assert_eq!(res, BigUint::one()); 54 | 55 | // check vartime implementation equivalence 56 | let actual_vartime = inverter.invert_vartime(&x).unwrap(); 57 | prop_assert_eq!(actual, actual_vartime); 58 | } 59 | } 60 | 61 | #[cfg(feature = "alloc")] 62 | #[test] 63 | fn boxed_invert_mod(x in boxed_uint()) { 64 | let p = Odd::::from(&P); 65 | let x = x.rem_vartime(p.as_nz_ref()).resize(p.bits_precision()); 66 | 67 | let x_bi = to_biguint(&x); 68 | let p_bi = to_biguint(&P); 69 | 70 | let expected_is_some = x_bi.gcd(&p_bi) == BigUint::one(); 71 | let inverter = p.precompute_inverter(); 72 | let actual = inverter.invert(&x); 73 | 74 | prop_assert_eq!(expected_is_some, bool::from(actual.is_some())); 75 | 76 | if let Some(actual) = Option::::from(actual) { 77 | let inv_bi = to_biguint(&actual); 78 | let res = (inv_bi * x_bi) % p_bi; 79 | prop_assert_eq!(res, BigUint::one()); 80 | 81 | // check vartime implementation equivalence 82 | let actual_vartime = inverter.invert_vartime(&x).unwrap(); 83 | prop_assert_eq!(actual, actual_vartime); 84 | } 85 | } 86 | } 87 | --------------------------------------------------------------------------------