├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── RELEASES.md ├── benchmark_crate ├── Cargo.toml ├── benches │ ├── bench_main.rs │ ├── benchmarks │ │ ├── bigint.rs │ │ ├── egcd.rs │ │ ├── factorial.rs │ │ ├── gcd.rs │ │ ├── mod.rs │ │ ├── prime_benches.rs │ │ └── roots.rs │ └── shootout-pidigits.rs └── src │ └── lib.rs ├── build.rs ├── ci ├── rustup.sh └── test_full.sh ├── src ├── algorithms │ ├── add.rs │ ├── bits.rs │ ├── cmp.rs │ ├── div.rs │ ├── gcd.rs │ ├── jacobi.rs │ ├── mac.rs │ ├── mod.rs │ ├── mod_inverse.rs │ ├── mul.rs │ ├── shl.rs │ ├── shr.rs │ └── sub.rs ├── bigint.rs ├── bigrand.rs ├── biguint.rs ├── lib.rs ├── macro.rs ├── macros.rs ├── monty.rs ├── prime.rs └── traits.rs └── tests ├── bigint.rs ├── bigint_bitwise.rs ├── bigint_scalar.rs ├── biguint.rs ├── biguint_scalar.rs ├── consts └── mod.rs ├── macros └── mod.rs ├── modpow.rs ├── rand.rs ├── roots.rs ├── serde.rs └── torture.rs /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | *.bk 4 | *.orig 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.56.0 4 | - stable 5 | - beta 6 | - nightly 7 | sudo: false 8 | script: 9 | - cargo build --verbose 10 | - ./ci/test_full.sh 11 | notifications: 12 | email: 13 | on_success: never 14 | branches: 15 | only: 16 | - master 17 | - next 18 | - staging 19 | - trying 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 3 | "dignifiedquire ", 4 | "The Rust Project Developers" 5 | ] 6 | description = "Big integer implementation for Rust" 7 | documentation = "https://docs.rs/num-bigint-dig" 8 | homepage = "https://github.com/dignifiedquire/num-bigint" 9 | keywords = ["mathematics", "numerics", "bignum"] 10 | categories = ["algorithms", "data-structures", "science"] 11 | license = "MIT/Apache-2.0" 12 | name = "num-bigint-dig" 13 | repository = "https://github.com/dignifiedquire/num-bigint" 14 | version = "0.8.4" 15 | edition = "2021" 16 | rust-version = "1.56" 17 | readme = "README.md" 18 | build = "build.rs" 19 | autobenches = false 20 | 21 | [package.metadata.docs.rs] 22 | features = ["std", "serde", "rand", "prime"] 23 | 24 | [dependencies.arbitrary] 25 | version = "1.1.0" 26 | optional = true 27 | 28 | [dependencies.smallvec] 29 | version = "1.10.0" 30 | default-features = false 31 | 32 | [dependencies.num-integer] 33 | version = "0.1.39" 34 | default-features = false 35 | features = [ "i128" ] 36 | 37 | [dependencies.num-traits] 38 | version = "0.2.4" 39 | default-features = false 40 | features = [ "i128" ] 41 | 42 | [dependencies.num-iter] 43 | version = "0.1.37" 44 | default-features = false 45 | 46 | [dependencies.rand] 47 | optional = true 48 | version = "0.8.3" 49 | default-features = false 50 | 51 | [dependencies.zeroize] 52 | version = "1.5" 53 | default-features = false 54 | optional = true 55 | 56 | [dependencies.serde] 57 | optional = true 58 | version = "1.0" 59 | default-features = false 60 | features = [ "alloc" ] 61 | 62 | [dependencies.libm] 63 | version = "0.2.1" 64 | 65 | [dependencies.lazy_static] 66 | version = "1.2.0" 67 | default-features = false 68 | # no_std feature is an anti-pattern. Why, lazy_static, why? 69 | # See https://github.com/rust-lang-nursery/lazy-static.rs/issues/150 70 | features = ["spin_no_std"] 71 | 72 | [dev-dependencies] 73 | rand_chacha = "0.3" 74 | rand_xorshift = "0.3" 75 | rand_isaac = "0.3" 76 | rand = { version = "0.8", features = ["small_rng"] } 77 | 78 | [dev-dependencies.serde_test] 79 | version = "1.0" 80 | 81 | [features] 82 | default = ["std", "u64_digit"] 83 | fuzz = ["arbitrary", "smallvec/arbitrary"] 84 | i128 = [] 85 | std = [ 86 | "num-integer/std", 87 | "num-traits/std", 88 | "smallvec/write", 89 | "rand/std", 90 | "serde/std" 91 | ] 92 | u64_digit = [] 93 | prime = ["rand/std_rng"] 94 | nightly = [] 95 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Rust 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 | # num-bigint-dig 2 | 3 | [![crate](https://img.shields.io/crates/v/num-bigint-dig.svg)](https://crates.io/crates/num-bigint-dig) 4 | [![documentation](https://docs.rs/num-bigint-dig/badge.svg)](https://docs.rs/num-bigint-dig) 5 | ![minimum rustc 1.56](https://img.shields.io/badge/rustc-1.56+-red.svg) 6 | [![Travis status](https://travis-ci.org/dignifiedquire/num-bigint.svg?branch=master)](https://travis-ci.org/dignifiedquire/num-bigint) 7 | 8 | Big integer types for Rust, `BigInt` and `BigUint`. 9 | 10 | > **Warning** This is a fork of [`rust-num/num-bigint`](https://github.com/rust-num/num-bigint) with a focus on providing functionality, needed to implement cryptographic operations. 11 | 12 | 13 | ## Usage 14 | 15 | Add this to your `Cargo.toml`: 16 | 17 | ```toml 18 | [dependencies] 19 | num-bigint-dig = "^0.7" 20 | ``` 21 | 22 | and this to your crate root: 23 | 24 | ```rust 25 | extern crate num_bigint_dig as num_bigint; 26 | ``` 27 | 28 | ## Features 29 | 30 | The `std` feature is enabled by default and mandatory to compile on older rust 31 | version. 32 | 33 | It is possible to use this crate on no_std target. If 34 | you wish to compile for a target that does not have an `std` crate, you should 35 | use `num-bigint` with `default-features = false`. All other sub-features should 36 | be compatible with no_std. Note that in this mode, `num-bigint` still relies on 37 | the alloc crate, so make sure you define a `global_allocator`. 38 | 39 | Implementations for `i128` and `u128` are only available with Rust 1.26 and 40 | later. The build script automatically detects this, but you can make it 41 | mandatory by enabling the `i128` crate feature. 42 | 43 | The `u64_digit` feature enables usage of larger internal "digits" (or otherwise known as "limbs"). Speeeding up almost all operations on architectures that have native support for it. 44 | 45 | The `prime` feature gate enables algorithms and support for dealing with large primes. 46 | 47 | ## Releases 48 | 49 | Release notes are available in [RELEASES.md](RELEASES.md). 50 | 51 | ## Compatibility 52 | 53 | The `num-bigint` crate is tested for rustc 1.56 and greater. 54 | 55 | ## Alternatives 56 | 57 | While `num-bigint` strives for good performance in pure Rust code, other 58 | crates may offer better performance with different trade-offs. The following 59 | table offers a brief comparison to a few alternatives. 60 | 61 | | Crate | License | Min rustc | Implementation | 62 | | :------------------- | :------------- |:----------| :------------- | 63 | | **`num-bigint-dig`** | MIT/Apache-2.0 | 1.56 | pure rust | 64 | | [`num-bigint`] | MIT/Apache-2.0 | 1.15 | pure rust | 65 | | [`ramp`] | Apache-2.0 | nightly | rust and inline assembly | 66 | | [`rug`] | LGPL-3.0+ | 1.18 | bundles [GMP] via [`gmp-mpfr-sys`] | 67 | | [`rust-gmp`] | MIT | stable? | links to [GMP] | 68 | | [`apint`] | MIT/Apache-2.0 | 1.26 | pure rust (unfinished) | 69 | 70 | [`num-bigint`]: https://crates.io/crates/num-bigint 71 | [GMP]: https://gmplib.org/ 72 | [`gmp-mpfr-sys`]: https://crates.io/crates/gmp-mpfr-sys 73 | [`rug`]: https://crates.io/crates/rug 74 | [`rust-gmp`]: https://crates.io/crates/rust-gmp 75 | [`ramp`]: https://crates.io/crates/ramp 76 | [`apint`]: https://crates.io/crates/apint 77 | 78 | ## Benchmarks 79 | 80 | ``` 81 | cargo bench --features prime 82 | ``` 83 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Release 0.2.2 (2018-12-14) 2 | 3 | - [The `Roots` implementations now use better initial guesses][71]. 4 | - [Fixed `to_signed_bytes_*` for some positive numbers][72], where the 5 | most-significant byte is `0x80` and the rest are `0`. 6 | 7 | [71]: https://github.com/rust-num/num-bigint/pull/71 8 | [72]: https://github.com/rust-num/num-bigint/pull/72 9 | 10 | **Contributors**: @cuviper, @leodasvacas 11 | 12 | # Release 0.2.1 (2018-11-02) 13 | 14 | - [`RandBigInt` now uses `Rng::fill_bytes`][53] to improve performance, instead 15 | of repeated `gen::` calls. The also affects the implementations of the 16 | other `rand` traits. This may potentially change the values produced by some 17 | seeded RNGs on previous versions, but the values were tested to be stable 18 | with `ChaChaRng`, `IsaacRng`, and `XorShiftRng`. 19 | - [`BigInt` and `BigUint` now implement `num_integer::Roots`][56]. 20 | - [`BigInt` and `BigUint` now implement `num_traits::Pow`][54]. 21 | - [`BigInt` and `BigUint` now implement operators with 128-bit integers][64]. 22 | 23 | **Contributors**: @cuviper, @dignifiedquire, @mancabizjak, @Robbepop, 24 | @TheIronBorn, @thomwiggers 25 | 26 | [53]: https://github.com/rust-num/num-bigint/pull/53 27 | [54]: https://github.com/rust-num/num-bigint/pull/54 28 | [56]: https://github.com/rust-num/num-bigint/pull/56 29 | [64]: https://github.com/rust-num/num-bigint/pull/64 30 | 31 | # Release 0.2.0 (2018-05-25) 32 | 33 | ### Enhancements 34 | 35 | - [`BigInt` and `BigUint` now implement `Product` and `Sum`][22] for iterators 36 | of any item that we can `Mul` and `Add`, respectively. For example, a 37 | factorial can now be simply: `let f: BigUint = (1u32..1000).product();` 38 | - [`BigInt` now supports two's-complement logic operations][26], namely 39 | `BitAnd`, `BitOr`, `BitXor`, and `Not`. These act conceptually as if each 40 | number had an infinite prefix of `0` or `1` bits for positive or negative. 41 | - [`BigInt` now supports assignment operators][41] like `AddAssign`. 42 | - [`BigInt` and `BigUint` now support conversions with `i128` and `u128`][44], 43 | if sufficient compiler support is detected. 44 | - [`BigInt` and `BigUint` now implement rand's `SampleUniform` trait][48], and 45 | [a custom `RandomBits` distribution samples by bit size][49]. 46 | - The release also includes other miscellaneous improvements to performance. 47 | 48 | ### Breaking Changes 49 | 50 | - [`num-bigint` now requires rustc 1.15 or greater][23]. 51 | - [The crate now has a `std` feature, and won't build without it][46]. This is 52 | in preparation for someday supporting `#![no_std]` with `alloc`. 53 | - [The `serde` dependency has been updated to 1.0][24], still disabled by 54 | default. The `rustc-serialize` crate is no longer supported by `num-bigint`. 55 | - [The `rand` dependency has been updated to 0.5][48], now disabled by default. 56 | This requires rustc 1.22 or greater for `rand`'s own requirement. 57 | - [`Shr for BigInt` now rounds down][8] rather than toward zero, matching the 58 | behavior of the primitive integers for negative values. 59 | - [`ParseBigIntError` is now an opaque type][37]. 60 | - [The `big_digit` module is no longer public][38], nor are the `BigDigit` and 61 | `DoubleBigDigit` types and `ZERO_BIG_DIGIT` constant that were re-exported in 62 | the crate root. Public APIs which deal in digits, like `BigUint::from_slice`, 63 | will now always be base-`u32`. 64 | 65 | **Contributors**: @clarcharr, @cuviper, @dodomorandi, @tiehuis, @tspiteri 66 | 67 | [8]: https://github.com/rust-num/num-bigint/pull/8 68 | [22]: https://github.com/rust-num/num-bigint/pull/22 69 | [23]: https://github.com/rust-num/num-bigint/pull/23 70 | [24]: https://github.com/rust-num/num-bigint/pull/24 71 | [26]: https://github.com/rust-num/num-bigint/pull/26 72 | [37]: https://github.com/rust-num/num-bigint/pull/37 73 | [38]: https://github.com/rust-num/num-bigint/pull/38 74 | [41]: https://github.com/rust-num/num-bigint/pull/41 75 | [44]: https://github.com/rust-num/num-bigint/pull/44 76 | [46]: https://github.com/rust-num/num-bigint/pull/46 77 | [48]: https://github.com/rust-num/num-bigint/pull/48 78 | [49]: https://github.com/rust-num/num-bigint/pull/49 79 | 80 | # Release 0.1.44 (2018-05-14) 81 | 82 | - [Division with single-digit divisors is now much faster.][42] 83 | - The README now compares [`ramp`, `rug`, `rust-gmp`][20], and [`apint`][21]. 84 | 85 | **Contributors**: @cuviper, @Robbepop 86 | 87 | [20]: https://github.com/rust-num/num-bigint/pull/20 88 | [21]: https://github.com/rust-num/num-bigint/pull/21 89 | [42]: https://github.com/rust-num/num-bigint/pull/42 90 | 91 | # Release 0.1.43 (2018-02-08) 92 | 93 | - [The new `BigInt::modpow`][18] performs signed modular exponentiation, using 94 | the existing `BigUint::modpow` and rounding negatives similar to `mod_floor`. 95 | 96 | **Contributors**: @cuviper 97 | 98 | [18]: https://github.com/rust-num/num-bigint/pull/18 99 | 100 | 101 | # Release 0.1.42 (2018-02-07) 102 | 103 | - [num-bigint now has its own source repository][num-356] at [rust-num/num-bigint][home]. 104 | - [`lcm` now avoids creating a large intermediate product][num-350]. 105 | - [`gcd` now uses Stein's algorithm][15] with faster shifts instead of division. 106 | - [`rand` support is now extended to 0.4][11] (while still allowing 0.3). 107 | 108 | **Contributors**: @cuviper, @Emerentius, @ignatenkobrain, @mhogrefe 109 | 110 | [home]: https://github.com/rust-num/num-bigint 111 | [num-350]: https://github.com/rust-num/num/pull/350 112 | [num-356]: https://github.com/rust-num/num/pull/356 113 | [11]: https://github.com/rust-num/num-bigint/pull/11 114 | [15]: https://github.com/rust-num/num-bigint/pull/15 115 | 116 | 117 | # Prior releases 118 | 119 | No prior release notes were kept. Thanks all the same to the many 120 | contributors that have made this crate what it is! 121 | 122 | -------------------------------------------------------------------------------- /benchmark_crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "num-bigint-dig-benchmark" 3 | version = "0.0.0" 4 | autobenches = false 5 | publish = false 6 | 7 | [[bench]] 8 | harness = false 9 | name = "bench_main" 10 | 11 | [dependencies] 12 | num-bigint-dig = { path = "../", features = ["prime", "rand"] } 13 | num-integer = "0.1.39" 14 | num-traits = "0.2.4" 15 | rand = "0.8.3" 16 | rand_chacha = "0.3.0" 17 | 18 | [dev-dependencies] 19 | criterion = "0.2" 20 | -------------------------------------------------------------------------------- /benchmark_crate/benches/bench_main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | extern crate num_bigint_dig as num_bigint; 4 | extern crate num_integer; 5 | extern crate num_traits; 6 | extern crate rand; 7 | extern crate rand_chacha; 8 | 9 | mod benchmarks; 10 | 11 | criterion_main! { 12 | benchmarks::prime_benches::benches, 13 | benchmarks::gcd::benches, 14 | benchmarks::egcd::benches, 15 | benchmarks::factorial::benches, 16 | benchmarks::bigint::benches, 17 | benchmarks::roots::benches, 18 | } 19 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/bigint.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::{BigInt, BigUint, RandBigInt}; 3 | use num_traits::{FromPrimitive, Num, One, Pow, Zero}; 4 | use rand::{rngs::StdRng, SeedableRng}; 5 | use std::mem::replace; 6 | 7 | fn get_rng() -> StdRng { 8 | let mut seed = [0; 32]; 9 | for i in 1..32 { 10 | seed[usize::from(i)] = i; 11 | } 12 | SeedableRng::from_seed(seed) 13 | } 14 | 15 | fn multiply_bench(c: &mut Criterion, name: String, xbits: usize, ybits: usize) { 16 | let mut rng = get_rng(); 17 | let x = rng.gen_bigint(xbits); 18 | let y = rng.gen_bigint(ybits); 19 | 20 | c.bench_function(&name, move |b| b.iter(|| &x * &y)); 21 | } 22 | 23 | fn divide_bench(c: &mut Criterion, name: String, xbits: usize, ybits: usize) { 24 | let mut rng = get_rng(); 25 | let x = rng.gen_bigint(xbits); 26 | let y = rng.gen_bigint(ybits); 27 | 28 | c.bench_function(&name, move |b| b.iter(|| &x / &y)); 29 | } 30 | 31 | fn factorial(n: usize) -> BigUint { 32 | let mut f: BigUint = One::one(); 33 | for i in 1..(n + 1) { 34 | let bu: BigUint = FromPrimitive::from_usize(i).unwrap(); 35 | f = f * bu; 36 | } 37 | f 38 | } 39 | 40 | /// Compute Fibonacci numbers 41 | fn fib(n: usize) -> BigUint { 42 | let mut f0: BigUint = Zero::zero(); 43 | let mut f1: BigUint = One::one(); 44 | for _ in 0..n { 45 | let f2 = f0 + &f1; 46 | f0 = replace(&mut f1, f2); 47 | } 48 | f0 49 | } 50 | 51 | /// Compute Fibonacci numbers with two ops per iteration 52 | /// (add and subtract, like issue #200) 53 | fn fib2(n: usize) -> BigUint { 54 | let mut f0: BigUint = Zero::zero(); 55 | let mut f1: BigUint = One::one(); 56 | for _ in 0..n { 57 | f1 = f1 + &f0; 58 | f0 = &f1 - f0; 59 | } 60 | f0 61 | } 62 | 63 | fn multiply_0(c: &mut Criterion) { 64 | multiply_bench(c, "multiply_0".to_string(), 1 << 8, 1 << 8); 65 | } 66 | 67 | fn multiply_1(c: &mut Criterion) { 68 | multiply_bench(c, "multiply_1".to_string(), 1 << 8, 1 << 16); 69 | } 70 | 71 | fn multiply_2(c: &mut Criterion) { 72 | multiply_bench(c, "multiply_2".to_string(), 1 << 16, 1 << 16); 73 | } 74 | 75 | fn multiply_3(c: &mut Criterion) { 76 | multiply_bench(c, "multiply_3".to_string(), 1 << 16, 1 << 17); 77 | } 78 | 79 | fn divide_0(c: &mut Criterion) { 80 | divide_bench(c, "divide_0".to_string(), 1 << 8, 1 << 6); 81 | } 82 | 83 | fn divide_1(c: &mut Criterion) { 84 | divide_bench(c, "divide_1".to_string(), 1 << 12, 1 << 8); 85 | } 86 | 87 | fn divide_2(c: &mut Criterion) { 88 | divide_bench(c, "divide_2".to_string(), 1 << 16, 1 << 12); 89 | } 90 | 91 | fn factorial_100(c: &mut Criterion) { 92 | c.bench_function("factorial_100", move |b| b.iter(|| factorial(100))); 93 | } 94 | 95 | fn fib_100(c: &mut Criterion) { 96 | c.bench_function("fib_100", move |b| b.iter(|| fib(100))); 97 | } 98 | 99 | fn fib_1000(c: &mut Criterion) { 100 | c.bench_function("fib_1000", move |b| b.iter(|| fib(1000))); 101 | } 102 | 103 | fn fib_10000(c: &mut Criterion) { 104 | c.bench_function("fib_10000", move |b| b.iter(|| fib(10000))); 105 | } 106 | 107 | fn fib2_100(c: &mut Criterion) { 108 | c.bench_function("fib2_100", move |b| b.iter(|| fib2(100))); 109 | } 110 | 111 | fn fib2_1000(c: &mut Criterion) { 112 | c.bench_function("fib2_1000", move |b| b.iter(|| fib2(1000))); 113 | } 114 | 115 | fn fib2_10000(c: &mut Criterion) { 116 | c.bench_function("fib2_10000", move |b| b.iter(|| fib2(10000))); 117 | } 118 | 119 | fn fac_to_string(c: &mut Criterion) { 120 | let fac = factorial(100); 121 | c.bench_function("fac_to_string", move |b| b.iter(|| fac.to_string())); 122 | } 123 | 124 | fn fib_to_string(c: &mut Criterion) { 125 | let fib = fib(100); 126 | c.bench_function("fib_to_string", move |b| b.iter(|| fib.to_string())); 127 | } 128 | 129 | fn to_str_radix_bench(c: &mut Criterion, radix: u32) { 130 | let mut rng = get_rng(); 131 | let x = rng.gen_bigint(1009); 132 | c.bench_function(&format!("to_str_radix_bench_{:?}", radix), move |b| { 133 | b.iter(|| x.to_str_radix(radix)) 134 | }); 135 | } 136 | 137 | fn to_str_radix_02(c: &mut Criterion) { 138 | to_str_radix_bench(c, 2); 139 | } 140 | 141 | fn to_str_radix_08(c: &mut Criterion) { 142 | to_str_radix_bench(c, 8); 143 | } 144 | 145 | fn to_str_radix_10(c: &mut Criterion) { 146 | to_str_radix_bench(c, 10); 147 | } 148 | 149 | fn to_str_radix_16(c: &mut Criterion) { 150 | to_str_radix_bench(c, 16); 151 | } 152 | 153 | fn to_str_radix_36(c: &mut Criterion) { 154 | to_str_radix_bench(c, 36); 155 | } 156 | 157 | fn from_str_radix_bench(c: &mut Criterion, radix: u32) { 158 | let mut rng = get_rng(); 159 | let x = rng.gen_bigint(1009); 160 | let s = x.to_str_radix(radix); 161 | assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap()); 162 | 163 | c.bench_function(&format!("from_str_radix_bench{:?}", radix), move |b| { 164 | b.iter(|| BigInt::from_str_radix(&s, radix)) 165 | }); 166 | } 167 | 168 | fn from_str_radix_02(c: &mut Criterion) { 169 | from_str_radix_bench(c, 2); 170 | } 171 | 172 | fn from_str_radix_08(c: &mut Criterion) { 173 | from_str_radix_bench(c, 8); 174 | } 175 | 176 | fn from_str_radix_10(c: &mut Criterion) { 177 | from_str_radix_bench(c, 10); 178 | } 179 | 180 | fn from_str_radix_16(c: &mut Criterion) { 181 | from_str_radix_bench(c, 16); 182 | } 183 | 184 | fn from_str_radix_36(c: &mut Criterion) { 185 | from_str_radix_bench(c, 36); 186 | } 187 | 188 | fn rand_bench(c: &mut Criterion, bits: usize) { 189 | let mut rng = get_rng(); 190 | c.bench_function(&format!("rand_bench_{:?}", bits), move |b| { 191 | b.iter(|| rng.gen_bigint(bits)) 192 | }); 193 | } 194 | 195 | fn rand_64(c: &mut Criterion) { 196 | rand_bench(c, 1 << 6); 197 | } 198 | 199 | fn rand_256(c: &mut Criterion) { 200 | rand_bench(c, 1 << 8); 201 | } 202 | 203 | fn rand_1009(c: &mut Criterion) { 204 | rand_bench(c, 1009); 205 | } 206 | 207 | fn rand_2048(c: &mut Criterion) { 208 | rand_bench(c, 1 << 11); 209 | } 210 | 211 | fn rand_4096(c: &mut Criterion) { 212 | rand_bench(c, 1 << 12); 213 | } 214 | 215 | fn rand_8192(c: &mut Criterion) { 216 | rand_bench(c, 1 << 13); 217 | } 218 | 219 | fn rand_65536(c: &mut Criterion) { 220 | rand_bench(c, 1 << 16); 221 | } 222 | 223 | fn rand_131072(c: &mut Criterion) { 224 | rand_bench(c, 1 << 17); 225 | } 226 | 227 | fn shl(c: &mut Criterion) { 228 | let n = BigUint::one() << 1000; 229 | 230 | c.bench_function("shl", move |b| { 231 | b.iter(|| { 232 | let mut m = n.clone(); 233 | for i in 0..50 { 234 | m = m << i; 235 | } 236 | }) 237 | }); 238 | } 239 | 240 | fn shr(c: &mut Criterion) { 241 | let n = BigUint::one() << 2000; 242 | 243 | c.bench_function("shr", move |b| { 244 | b.iter(|| { 245 | let mut m = n.clone(); 246 | for i in 0..50 { 247 | m = m << i; 248 | } 249 | }) 250 | }); 251 | } 252 | 253 | fn hash(c: &mut Criterion) { 254 | use std::collections::HashSet; 255 | let mut rng = get_rng(); 256 | let v: Vec = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect(); 257 | c.bench_function("hash", move |b| { 258 | b.iter(|| { 259 | let h: HashSet<&BigInt> = v.iter().collect(); 260 | assert_eq!(h.len(), v.len()); 261 | }) 262 | }); 263 | } 264 | 265 | fn pow_bench(c: &mut Criterion) { 266 | c.bench_function("pow_bench", move |b| { 267 | b.iter(|| { 268 | let upper = 100_usize; 269 | for i in 2..upper + 1 { 270 | for j in 2..upper + 1 { 271 | let i_big = BigUint::from_usize(i).unwrap(); 272 | i_big.pow(j); 273 | } 274 | } 275 | }) 276 | }); 277 | } 278 | 279 | /// This modulus is the prime from the 2048-bit MODP DH group: 280 | /// https://tools.ietf.org/html/rfc3526#section-3 281 | const RFC3526_2048BIT_MODP_GROUP: &'static str = 282 | "\ 283 | FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\ 284 | 29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\ 285 | EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\ 286 | E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\ 287 | EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\ 288 | C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\ 289 | 83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\ 290 | 670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\ 291 | E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\ 292 | DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\ 293 | 15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF"; 294 | 295 | fn modpow(c: &mut Criterion) { 296 | let mut rng = get_rng(); 297 | let base = rng.gen_biguint(2048); 298 | let e = rng.gen_biguint(2048); 299 | let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap(); 300 | 301 | c.bench_function("modpow", move |b| b.iter(|| base.modpow(&e, &m))); 302 | } 303 | 304 | fn modpow_even(c: &mut Criterion) { 305 | let mut rng = get_rng(); 306 | let base = rng.gen_biguint(2048); 307 | let e = rng.gen_biguint(2048); 308 | // Make the modulus even, so monty (base-2^32) doesn't apply. 309 | let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap() - 1u32; 310 | 311 | c.bench_function("modpow_even", move |b| { 312 | b.iter(|| base.modpow(&e, &m)); 313 | }); 314 | } 315 | 316 | fn roots_sqrt(c: &mut Criterion) { 317 | let mut rng = get_rng(); 318 | let x = rng.gen_biguint(2048); 319 | c.bench_function("roots_sqrt", move |b| b.iter(|| x.sqrt())); 320 | } 321 | 322 | fn roots_cbrt(c: &mut Criterion) { 323 | let mut rng = get_rng(); 324 | let x = rng.gen_biguint(2048); 325 | c.bench_function("roots_cbrt", move |b| b.iter(|| x.cbrt())); 326 | } 327 | 328 | fn roots_nth_100(c: &mut Criterion) { 329 | let mut rng = get_rng(); 330 | let x = rng.gen_biguint(2048); 331 | c.bench_function("roots_nth_100", move |b| b.iter(|| x.nth_root(100))); 332 | } 333 | 334 | criterion_group! { 335 | name = benches; 336 | config = Criterion::default(); 337 | targets = 338 | multiply_0, 339 | multiply_1, 340 | multiply_2, 341 | multiply_3, 342 | divide_0, 343 | divide_1, 344 | divide_2, 345 | factorial_100, 346 | fib_100, 347 | fib_1000, 348 | fib_10000, 349 | fib2_100, 350 | fib2_1000, 351 | fib2_10000, 352 | fac_to_string, 353 | fib_to_string, 354 | to_str_radix_02, 355 | to_str_radix_08, 356 | to_str_radix_10, 357 | to_str_radix_16, 358 | to_str_radix_36, 359 | from_str_radix_02, 360 | from_str_radix_08, 361 | from_str_radix_10, 362 | from_str_radix_16, 363 | from_str_radix_36, 364 | rand_64, 365 | rand_256, 366 | rand_1009, 367 | rand_2048, 368 | rand_4096, 369 | rand_8192, 370 | rand_65536, 371 | rand_131072, 372 | shl, 373 | shr, 374 | hash, 375 | pow_bench, 376 | modpow, 377 | modpow_even, 378 | roots_sqrt, 379 | roots_cbrt, 380 | roots_nth_100, 381 | } 382 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/egcd.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::{ExtendedGcd, RandBigInt}; 3 | use rand::{rngs::StdRng, SeedableRng}; 4 | 5 | fn get_rng() -> StdRng { 6 | let mut seed = [0; 32]; 7 | for i in 1..32 { 8 | seed[usize::from(i)] = i; 9 | } 10 | SeedableRng::from_seed(seed) 11 | } 12 | 13 | fn bench(c: &mut Criterion, name: String, bits: usize) { 14 | let mut rng = get_rng(); 15 | let x = rng.gen_biguint(bits); 16 | let y = rng.gen_biguint(bits); 17 | 18 | c.bench_function(&name, move |b| b.iter(|| (&x).extended_gcd(&y))); 19 | } 20 | 21 | fn egcd_0064(c: &mut Criterion) { 22 | bench(c, "egcd_0064".to_string(), 64); 23 | } 24 | 25 | fn egcd_0256(c: &mut Criterion) { 26 | bench(c, "egcd_0256".to_string(), 256); 27 | } 28 | 29 | fn egcd_1024(c: &mut Criterion) { 30 | bench(c, "egcd_1024".to_string(), 1024); 31 | } 32 | 33 | fn egcd_4096(c: &mut Criterion) { 34 | bench(c, "egcd_4096".to_string(), 4096); 35 | } 36 | 37 | criterion_group! { 38 | name = benches; 39 | config = Criterion::default(); 40 | targets = 41 | egcd_0064, 42 | egcd_0256, 43 | egcd_1024, 44 | egcd_4096, 45 | } 46 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/factorial.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::BigUint; 3 | use num_traits::One; 4 | use std::ops::{Div, Mul}; 5 | 6 | fn factorial_mul_biguint(c: &mut Criterion) { 7 | c.bench_function("factorial_mul_biguint", move |b| { 8 | b.iter(|| { 9 | (1u32..1000) 10 | .map(BigUint::from) 11 | .fold(BigUint::one(), Mul::mul) 12 | }) 13 | }); 14 | } 15 | 16 | fn factorial_mul_u32(c: &mut Criterion) { 17 | c.bench_function("factorial_mul_u32", move |b| { 18 | b.iter(|| (1u32..1000).fold(BigUint::one(), Mul::mul)) 19 | }); 20 | } 21 | 22 | // The division test is inspired by this blog comparison: 23 | // 24 | 25 | fn factorial_div_biguint(c: &mut Criterion) { 26 | let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul); 27 | 28 | c.bench_function("factorial_div_biguint", move |b| { 29 | b.iter(|| { 30 | (1u32..1000) 31 | .rev() 32 | .map(BigUint::from) 33 | .fold(n.clone(), Div::div) 34 | }) 35 | }); 36 | } 37 | 38 | fn factorial_div_u32(c: &mut Criterion) { 39 | let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul); 40 | 41 | c.bench_function("factorial_div_u32", move |b| { 42 | b.iter(|| (1u32..1000).rev().fold(n.clone(), Div::div)) 43 | }); 44 | } 45 | 46 | criterion_group! { 47 | name = benches; 48 | config = { let c = Criterion::default(); c.sample_size(5) }; 49 | targets = 50 | factorial_mul_biguint, 51 | factorial_mul_u32, 52 | factorial_div_biguint, 53 | factorial_div_u32, 54 | } 55 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/gcd.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::{BigUint, RandBigInt}; 3 | use num_integer::Integer; 4 | use num_traits::Zero; 5 | use rand::{rngs::StdRng, SeedableRng}; 6 | 7 | fn get_rng() -> StdRng { 8 | let mut seed = [0; 32]; 9 | for i in 1..32 { 10 | seed[usize::from(i)] = i; 11 | } 12 | SeedableRng::from_seed(seed) 13 | } 14 | 15 | fn bench(c: &mut Criterion, name: String, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) { 16 | let mut rng = get_rng(); 17 | let x = rng.gen_biguint(bits); 18 | let y = rng.gen_biguint(bits); 19 | 20 | assert_eq!(euclid(&x, &y), x.gcd(&y)); 21 | 22 | c.bench_function(&name, move |b| b.iter(|| gcd(&x, &y))); 23 | } 24 | 25 | fn euclid(x: &BigUint, y: &BigUint) -> BigUint { 26 | // Use Euclid's algorithm 27 | let mut m = x.clone(); 28 | let mut n = y.clone(); 29 | while !m.is_zero() { 30 | let temp = m; 31 | m = n % &temp; 32 | n = temp; 33 | } 34 | return n; 35 | } 36 | 37 | fn gcd_euclid_0064(c: &mut Criterion) { 38 | bench(c, "gcd_euclid_0064".to_string(), 64, euclid); 39 | } 40 | 41 | fn gcd_euclid_0256(c: &mut Criterion) { 42 | bench(c, "gcd_euclid_0256".to_string(), 256, euclid); 43 | } 44 | 45 | fn gcd_euclid_1024(c: &mut Criterion) { 46 | bench(c, "gcd_euclid_1024".to_string(), 1024, euclid); 47 | } 48 | 49 | fn gcd_euclid_4096(c: &mut Criterion) { 50 | bench(c, "gcd_euclid_4096".to_string(), 4096, euclid); 51 | } 52 | 53 | // Integer for BigUint now uses Lehmer for gcd 54 | 55 | fn gcd_lehmer_0064(c: &mut Criterion) { 56 | bench(c, "gcd_lehmer_0064".to_string(), 64, BigUint::gcd); 57 | } 58 | 59 | fn gcd_lehmer_0256(c: &mut Criterion) { 60 | bench(c, "gcd_lehmer_0256".to_string(), 256, BigUint::gcd); 61 | } 62 | 63 | fn gcd_lehmer_1024(c: &mut Criterion) { 64 | bench(c, "gcd_lehmer_1024".to_string(), 1024, BigUint::gcd); 65 | } 66 | 67 | fn gcd_lehmer_4096(c: &mut Criterion) { 68 | bench(c, "gcd_lehmer_4096".to_string(), 4096, BigUint::gcd); 69 | } 70 | 71 | criterion_group! { 72 | name = benches; 73 | config = Criterion::default(); 74 | targets = 75 | gcd_euclid_0064, 76 | gcd_euclid_0256, 77 | gcd_euclid_1024, 78 | gcd_euclid_4096, 79 | gcd_lehmer_0064, 80 | gcd_lehmer_0256, 81 | gcd_lehmer_1024, 82 | gcd_lehmer_4096, 83 | } 84 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bigint; 2 | pub mod egcd; 3 | pub mod factorial; 4 | pub mod gcd; 5 | pub mod prime_benches; 6 | pub mod roots; 7 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/prime_benches.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::prime; 3 | use num_bigint::BigUint; 4 | use num_bigint::RandPrime; 5 | use rand::SeedableRng; 6 | use rand_chacha::ChaChaRng; 7 | 8 | const NUM: &'static str = "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123"; 9 | 10 | fn probably_prime_0(c: &mut Criterion) { 11 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 12 | 13 | c.bench_function("probably_prime_0", move |b| { 14 | b.iter(|| prime::probably_prime(&x, 0)) 15 | }); 16 | } 17 | 18 | fn probably_prime_1(c: &mut Criterion) { 19 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 20 | 21 | c.bench_function("probably_prime_1", move |b| { 22 | b.iter(|| prime::probably_prime(&x, 1)) 23 | }); 24 | } 25 | 26 | fn probably_prime_5(c: &mut Criterion) { 27 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 28 | 29 | c.bench_function("probably_prime_5", move |b| { 30 | b.iter(|| prime::probably_prime(&x, 5)) 31 | }); 32 | } 33 | 34 | fn probably_prime_10(c: &mut Criterion) { 35 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 36 | 37 | c.bench_function("probably_prime_10", move |b| { 38 | b.iter(|| prime::probably_prime(&x, 10)) 39 | }); 40 | } 41 | 42 | fn probably_prime_20(c: &mut Criterion) { 43 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 44 | 45 | c.bench_function("probably_prime_20", move |b| { 46 | b.iter(|| prime::probably_prime(&x, 20)) 47 | }); 48 | } 49 | 50 | fn bench_prime_lucas(c: &mut Criterion) { 51 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 52 | 53 | c.bench_function("bench_prime_lucas", move |b| { 54 | b.iter(|| prime::probably_prime_lucas(&x)) 55 | }); 56 | } 57 | 58 | fn bench_prime_miller_rabin(c: &mut Criterion) { 59 | let x = BigUint::parse_bytes(NUM.as_bytes(), 10).unwrap(); 60 | 61 | c.bench_function("bench_prime_miller_rabin", move |b| { 62 | b.iter(|| prime::probably_prime_miller_rabin(&x, 1, true)) 63 | }); 64 | } 65 | 66 | fn bench_gen_prime(c: &mut Criterion) { 67 | c.bench_function("bench_gen_prime", move |b| { 68 | let rng = &mut ChaChaRng::from_seed([0u8; 32]); 69 | b.iter(|| rng.gen_prime(1024)) 70 | }); 71 | } 72 | 73 | criterion_group! { 74 | name = benches; 75 | config = { let c = Criterion::default(); c.sample_size(5) }; 76 | targets = 77 | probably_prime_0, 78 | probably_prime_1, 79 | probably_prime_5, 80 | probably_prime_10, 81 | probably_prime_20, 82 | bench_prime_lucas, 83 | bench_prime_miller_rabin, 84 | bench_gen_prime, 85 | } 86 | -------------------------------------------------------------------------------- /benchmark_crate/benches/benchmarks/roots.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | use num_bigint::{BigUint, RandBigInt}; 3 | use num_traits::Pow; 4 | use rand::{rngs::StdRng, SeedableRng}; 5 | 6 | // The `big64` cases demonstrate the speed of cases where the value 7 | // can be converted to a `u64` primitive for faster calculation. 8 | // 9 | // The `big1k` cases demonstrate those that can convert to `f64` for 10 | // a better initial guess of the actual value. 11 | // 12 | // The `big2k` and `big4k` cases are too big for `f64`, and use a simpler guess. 13 | 14 | fn get_rng() -> StdRng { 15 | let mut seed = [0; 32]; 16 | for i in 1..32 { 17 | seed[usize::from(i)] = i; 18 | } 19 | SeedableRng::from_seed(seed) 20 | } 21 | 22 | fn check(x: &BigUint, n: u32) { 23 | let root = x.nth_root(n); 24 | if n == 2 { 25 | assert_eq!(root, x.sqrt()) 26 | } else if n == 3 { 27 | assert_eq!(root, x.cbrt()) 28 | } 29 | 30 | let lo = root.pow(n); 31 | assert!(lo <= *x); 32 | assert_eq!(lo.nth_root(n), root); 33 | assert_eq!((&lo - 1u32).nth_root(n), &root - 1u32); 34 | 35 | let hi = (&root + 1u32).pow(n); 36 | assert!(hi > *x); 37 | assert_eq!(hi.nth_root(n), &root + 1u32); 38 | assert_eq!((&hi - 1u32).nth_root(n), root); 39 | } 40 | 41 | fn bench_sqrt(c: &mut Criterion, bits: usize) { 42 | let x = get_rng().gen_biguint(bits); 43 | 44 | check(&x, 2); 45 | c.bench_function(&format!("bench_sqrt(bits={})", bits), move |b| { 46 | b.iter(|| x.sqrt()) 47 | }); 48 | } 49 | 50 | fn big64_sqrt(b: &mut Criterion) { 51 | bench_sqrt(b, 64); 52 | } 53 | 54 | fn big1k_sqrt(b: &mut Criterion) { 55 | bench_sqrt(b, 1024); 56 | } 57 | 58 | fn big2k_sqrt(b: &mut Criterion) { 59 | bench_sqrt(b, 2048); 60 | } 61 | 62 | fn big4k_sqrt(b: &mut Criterion) { 63 | bench_sqrt(b, 4096); 64 | } 65 | 66 | fn bench_cbrt(c: &mut Criterion, bits: usize) { 67 | let x = get_rng().gen_biguint(bits); 68 | 69 | check(&x, 3); 70 | c.bench_function(&format!("bench_cbrt(bits={})", bits), move |b| { 71 | b.iter(|| x.cbrt()) 72 | }); 73 | } 74 | 75 | fn big64_cbrt(b: &mut Criterion) { 76 | bench_cbrt(b, 64); 77 | } 78 | 79 | fn big1k_cbrt(b: &mut Criterion) { 80 | bench_cbrt(b, 1024); 81 | } 82 | 83 | fn big2k_cbrt(b: &mut Criterion) { 84 | bench_cbrt(b, 2048); 85 | } 86 | 87 | fn big4k_cbrt(b: &mut Criterion) { 88 | bench_cbrt(b, 4096); 89 | } 90 | 91 | fn bench_nth_root(c: &mut Criterion, bits: usize, n: u32) { 92 | let x = get_rng().gen_biguint(bits); 93 | 94 | check(&x, n); 95 | c.bench_function(&format!("bench_{}th_root(bits={})", n, bits), move |b| { 96 | b.iter(|| x.nth_root(n)) 97 | }); 98 | } 99 | 100 | fn big64_nth_10(b: &mut Criterion) { 101 | bench_nth_root(b, 64, 10); 102 | } 103 | 104 | fn big1k_nth_10(b: &mut Criterion) { 105 | bench_nth_root(b, 1024, 10); 106 | } 107 | 108 | fn big1k_nth_100(b: &mut Criterion) { 109 | bench_nth_root(b, 1024, 100); 110 | } 111 | 112 | fn big1k_nth_1000(b: &mut Criterion) { 113 | bench_nth_root(b, 1024, 1000); 114 | } 115 | 116 | fn big1k_nth_10000(b: &mut Criterion) { 117 | bench_nth_root(b, 1024, 10000); 118 | } 119 | 120 | fn big2k_nth_10(b: &mut Criterion) { 121 | bench_nth_root(b, 2048, 10); 122 | } 123 | 124 | fn big2k_nth_100(b: &mut Criterion) { 125 | bench_nth_root(b, 2048, 100); 126 | } 127 | 128 | fn big2k_nth_1000(b: &mut Criterion) { 129 | bench_nth_root(b, 2048, 1000); 130 | } 131 | 132 | fn big2k_nth_10000(b: &mut Criterion) { 133 | bench_nth_root(b, 2048, 10000); 134 | } 135 | 136 | fn big4k_nth_10(b: &mut Criterion) { 137 | bench_nth_root(b, 4096, 10); 138 | } 139 | 140 | fn big4k_nth_100(b: &mut Criterion) { 141 | bench_nth_root(b, 4096, 100); 142 | } 143 | 144 | fn big4k_nth_1000(b: &mut Criterion) { 145 | bench_nth_root(b, 4096, 1000); 146 | } 147 | 148 | fn big4k_nth_10000(b: &mut Criterion) { 149 | bench_nth_root(b, 4096, 10000); 150 | } 151 | 152 | criterion_group! { 153 | name = benches; 154 | config = Criterion::default(); 155 | targets = 156 | big64_sqrt, 157 | big1k_sqrt, 158 | big2k_sqrt, 159 | big4k_sqrt, 160 | big64_cbrt, 161 | big1k_cbrt, 162 | big2k_cbrt, 163 | big4k_cbrt, 164 | big64_nth_10, 165 | big1k_nth_10, 166 | big1k_nth_100, 167 | big1k_nth_1000, 168 | big1k_nth_10000, 169 | big2k_nth_10, 170 | big2k_nth_100, 171 | big2k_nth_1000, 172 | big2k_nth_10000, 173 | big4k_nth_10, 174 | big4k_nth_100, 175 | big4k_nth_1000, 176 | big4k_nth_10000, 177 | } 178 | -------------------------------------------------------------------------------- /benchmark_crate/benches/shootout-pidigits.rs: -------------------------------------------------------------------------------- 1 | // The Computer Language Benchmarks Game 2 | // http://benchmarksgame.alioth.debian.org/ 3 | // 4 | // contributed by the Rust Project Developers 5 | 6 | // Copyright (c) 2013-2014 The Rust Project Developers 7 | // 8 | // All rights reserved. 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions 12 | // are met: 13 | // 14 | // - Redistributions of source code must retain the above copyright 15 | // notice, this list of conditions and the following disclaimer. 16 | // 17 | // - Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in 19 | // the documentation and/or other materials provided with the 20 | // distribution. 21 | // 22 | // - Neither the name of "The Computer Language Benchmarks Game" nor 23 | // the name of "The Computer Language Shootout Benchmarks" nor the 24 | // names of its contributors may be used to endorse or promote 25 | // products derived from this software without specific prior 26 | // written permission. 27 | // 28 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 31 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 32 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 33 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 | // OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | extern crate num_bigint_dig as num_bigint; 42 | extern crate num_integer; 43 | extern crate num_traits; 44 | 45 | use std::io; 46 | use std::str::FromStr; 47 | 48 | use num_bigint::BigInt; 49 | use num_integer::Integer; 50 | use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; 51 | 52 | struct Context { 53 | numer: BigInt, 54 | accum: BigInt, 55 | denom: BigInt, 56 | } 57 | 58 | impl Context { 59 | fn new() -> Context { 60 | Context { 61 | numer: One::one(), 62 | accum: Zero::zero(), 63 | denom: One::one(), 64 | } 65 | } 66 | 67 | fn from_i32(i: i32) -> BigInt { 68 | FromPrimitive::from_i32(i).unwrap() 69 | } 70 | 71 | fn extract_digit(&self) -> i32 { 72 | if self.numer > self.accum { 73 | return -1; 74 | } 75 | let (q, r) = (&self.numer * Context::from_i32(3) + &self.accum).div_rem(&self.denom); 76 | if r + &self.numer >= self.denom { 77 | return -1; 78 | } 79 | q.to_i32().unwrap() 80 | } 81 | 82 | fn next_term(&mut self, k: i32) { 83 | let y2 = Context::from_i32(k * 2 + 1); 84 | self.accum = (&self.accum + (&self.numer << 1)) * &y2; 85 | self.numer = &self.numer * Context::from_i32(k); 86 | self.denom = &self.denom * y2; 87 | } 88 | 89 | fn eliminate_digit(&mut self, d: i32) { 90 | let d = Context::from_i32(d); 91 | let ten = Context::from_i32(10); 92 | self.accum = (&self.accum - &self.denom * d) * &ten; 93 | self.numer = &self.numer * ten; 94 | } 95 | } 96 | 97 | fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> { 98 | let mut k = 0; 99 | let mut context = Context::new(); 100 | 101 | for i in 1..(n + 1) { 102 | let mut d; 103 | loop { 104 | k += 1; 105 | context.next_term(k); 106 | d = context.extract_digit(); 107 | if d != -1 { 108 | break; 109 | } 110 | } 111 | 112 | write!(out, "{}", d)?; 113 | if i % 10 == 0 { 114 | write!(out, "\t:{}\n", i)?; 115 | } 116 | 117 | context.eliminate_digit(d); 118 | } 119 | 120 | let m = n % 10; 121 | if m != 0 { 122 | for _ in m..10 { 123 | write!(out, " ")?; 124 | } 125 | write!(out, "\t:{}\n", n)?; 126 | } 127 | Ok(()) 128 | } 129 | 130 | const DEFAULT_DIGITS: isize = 512; 131 | 132 | fn main() { 133 | let args = std::env::args().collect::>(); 134 | let n = if args.len() < 2 { 135 | DEFAULT_DIGITS 136 | } else if args[1] == "--bench" { 137 | return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap(); 138 | } else if let Ok(n) = FromStr::from_str(&args[1]) { 139 | n 140 | } else { 141 | DEFAULT_DIGITS 142 | }; 143 | pidigits(n, &mut std::io::stdout()).unwrap(); 144 | } 145 | -------------------------------------------------------------------------------- /benchmark_crate/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dignifiedquire/num-bigint/6f73f0a4025164325e85f8645dad6712b3110c51/benchmark_crate/src/lib.rs -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-cfg=has_i128"); 3 | } 4 | -------------------------------------------------------------------------------- /ci/rustup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Use rustup to locally run the same suite of tests as .travis.yml. 3 | # (You should first install/update all versions listed below.) 4 | 5 | set -ex 6 | 7 | export TRAVIS_RUST_VERSION 8 | for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 stable beta nightly; do 9 | run="rustup run $TRAVIS_RUST_VERSION" 10 | $run cargo build --verbose 11 | $run $PWD/ci/test_full.sh 12 | done 13 | -------------------------------------------------------------------------------- /ci/test_full.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | echo Testing num-bigint on rustc ${TRAVIS_RUST_VERSION} 6 | 7 | FEATURES="serde i128 u64_digit prime" 8 | 9 | export RUST_BACKTRACE=1 10 | 11 | # num-bigint should build and test everywhere. 12 | cargo build --verbose 13 | cargo test --verbose 14 | 15 | # It should build with minimal features too. 16 | cargo build --no-default-features --features="std" 17 | cargo test --no-default-features --features="std" 18 | 19 | # It should build in no_std 20 | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then 21 | rustup target add thumbv7m-none-eabi 22 | cargo build --no-default-features --target=thumbv7m-none-eabi 23 | 24 | # It should work in no_std on nightly. 25 | # Note: Doctest might show an error: https://github.com/rust-lang/rust/issues/54010 26 | # The "error" is wrong however, the doctests still run. 27 | cargo test --no-default-features 28 | fi 29 | 30 | # Each isolated feature should also work everywhere. 31 | for feature in $FEATURES; do 32 | cargo build --verbose --no-default-features --features="std $feature" 33 | cargo test --verbose --no-default-features --features="std $feature" 34 | 35 | # Ensure that feature also works in nostd context on nightly. 36 | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then 37 | cargo build --verbose --no-default-features --features="$feature" 38 | cargo test --verbose --no-default-features --features="$feature" 39 | fi 40 | done 41 | 42 | # test all supported features together 43 | cargo build --features="std $FEATURES" 44 | cargo test --features="std $FEATURES" 45 | 46 | # make sure benchmarks can be built 47 | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then 48 | cd benchmark_crate 49 | cargo bench --all-features --no-run 50 | fi 51 | -------------------------------------------------------------------------------- /src/algorithms/add.rs: -------------------------------------------------------------------------------- 1 | use crate::big_digit::{BigDigit, DoubleBigDigit, BITS}; 2 | 3 | // Add with carry: 4 | #[inline] 5 | pub fn adc(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit { 6 | *acc += a as DoubleBigDigit; 7 | *acc += b as DoubleBigDigit; 8 | let lo = *acc as BigDigit; 9 | *acc >>= BITS; 10 | lo 11 | } 12 | 13 | // Only for the Add impl: 14 | #[inline] 15 | pub fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit { 16 | debug_assert!(a.len() >= b.len()); 17 | 18 | let mut carry = 0; 19 | let (a_lo, a_hi) = a.split_at_mut(b.len()); 20 | 21 | for (a, b) in a_lo.iter_mut().zip(b) { 22 | *a = adc(*a, *b, &mut carry); 23 | } 24 | 25 | if carry != 0 { 26 | for a in a_hi { 27 | *a = adc(*a, 0, &mut carry); 28 | if carry == 0 { 29 | break; 30 | } 31 | } 32 | } 33 | 34 | carry as BigDigit 35 | } 36 | 37 | /// /Two argument addition of raw slices: 38 | /// a += b 39 | /// 40 | /// The caller _must_ ensure that a is big enough to store the result - typically this means 41 | /// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry. 42 | pub fn add2(a: &mut [BigDigit], b: &[BigDigit]) { 43 | let carry = __add2(a, b); 44 | 45 | debug_assert!(carry == 0); 46 | } 47 | -------------------------------------------------------------------------------- /src/algorithms/bits.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | 3 | /// Find last set bit 4 | /// fls(0) == 0, fls(u32::MAX) == 32 5 | pub fn fls(v: T) -> usize { 6 | mem::size_of::() * 8 - v.leading_zeros() as usize 7 | } 8 | 9 | pub fn ilog2(v: T) -> usize { 10 | fls(v) - 1 11 | } 12 | 13 | /// Divide two integers, and ceil the result. 14 | pub fn idiv_ceil(a: T, b: T) -> T { 15 | if a % b != T::zero() { 16 | a / b + T::one() 17 | } else { 18 | a / b 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/algorithms/cmp.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::Ordering::{self, Equal, Greater, Less}; 2 | 3 | use crate::big_digit::BigDigit; 4 | 5 | pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering { 6 | debug_assert!(a.last() != Some(&0)); 7 | debug_assert!(b.last() != Some(&0)); 8 | 9 | let (a_len, b_len) = (a.len(), b.len()); 10 | if a_len < b_len { 11 | return Less; 12 | } 13 | if a_len > b_len { 14 | return Greater; 15 | } 16 | 17 | for (&ai, &bi) in a.iter().rev().zip(b.iter().rev()) { 18 | if ai < bi { 19 | return Less; 20 | } 21 | if ai > bi { 22 | return Greater; 23 | } 24 | } 25 | Equal 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use crate::BigUint; 31 | 32 | use num_traits::Num; 33 | 34 | #[test] 35 | fn test_eq() { 36 | let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap(); 37 | let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap(); 38 | assert!(a != b); 39 | assert_ne!(a, b); 40 | 41 | let a = BigUint::from_str_radix("138995801145388806366366393471481216294", 10).unwrap(); 42 | let b = BigUint::from_str_radix("168653801169012228514850424976871974699", 10).unwrap(); 43 | 44 | assert!(a != b); 45 | assert_ne!(a, b); 46 | assert!(&a != &b); 47 | assert_ne!(&a, &b); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/algorithms/div.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::Ordering; 2 | use num_traits::{One, Zero}; 3 | use smallvec::SmallVec; 4 | 5 | use crate::algorithms::{add2, cmp_slice, sub2}; 6 | use crate::big_digit::{self, BigDigit, DoubleBigDigit}; 7 | use crate::BigUint; 8 | 9 | pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) { 10 | let mut rem = 0; 11 | 12 | for d in a.data.iter_mut().rev() { 13 | let (q, r) = div_wide(rem, *d, b); 14 | *d = q; 15 | rem = r; 16 | } 17 | 18 | (a.normalized(), rem) 19 | } 20 | 21 | /// Divide a two digit numerator by a one digit divisor, returns quotient and remainder: 22 | /// 23 | /// Note: the caller must ensure that both the quotient and remainder will fit into a single digit. 24 | /// This is _not_ true for an arbitrary numerator/denominator. 25 | /// 26 | /// (This function also matches what the x86 divide instruction does). 27 | #[inline] 28 | pub fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigit) { 29 | debug_assert!(hi < divisor); 30 | 31 | let lhs = big_digit::to_doublebigdigit(hi, lo); 32 | let rhs = divisor as DoubleBigDigit; 33 | ((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit) 34 | } 35 | 36 | pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) { 37 | if d.is_zero() { 38 | panic!() 39 | } 40 | if u.is_zero() { 41 | return (Zero::zero(), Zero::zero()); 42 | } 43 | if d.data.len() == 1 { 44 | if d.data[0] == 1 { 45 | return (u.clone(), Zero::zero()); 46 | } 47 | 48 | let (div, rem) = div_rem_digit(u.clone(), d.data[0]); 49 | return (div, rem.into()); 50 | } 51 | 52 | // Required or the q_len calculation below can underflow: 53 | match u.cmp(d) { 54 | Ordering::Less => return (Zero::zero(), u.clone()), 55 | Ordering::Equal => return (One::one(), Zero::zero()), 56 | Ordering::Greater => {} // Do nothing 57 | } 58 | 59 | // This algorithm is from Knuth, TAOCP vol 2 section 4.3, algorithm D: 60 | // 61 | // First, normalize the arguments so the highest bit in the highest digit of the divisor is 62 | // set: the main loop uses the highest digit of the divisor for generating guesses, so we 63 | // want it to be the largest number we can efficiently divide by. 64 | // 65 | let shift = d.data.last().unwrap().leading_zeros() as usize; 66 | let mut a = u << shift; 67 | let b = d << shift; 68 | 69 | // The algorithm works by incrementally calculating "guesses", q0, for part of the 70 | // remainder. Once we have any number q0 such that q0 * b <= a, we can set 71 | // 72 | // q += q0 73 | // a -= q0 * b 74 | // 75 | // and then iterate until a < b. Then, (q, a) will be our desired quotient and remainder. 76 | // 77 | // q0, our guess, is calculated by dividing the last few digits of a by the last digit of b 78 | // - this should give us a guess that is "close" to the actual quotient, but is possibly 79 | // greater than the actual quotient. If q0 * b > a, we simply use iterated subtraction 80 | // until we have a guess such that q0 * b <= a. 81 | // 82 | 83 | let bn = *b.data.last().unwrap(); 84 | let q_len = a.data.len() - b.data.len() + 1; 85 | let mut q = BigUint { 86 | data: smallvec![0; q_len], 87 | }; 88 | 89 | // We reuse the same temporary to avoid hitting the allocator in our inner loop - this is 90 | // sized to hold a0 (in the common case; if a particular digit of the quotient is zero a0 91 | // can be bigger). 92 | // 93 | let mut tmp = BigUint { 94 | data: SmallVec::with_capacity(2), 95 | }; 96 | 97 | for j in (0..q_len).rev() { 98 | /* 99 | * When calculating our next guess q0, we don't need to consider the digits below j 100 | * + b.data.len() - 1: we're guessing digit j of the quotient (i.e. q0 << j) from 101 | * digit bn of the divisor (i.e. bn << (b.data.len() - 1) - so the product of those 102 | * two numbers will be zero in all digits up to (j + b.data.len() - 1). 103 | */ 104 | let offset = j + b.data.len() - 1; 105 | if offset >= a.data.len() { 106 | continue; 107 | } 108 | 109 | /* just avoiding a heap allocation: */ 110 | let mut a0 = tmp; 111 | a0.data.truncate(0); 112 | a0.data.extend(a.data[offset..].iter().cloned()); 113 | 114 | /* 115 | * q0 << j * big_digit::BITS is our actual quotient estimate - we do the shifts 116 | * implicitly at the end, when adding and subtracting to a and q. Not only do we 117 | * save the cost of the shifts, the rest of the arithmetic gets to work with 118 | * smaller numbers. 119 | */ 120 | let (mut q0, _) = div_rem_digit(a0, bn); 121 | let mut prod = &b * &q0; 122 | 123 | while cmp_slice(&prod.data[..], &a.data[j..]) == Ordering::Greater { 124 | let one: BigUint = One::one(); 125 | q0 = q0 - one; 126 | prod = prod - &b; 127 | } 128 | 129 | add2(&mut q.data[j..], &q0.data[..]); 130 | sub2(&mut a.data[j..], &prod.data[..]); 131 | a.normalize(); 132 | 133 | tmp = q0; 134 | } 135 | 136 | debug_assert!(a < b); 137 | 138 | (q.normalized(), a >> shift) 139 | } 140 | -------------------------------------------------------------------------------- /src/algorithms/jacobi.rs: -------------------------------------------------------------------------------- 1 | use crate::integer::Integer; 2 | use num_traits::{One, Signed, Zero}; 3 | 4 | use crate::BigInt; 5 | 6 | /// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0. 7 | /// The y argument must be an odd integer. 8 | pub fn jacobi(x: &BigInt, y: &BigInt) -> isize { 9 | if !y.is_odd() { 10 | panic!( 11 | "invalid arguments, y must be an odd integer,but got {:?}", 12 | y 13 | ); 14 | } 15 | 16 | let mut a = x.clone(); 17 | let mut b = y.clone(); 18 | let mut j = 1; 19 | 20 | if b.is_negative() { 21 | if a.is_negative() { 22 | j = -1; 23 | } 24 | b = -b; 25 | } 26 | 27 | loop { 28 | if b.is_one() { 29 | return j; 30 | } 31 | if a.is_zero() { 32 | return 0; 33 | } 34 | 35 | a = a.mod_floor(&b); 36 | if a.is_zero() { 37 | return 0; 38 | } 39 | 40 | // a > 0 41 | 42 | // handle factors of 2 in a 43 | let s = a.trailing_zeros().unwrap(); 44 | if s & 1 != 0 { 45 | let bmod8 = b.get_limb(0) & 7; 46 | if bmod8 == 3 || bmod8 == 5 { 47 | j = -j; 48 | } 49 | } 50 | 51 | let c = &a >> s; // a = 2^s*c 52 | 53 | // swap numerator and denominator 54 | if b.get_limb(0) & 3 == 3 && c.get_limb(0) & 3 == 3 { 55 | j = -j 56 | } 57 | 58 | a = b; 59 | b = c; 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod tests { 65 | use super::*; 66 | 67 | use num_traits::FromPrimitive; 68 | 69 | use crate::BigInt; 70 | 71 | #[test] 72 | fn test_jacobi() { 73 | let cases = [ 74 | [0, 1, 1], 75 | [0, -1, 1], 76 | [1, 1, 1], 77 | [1, -1, 1], 78 | [0, 5, 0], 79 | [1, 5, 1], 80 | [2, 5, -1], 81 | [-2, 5, -1], 82 | [2, -5, -1], 83 | [-2, -5, 1], 84 | [3, 5, -1], 85 | [5, 5, 0], 86 | [-5, 5, 0], 87 | [6, 5, 1], 88 | [6, -5, 1], 89 | [-6, 5, 1], 90 | [-6, -5, -1], 91 | ]; 92 | 93 | for case in cases.iter() { 94 | let x = BigInt::from_i64(case[0]).unwrap(); 95 | let y = BigInt::from_i64(case[1]).unwrap(); 96 | 97 | assert_eq!(case[2] as isize, jacobi(&x, &y), "jacobi({}, {})", x, y); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/algorithms/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::many_single_char_names)] 2 | 3 | mod add; 4 | mod bits; 5 | mod cmp; 6 | mod div; 7 | mod gcd; 8 | mod jacobi; 9 | mod mac; 10 | mod mod_inverse; 11 | mod mul; 12 | mod shl; 13 | mod shr; 14 | mod sub; 15 | 16 | pub use self::add::*; 17 | pub use self::bits::*; 18 | pub use self::cmp::*; 19 | pub use self::div::*; 20 | pub use self::gcd::*; 21 | pub use self::jacobi::*; 22 | pub use self::mac::*; 23 | pub use self::mod_inverse::*; 24 | pub use self::mul::*; 25 | pub use self::shl::*; 26 | pub use self::shr::*; 27 | pub use self::sub::*; 28 | -------------------------------------------------------------------------------- /src/algorithms/mod_inverse.rs: -------------------------------------------------------------------------------- 1 | use alloc::borrow::Cow; 2 | 3 | use num_traits::{One, Signed}; 4 | 5 | use crate::algorithms::extended_gcd; 6 | use crate::{BigInt, BigUint}; 7 | 8 | /// Calculate the modular inverse of `g`. 9 | /// Implementation is based on the naive version from wikipedia. 10 | #[inline] 11 | pub fn mod_inverse(g: Cow, n: Cow) -> Option { 12 | let (d, x, _) = extended_gcd(g, n.clone(), true); 13 | 14 | if !d.is_one() { 15 | return None; 16 | } 17 | 18 | let x = x.unwrap(); 19 | 20 | if x.is_negative() { 21 | Some(x + n.as_ref()) 22 | } else { 23 | Some(x) 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | 31 | use crate::integer::Integer; 32 | use num_traits::FromPrimitive; 33 | 34 | use crate::traits::ModInverse; 35 | 36 | #[test] 37 | fn test_mod_inverse() { 38 | let tests = [ 39 | ["1234567", "458948883992"], 40 | ["239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"], 41 | ["-10", "13"], 42 | ["-6193420858199668535", "2881"], 43 | ]; 44 | 45 | for test in &tests { 46 | let element = BigInt::parse_bytes(test[0].as_bytes(), 10).unwrap(); 47 | let modulus = BigInt::parse_bytes(test[1].as_bytes(), 10).unwrap(); 48 | 49 | //println!("{} modinv {}", element, modulus); 50 | let inverse = element.clone().mod_inverse(&modulus).unwrap(); 51 | //println!("inverse: {}", &inverse); 52 | let cmp = (inverse * &element).mod_floor(&modulus); 53 | 54 | assert_eq!( 55 | cmp, 56 | BigInt::one(), 57 | "mod_inverse({}, {}) * {} % {} = {}, not 1", 58 | &element, 59 | &modulus, 60 | &element, 61 | &modulus, 62 | &cmp 63 | ); 64 | } 65 | 66 | // exhaustive tests for small numbers 67 | for n in 2..100 { 68 | let modulus = BigInt::from_u64(n).unwrap(); 69 | for x in 1..n { 70 | for sign in vec![1i64, -1i64] { 71 | let element = BigInt::from_i64(sign * x as i64).unwrap(); 72 | let gcd = element.gcd(&modulus); 73 | 74 | if !gcd.is_one() { 75 | continue; 76 | } 77 | 78 | let inverse = element.clone().mod_inverse(&modulus).unwrap(); 79 | let cmp = (&inverse * &element).mod_floor(&modulus); 80 | //println!("inverse: {}", &inverse); 81 | assert_eq!( 82 | cmp, 83 | BigInt::one(), 84 | "mod_inverse({}, {}) * {} % {} = {}, not 1", 85 | &element, 86 | &modulus, 87 | &element, 88 | &modulus, 89 | &cmp 90 | ); 91 | } 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/algorithms/mul.rs: -------------------------------------------------------------------------------- 1 | use crate::algorithms::mac3; 2 | use crate::big_digit::{BigDigit, DoubleBigDigit, BITS}; 3 | use crate::BigUint; 4 | 5 | #[inline] 6 | pub fn mul_with_carry(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit { 7 | *acc += (a as DoubleBigDigit) * (b as DoubleBigDigit); 8 | let lo = *acc as BigDigit; 9 | *acc >>= BITS; 10 | lo 11 | } 12 | 13 | pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint { 14 | let len = x.len() + y.len() + 1; 15 | let mut prod = BigUint { 16 | data: smallvec![0; len], 17 | }; 18 | 19 | mac3(&mut prod.data[..], x, y); 20 | prod.normalized() 21 | } 22 | 23 | pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit { 24 | let mut carry = 0; 25 | for a in a.iter_mut() { 26 | *a = mul_with_carry(*a, b, &mut carry); 27 | } 28 | carry as BigDigit 29 | } 30 | -------------------------------------------------------------------------------- /src/algorithms/shl.rs: -------------------------------------------------------------------------------- 1 | use alloc::borrow::Cow; 2 | use core::iter::repeat; 3 | 4 | use smallvec::SmallVec; 5 | 6 | use crate::big_digit::BITS; 7 | use crate::BigUint; 8 | 9 | #[inline] 10 | pub fn biguint_shl(n: Cow, bits: usize) -> BigUint { 11 | let n_unit = bits / BITS; 12 | let mut data = match n_unit { 13 | 0 => n.into_owned().data, 14 | _ => { 15 | let len = n_unit + n.data.len() + 1; 16 | let mut data = SmallVec::with_capacity(len); 17 | data.extend(repeat(0).take(n_unit)); 18 | data.extend(n.data.iter().cloned()); 19 | data 20 | } 21 | }; 22 | 23 | let n_bits = bits % BITS; 24 | if n_bits > 0 { 25 | let mut carry = 0; 26 | for elem in data[n_unit..].iter_mut() { 27 | let new_carry = *elem >> (BITS - n_bits); 28 | *elem = (*elem << n_bits) | carry; 29 | carry = new_carry; 30 | } 31 | if carry != 0 { 32 | data.push(carry); 33 | } 34 | } 35 | 36 | BigUint::new_native(data) 37 | } 38 | -------------------------------------------------------------------------------- /src/algorithms/shr.rs: -------------------------------------------------------------------------------- 1 | use alloc::borrow::Cow; 2 | 3 | use num_traits::Zero; 4 | use smallvec::SmallVec; 5 | 6 | use crate::big_digit::{BigDigit, BITS}; 7 | use crate::BigUint; 8 | use crate::VEC_SIZE; 9 | 10 | #[inline] 11 | pub fn biguint_shr(n: Cow, bits: usize) -> BigUint { 12 | let n_unit = bits / BITS; 13 | if n_unit >= n.data.len() { 14 | return Zero::zero(); 15 | } 16 | let mut data: SmallVec<[BigDigit; VEC_SIZE]> = match n { 17 | Cow::Borrowed(n) => n.data[n_unit..].into(), 18 | Cow::Owned(n) => n.data[n_unit..].into(), 19 | }; 20 | 21 | let n_bits = bits % BITS; 22 | if n_bits > 0 { 23 | let mut borrow = 0; 24 | for elem in data.iter_mut().rev() { 25 | let new_borrow = *elem << (BITS - n_bits); 26 | *elem = (*elem >> n_bits) | borrow; 27 | borrow = new_borrow; 28 | } 29 | } 30 | 31 | BigUint::new_native(data) 32 | } 33 | -------------------------------------------------------------------------------- /src/algorithms/sub.rs: -------------------------------------------------------------------------------- 1 | use core::cmp; 2 | use core::cmp::Ordering::*; 3 | 4 | use num_traits::Zero; 5 | use smallvec::SmallVec; 6 | 7 | use crate::algorithms::cmp_slice; 8 | use crate::big_digit::{BigDigit, SignedDoubleBigDigit, BITS}; 9 | use crate::bigint::Sign::{self, *}; 10 | use crate::{BigUint, VEC_SIZE}; 11 | 12 | /// Subtract with borrow: 13 | #[inline] 14 | pub fn sbb(a: BigDigit, b: BigDigit, acc: &mut SignedDoubleBigDigit) -> BigDigit { 15 | *acc += a as SignedDoubleBigDigit; 16 | *acc -= b as SignedDoubleBigDigit; 17 | let lo = *acc as BigDigit; 18 | *acc >>= BITS; 19 | lo 20 | } 21 | 22 | pub fn sub2(a: &mut [BigDigit], b: &[BigDigit]) { 23 | let mut borrow = 0; 24 | 25 | let len = cmp::min(a.len(), b.len()); 26 | let (a_lo, a_hi) = a.split_at_mut(len); 27 | let (b_lo, b_hi) = b.split_at(len); 28 | 29 | for (a, b) in a_lo.iter_mut().zip(b_lo) { 30 | *a = sbb(*a, *b, &mut borrow); 31 | } 32 | 33 | if borrow != 0 { 34 | for a in a_hi { 35 | *a = sbb(*a, 0, &mut borrow); 36 | if borrow == 0 { 37 | break; 38 | } 39 | } 40 | } 41 | 42 | // note: we're _required_ to fail on underflow 43 | assert!( 44 | borrow == 0 && b_hi.iter().all(|x| *x == 0), 45 | "Cannot subtract b from a because b is larger than a." 46 | ); 47 | } 48 | 49 | // Only for the Sub impl. `a` and `b` must have same length. 50 | #[inline] 51 | pub fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> BigDigit { 52 | debug_assert!(b.len() == a.len()); 53 | 54 | let mut borrow = 0; 55 | 56 | for (ai, bi) in a.iter().zip(b) { 57 | *bi = sbb(*ai, *bi, &mut borrow); 58 | } 59 | 60 | borrow as BigDigit 61 | } 62 | 63 | pub fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) { 64 | debug_assert!(b.len() >= a.len()); 65 | 66 | let len = cmp::min(a.len(), b.len()); 67 | let (a_lo, a_hi) = a.split_at(len); 68 | let (b_lo, b_hi) = b.split_at_mut(len); 69 | 70 | let borrow = __sub2rev(a_lo, b_lo); 71 | 72 | assert!(a_hi.is_empty()); 73 | 74 | // note: we're _required_ to fail on underflow 75 | assert!( 76 | borrow == 0 && b_hi.iter().all(|x| *x == 0), 77 | "Cannot subtract b from a because b is larger than a." 78 | ); 79 | } 80 | 81 | pub fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) { 82 | // Normalize: 83 | let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)]; 84 | let b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)]; 85 | 86 | match cmp_slice(a, b) { 87 | Greater => { 88 | let mut a: SmallVec<[BigDigit; VEC_SIZE]> = a.into(); 89 | sub2(&mut a, b); 90 | (Plus, BigUint::new_native(a)) 91 | } 92 | Less => { 93 | let mut b: SmallVec<[BigDigit; VEC_SIZE]> = b.into(); 94 | sub2(&mut b, a); 95 | (Minus, BigUint::new_native(b)) 96 | } 97 | _ => (NoSign, Zero::zero()), 98 | } 99 | } 100 | 101 | #[cfg(test)] 102 | mod tests { 103 | use super::*; 104 | 105 | use num_traits::Num; 106 | 107 | use crate::BigInt; 108 | 109 | #[test] 110 | fn test_sub_sign() { 111 | fn sub_sign_i(a: &[BigDigit], b: &[BigDigit]) -> BigInt { 112 | let (sign, val) = sub_sign(a, b); 113 | BigInt::from_biguint(sign, val) 114 | } 115 | 116 | let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap(); 117 | let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap(); 118 | let a_i = BigInt::from_biguint(Plus, a.clone()); 119 | let b_i = BigInt::from_biguint(Plus, b.clone()); 120 | 121 | assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i); 122 | assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/bigrand.rs: -------------------------------------------------------------------------------- 1 | //! Randomization of big integers 2 | 3 | use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler}; 4 | use rand::prelude::*; 5 | use rand::Rng; 6 | 7 | use crate::BigInt; 8 | use crate::BigUint; 9 | use crate::Sign::*; 10 | 11 | use crate::big_digit::BigDigit; 12 | use crate::bigint::{into_magnitude, magnitude}; 13 | use crate::integer::Integer; 14 | #[cfg(feature = "prime")] 15 | use num_iter::range_step; 16 | use num_traits::Zero; 17 | #[cfg(feature = "prime")] 18 | use num_traits::{FromPrimitive, ToPrimitive}; 19 | 20 | #[cfg(feature = "prime")] 21 | use crate::prime::probably_prime; 22 | 23 | pub trait RandBigInt { 24 | /// Generate a random `BigUint` of the given bit size. 25 | fn gen_biguint(&mut self, bit_size: usize) -> BigUint; 26 | 27 | /// Generate a random BigInt of the given bit size. 28 | fn gen_bigint(&mut self, bit_size: usize) -> BigInt; 29 | 30 | /// Generate a random `BigUint` less than the given bound. Fails 31 | /// when the bound is zero. 32 | fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint; 33 | 34 | /// Generate a random `BigUint` within the given range. The lower 35 | /// bound is inclusive; the upper bound is exclusive. Fails when 36 | /// the upper bound is not greater than the lower bound. 37 | fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint; 38 | 39 | /// Generate a random `BigInt` within the given range. The lower 40 | /// bound is inclusive; the upper bound is exclusive. Fails when 41 | /// the upper bound is not greater than the lower bound. 42 | fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt; 43 | } 44 | 45 | impl RandBigInt for R { 46 | fn gen_biguint(&mut self, bit_size: usize) -> BigUint { 47 | use super::big_digit::BITS; 48 | let (digits, rem) = bit_size.div_rem(&BITS); 49 | let mut data = smallvec![BigDigit::default(); digits + (rem > 0) as usize]; 50 | 51 | // `fill` is faster than many `gen::` calls 52 | // Internally this calls `SeedableRng` where implementors are responsible for adjusting endianness for reproducable values. 53 | self.fill(data.as_mut_slice()); 54 | 55 | if rem > 0 { 56 | data[digits] >>= BITS - rem; 57 | } 58 | BigUint::new_native(data) 59 | } 60 | 61 | fn gen_bigint(&mut self, bit_size: usize) -> BigInt { 62 | loop { 63 | // Generate a random BigUint... 64 | let biguint = self.gen_biguint(bit_size); 65 | // ...and then randomly assign it a Sign... 66 | let sign = if biguint.is_zero() { 67 | // ...except that if the BigUint is zero, we need to try 68 | // again with probability 0.5. This is because otherwise, 69 | // the probability of generating a zero BigInt would be 70 | // double that of any other number. 71 | if self.gen() { 72 | continue; 73 | } else { 74 | NoSign 75 | } 76 | } else if self.gen() { 77 | Plus 78 | } else { 79 | Minus 80 | }; 81 | return BigInt::from_biguint(sign, biguint); 82 | } 83 | } 84 | 85 | fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint { 86 | assert!(!bound.is_zero()); 87 | let bits = bound.bits(); 88 | loop { 89 | let n = self.gen_biguint(bits); 90 | if n < *bound { 91 | return n; 92 | } 93 | } 94 | } 95 | 96 | fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint { 97 | assert!(*lbound < *ubound); 98 | if lbound.is_zero() { 99 | self.gen_biguint_below(ubound) 100 | } else { 101 | lbound + self.gen_biguint_below(&(ubound - lbound)) 102 | } 103 | } 104 | 105 | fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt { 106 | assert!(*lbound < *ubound); 107 | if lbound.is_zero() { 108 | BigInt::from(self.gen_biguint_below(magnitude(&ubound))) 109 | } else if ubound.is_zero() { 110 | lbound + BigInt::from(self.gen_biguint_below(magnitude(&lbound))) 111 | } else { 112 | let delta = ubound - lbound; 113 | lbound + BigInt::from(self.gen_biguint_below(magnitude(&delta))) 114 | } 115 | } 116 | } 117 | 118 | /// The back-end implementing rand's `UniformSampler` for `BigUint`. 119 | #[derive(Clone, Debug)] 120 | pub struct UniformBigUint { 121 | base: BigUint, 122 | len: BigUint, 123 | } 124 | 125 | impl UniformSampler for UniformBigUint { 126 | type X = BigUint; 127 | 128 | #[inline] 129 | fn new(low_b: B1, high_b: B2) -> Self 130 | where 131 | B1: SampleBorrow + Sized, 132 | B2: SampleBorrow + Sized, 133 | { 134 | let low = low_b.borrow(); 135 | let high = high_b.borrow(); 136 | 137 | assert!(low < high); 138 | 139 | UniformBigUint { 140 | len: high - low, 141 | base: low.clone(), 142 | } 143 | } 144 | 145 | #[inline] 146 | fn new_inclusive(low_b: B1, high_b: B2) -> Self 147 | where 148 | B1: SampleBorrow + Sized, 149 | B2: SampleBorrow + Sized, 150 | { 151 | Self::new(low_b, high_b.borrow() + 1u32) 152 | } 153 | 154 | #[inline] 155 | fn sample(&self, rng: &mut R) -> Self::X { 156 | &self.base + rng.gen_biguint_below(&self.len) 157 | } 158 | 159 | #[inline] 160 | fn sample_single(low_b: B1, high_b: B2, rng: &mut R) -> Self::X 161 | where 162 | B1: SampleBorrow + Sized, 163 | B2: SampleBorrow + Sized, 164 | { 165 | let low = low_b.borrow(); 166 | let high = high_b.borrow(); 167 | 168 | rng.gen_biguint_range(low, high) 169 | } 170 | } 171 | 172 | impl SampleUniform for BigUint { 173 | type Sampler = UniformBigUint; 174 | } 175 | 176 | /// The back-end implementing rand's `UniformSampler` for `BigInt`. 177 | #[derive(Clone, Debug)] 178 | pub struct UniformBigInt { 179 | base: BigInt, 180 | len: BigUint, 181 | } 182 | 183 | impl UniformSampler for UniformBigInt { 184 | type X = BigInt; 185 | 186 | #[inline] 187 | fn new(low_b: B1, high_b: B2) -> Self 188 | where 189 | B1: SampleBorrow + Sized, 190 | B2: SampleBorrow + Sized, 191 | { 192 | let low = low_b.borrow(); 193 | let high = high_b.borrow(); 194 | 195 | assert!(low < high); 196 | UniformBigInt { 197 | len: into_magnitude(high - low), 198 | base: low.clone(), 199 | } 200 | } 201 | 202 | #[inline] 203 | fn new_inclusive(low_b: B1, high_b: B2) -> Self 204 | where 205 | B1: SampleBorrow + Sized, 206 | B2: SampleBorrow + Sized, 207 | { 208 | let low = low_b.borrow(); 209 | let high = high_b.borrow(); 210 | 211 | assert!(low <= high); 212 | Self::new(low, high + 1u32) 213 | } 214 | 215 | #[inline] 216 | fn sample(&self, rng: &mut R) -> Self::X { 217 | &self.base + BigInt::from(rng.gen_biguint_below(&self.len)) 218 | } 219 | 220 | #[inline] 221 | fn sample_single(low_b: B1, high_b: B2, rng: &mut R) -> Self::X 222 | where 223 | B1: SampleBorrow + Sized, 224 | B2: SampleBorrow + Sized, 225 | { 226 | let low = low_b.borrow(); 227 | let high = high_b.borrow(); 228 | 229 | rng.gen_bigint_range(low, high) 230 | } 231 | } 232 | 233 | impl SampleUniform for BigInt { 234 | type Sampler = UniformBigInt; 235 | } 236 | 237 | /// A random distribution for `BigUint` and `BigInt` values of a particular bit size. 238 | #[derive(Clone, Copy, Debug)] 239 | pub struct RandomBits { 240 | bits: usize, 241 | } 242 | 243 | impl RandomBits { 244 | #[inline] 245 | pub fn new(bits: usize) -> RandomBits { 246 | RandomBits { bits } 247 | } 248 | } 249 | 250 | impl Distribution for RandomBits { 251 | #[inline] 252 | fn sample(&self, rng: &mut R) -> BigUint { 253 | rng.gen_biguint(self.bits) 254 | } 255 | } 256 | 257 | impl Distribution for RandomBits { 258 | #[inline] 259 | fn sample(&self, rng: &mut R) -> BigInt { 260 | rng.gen_bigint(self.bits) 261 | } 262 | } 263 | 264 | /// A generic trait for generating random primes. 265 | /// 266 | /// *Warning*: This is highly dependend on the provided random number generator, 267 | /// to provide actually random primes. 268 | /// 269 | /// # Example 270 | #[cfg_attr(feature = "std", doc = " ```")] 271 | #[cfg_attr(not(feature = "std"), doc = " ```ignore")] 272 | /// extern crate rand; 273 | /// extern crate num_bigint_dig as num_bigint; 274 | /// 275 | /// use rand::thread_rng; 276 | /// use num_bigint::RandPrime; 277 | /// 278 | /// let mut rng = thread_rng(); 279 | /// let p = rng.gen_prime(1024); 280 | /// assert_eq!(p.bits(), 1024); 281 | /// ``` 282 | /// 283 | #[cfg(feature = "prime")] 284 | pub trait RandPrime { 285 | /// Generate a random prime number with as many bits as given. 286 | fn gen_prime(&mut self, bits: usize) -> BigUint; 287 | } 288 | 289 | /// A list of small, prime numbers that allows us to rapidly 290 | /// exclude some fraction of composite candidates when searching for a random 291 | /// prime. This list is truncated at the point where smallPrimesProduct exceeds 292 | /// a u64. It does not include two because we ensure that the candidates are 293 | /// odd by construction. 294 | #[cfg(feature = "prime")] 295 | const SMALL_PRIMES: [u8; 15] = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]; 296 | 297 | #[cfg(feature = "prime")] 298 | lazy_static! { 299 | /// The product of the values in SMALL_PRIMES and allows us 300 | /// to reduce a candidate prime by this number and then determine whether it's 301 | /// coprime to all the elements of SMALL_PRIMES without further BigUint 302 | /// operations. 303 | static ref SMALL_PRIMES_PRODUCT: BigUint = BigUint::from_u64(16_294_579_238_595_022_365).unwrap(); 304 | } 305 | 306 | #[cfg(feature = "prime")] 307 | impl RandPrime for R { 308 | fn gen_prime(&mut self, bit_size: usize) -> BigUint { 309 | if bit_size < 2 { 310 | panic!("prime size must be at least 2-bit"); 311 | } 312 | 313 | let mut b = bit_size % 8; 314 | if b == 0 { 315 | b = 8; 316 | } 317 | 318 | let bytes_len = (bit_size + 7) / 8; 319 | let mut bytes = vec![0u8; bytes_len]; 320 | 321 | loop { 322 | self.fill_bytes(&mut bytes); 323 | // Clear bits in the first byte to make sure the candidate has a size <= bits. 324 | bytes[0] &= ((1u32 << (b as u32)) - 1) as u8; 325 | 326 | // Don't let the value be too small, i.e, set the most significant two bits. 327 | // Setting the top two bits, rather than just the top bit, 328 | // means that when two of these values are multiplied together, 329 | // the result isn't ever one bit short. 330 | if b >= 2 { 331 | bytes[0] |= 3u8.wrapping_shl(b as u32 - 2); 332 | } else { 333 | // Here b==1, because b cannot be zero. 334 | bytes[0] |= 1; 335 | if bytes_len > 1 { 336 | bytes[1] |= 0x80; 337 | } 338 | } 339 | 340 | // Make the value odd since an even number this large certainly isn't prime. 341 | bytes[bytes_len - 1] |= 1u8; 342 | 343 | let mut p = BigUint::from_bytes_be(&bytes); 344 | // must always be a u64, as the SMALL_PRIMES_PRODUCT is a u64 345 | let rem = (&p % &*SMALL_PRIMES_PRODUCT).to_u64().unwrap(); 346 | 347 | 'next: for delta in range_step(0, 1 << 20, 2) { 348 | let m = rem + delta; 349 | 350 | for prime in &SMALL_PRIMES { 351 | if m % u64::from(*prime) == 0 && (bit_size > 6 || m != u64::from(*prime)) { 352 | continue 'next; 353 | } 354 | } 355 | 356 | if delta > 0 { 357 | p += BigUint::from_u64(delta).unwrap(); 358 | } 359 | 360 | break; 361 | } 362 | 363 | // There is a tiny possibility that, by adding delta, we caused 364 | // the number to be one bit too long. Thus we check bit length here. 365 | if p.bits() == bit_size && probably_prime(&p, 20) { 366 | return p; 367 | } 368 | } 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stichting Organism 2 | // 3 | // Copyright 2018 Friedel Ziegelmayer 4 | // 5 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 6 | // file at the top-level directory of this distribution and at 7 | // http://rust-lang.org/COPYRIGHT. 8 | // 9 | // Licensed under the Apache License, Version 2.0 or the MIT license 11 | // , at your 12 | // option. This file may not be copied, modified, or distributed 13 | // except according to those terms. 14 | 15 | //! A Big integer (signed version: `BigInt`, unsigned version: `BigUint`). 16 | //! 17 | //! A `BigUint` is represented as a vector of `BigDigit`s. 18 | //! A `BigInt` is a combination of `BigUint` and `Sign`. 19 | //! 20 | //! Common numerical operations are overloaded, so we can treat them 21 | //! the same way we treat other numbers. 22 | //! 23 | //! ## Example 24 | //! 25 | //! ```rust 26 | //! extern crate num_bigint_dig as num_bigint; 27 | //! extern crate num_traits; 28 | //! 29 | //! # fn main() { 30 | //! use num_bigint::BigUint; 31 | //! use num_traits::{Zero, One}; 32 | //! use std::mem::replace; 33 | //! 34 | //! // Calculate large fibonacci numbers. 35 | //! fn fib(n: usize) -> BigUint { 36 | //! let mut f0: BigUint = Zero::zero(); 37 | //! let mut f1: BigUint = One::one(); 38 | //! for _ in 0..n { 39 | //! let f2 = f0 + &f1; 40 | //! // This is a low cost way of swapping f0 with f1 and f1 with f2. 41 | //! f0 = replace(&mut f1, f2); 42 | //! } 43 | //! f0 44 | //! } 45 | //! 46 | //! // This is a very large number. 47 | //! //println!("fib(1000) = {}", fib(1000)); 48 | //! # } 49 | //! ``` 50 | //! 51 | //! It's easy to generate large random numbers: 52 | //! 53 | #![cfg_attr(feature = "std", doc = " ```")] 54 | #![cfg_attr(not(feature = "std"), doc = " ```ignore")] 55 | //! 56 | //! # #[cfg(feature = "rand")] 57 | //! extern crate rand; 58 | //! extern crate num_bigint_dig as bigint; 59 | //! 60 | //! # #[cfg(feature = "rand")] 61 | //! # fn main() { 62 | //! use bigint::{ToBigInt, RandBigInt}; 63 | //! 64 | //! let mut rng = rand::thread_rng(); 65 | //! let a = rng.gen_bigint(1000); 66 | //! 67 | //! let low = -10000.to_bigint().unwrap(); 68 | //! let high = 10000.to_bigint().unwrap(); 69 | //! let b = rng.gen_bigint_range(&low, &high); 70 | //! 71 | //! // Probably an even larger number. 72 | //! //println!("{}", a * b); 73 | //! # } 74 | //! 75 | //! # #[cfg(not(feature = "rand"))] 76 | //! # fn main() { 77 | //! # } 78 | //! ``` 79 | //! 80 | //! ## Compatibility 81 | //! 82 | //! The `num-bigint-dig` crate is tested for rustc 1.56 and greater. 83 | //! 84 | //! ## `no_std` compatibility 85 | //! 86 | //! This crate is compatible with `no_std` environments. 87 | //! 88 | //! Note however that it still requires the `alloc` crate, so the user should 89 | //! ensure that they set a `global_allocator`. 90 | //! 91 | //! To use in no_std environment, add the crate as such in your `Cargo.toml` 92 | //! file: 93 | //! 94 | //! ```toml 95 | //! [dependencies] 96 | //! num-bigint-dig = { version = "0.8", default-features=false } 97 | //! ``` 98 | //! 99 | //! Every features should be compatible with no_std environment, so feel free to 100 | //! add features like `prime`, `i128`, etc... 101 | 102 | #![doc(html_root_url = "https://docs.rs/num-bigint/0.2")] 103 | #![no_std] 104 | 105 | extern crate alloc; 106 | 107 | #[cfg(feature = "std")] 108 | extern crate std; 109 | 110 | #[macro_use] 111 | extern crate smallvec; 112 | 113 | #[cfg(feature = "prime")] 114 | #[macro_use] 115 | extern crate lazy_static; 116 | 117 | extern crate num_integer as integer; 118 | 119 | use core::fmt; 120 | #[cfg(feature = "std")] 121 | use std::error::Error; 122 | 123 | #[macro_use] 124 | mod macros; 125 | 126 | mod bigint; 127 | mod biguint; 128 | 129 | #[cfg(feature = "prime")] 130 | pub mod prime; 131 | 132 | pub mod algorithms; 133 | pub mod traits; 134 | 135 | pub use crate::traits::*; 136 | 137 | #[cfg(feature = "rand")] 138 | mod bigrand; 139 | 140 | #[cfg(target_pointer_width = "32")] 141 | type UsizePromotion = u32; 142 | #[cfg(target_pointer_width = "64")] 143 | type UsizePromotion = u64; 144 | 145 | #[cfg(target_pointer_width = "32")] 146 | type IsizePromotion = i32; 147 | #[cfg(target_pointer_width = "64")] 148 | type IsizePromotion = i64; 149 | 150 | #[derive(Debug, Clone, PartialEq, Eq)] 151 | pub struct ParseBigIntError { 152 | kind: BigIntErrorKind, 153 | } 154 | 155 | #[derive(Debug, Clone, PartialEq, Eq)] 156 | enum BigIntErrorKind { 157 | Empty, 158 | InvalidDigit, 159 | } 160 | 161 | impl ParseBigIntError { 162 | fn __description(&self) -> &str { 163 | use crate::BigIntErrorKind::*; 164 | match self.kind { 165 | Empty => "cannot parse integer from empty string", 166 | InvalidDigit => "invalid digit found in string", 167 | } 168 | } 169 | 170 | fn empty() -> Self { 171 | ParseBigIntError { 172 | kind: BigIntErrorKind::Empty, 173 | } 174 | } 175 | 176 | fn invalid() -> Self { 177 | ParseBigIntError { 178 | kind: BigIntErrorKind::InvalidDigit, 179 | } 180 | } 181 | } 182 | 183 | impl fmt::Display for ParseBigIntError { 184 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 185 | self.__description().fmt(f) 186 | } 187 | } 188 | 189 | #[cfg(feature = "std")] 190 | impl Error for ParseBigIntError { 191 | fn description(&self) -> &str { 192 | self.__description() 193 | } 194 | } 195 | 196 | pub use crate::biguint::BigUint; 197 | pub use crate::biguint::IntoBigUint; 198 | pub use crate::biguint::ToBigUint; 199 | 200 | pub use crate::bigint::negate_sign; 201 | pub use crate::bigint::BigInt; 202 | pub use crate::bigint::IntoBigInt; 203 | pub use crate::bigint::Sign; 204 | pub use crate::bigint::ToBigInt; 205 | 206 | #[cfg(feature = "rand")] 207 | pub use crate::bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint}; 208 | 209 | #[cfg(feature = "prime")] 210 | pub use bigrand::RandPrime; 211 | 212 | #[cfg(not(feature = "u64_digit"))] 213 | pub const VEC_SIZE: usize = 8; 214 | 215 | #[cfg(feature = "u64_digit")] 216 | pub const VEC_SIZE: usize = 4; 217 | 218 | mod big_digit { 219 | /// A `BigDigit` is a `BigUint`'s composing element. 220 | #[cfg(not(feature = "u64_digit"))] 221 | pub type BigDigit = u32; 222 | #[cfg(feature = "u64_digit")] 223 | pub type BigDigit = u64; 224 | 225 | /// A `DoubleBigDigit` is the internal type used to do the computations. Its 226 | /// size is the double of the size of `BigDigit`. 227 | #[cfg(not(feature = "u64_digit"))] 228 | pub type DoubleBigDigit = u64; 229 | #[cfg(feature = "u64_digit")] 230 | pub type DoubleBigDigit = u128; 231 | 232 | /// A `SignedDoubleBigDigit` is the signed version of `DoubleBigDigit`. 233 | #[cfg(not(feature = "u64_digit"))] 234 | pub type SignedDoubleBigDigit = i64; 235 | #[cfg(feature = "u64_digit")] 236 | pub type SignedDoubleBigDigit = i128; 237 | 238 | // `DoubleBigDigit` size dependent 239 | #[cfg(not(feature = "u64_digit"))] 240 | pub const BITS: usize = 32; 241 | #[cfg(feature = "u64_digit")] 242 | pub const BITS: usize = 64; 243 | 244 | #[cfg(not(feature = "u64_digit"))] 245 | const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS; 246 | #[cfg(feature = "u64_digit")] 247 | const LO_MASK: DoubleBigDigit = (-1i64 as DoubleBigDigit) >> BITS; 248 | 249 | #[inline] 250 | fn get_hi(n: DoubleBigDigit) -> BigDigit { 251 | (n >> BITS) as BigDigit 252 | } 253 | #[inline] 254 | fn get_lo(n: DoubleBigDigit) -> BigDigit { 255 | (n & LO_MASK) as BigDigit 256 | } 257 | 258 | /// Split one `DoubleBigDigit` into two `BigDigit`s. 259 | #[inline] 260 | pub fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) { 261 | (get_hi(n), get_lo(n)) 262 | } 263 | 264 | /// Join two `BigDigit`s into one `DoubleBigDigit` 265 | #[inline] 266 | pub fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit { 267 | (DoubleBigDigit::from(lo)) | ((DoubleBigDigit::from(hi)) << BITS) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/macro.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dignifiedquire/num-bigint/6f73f0a4025164325e85f8645dad6712b3110c51/src/macro.rs -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | #![allow(unknown_lints)] // older rustc doesn't know `unused_macros` 2 | #![allow(unused_macros)] 3 | 4 | macro_rules! forward_val_val_binop { 5 | (impl $imp:ident for $res:ty, $method:ident) => { 6 | impl $imp<$res> for $res { 7 | type Output = $res; 8 | 9 | #[inline] 10 | fn $method(self, other: $res) -> $res { 11 | // forward to val-ref 12 | $imp::$method(self, &other) 13 | } 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! forward_val_val_binop_commutative { 19 | (impl $imp:ident for $res:ty, $method:ident) => { 20 | impl $imp<$res> for $res { 21 | type Output = $res; 22 | 23 | #[inline] 24 | fn $method(self, other: $res) -> $res { 25 | // forward to val-ref, with the larger capacity as val 26 | if self.capacity() >= other.capacity() { 27 | $imp::$method(self, &other) 28 | } else { 29 | $imp::$method(other, &self) 30 | } 31 | } 32 | } 33 | }; 34 | } 35 | 36 | macro_rules! forward_ref_val_binop { 37 | (impl $imp:ident for $res:ty, $method:ident) => { 38 | impl<'a> $imp<$res> for &'a $res { 39 | type Output = $res; 40 | 41 | #[inline] 42 | fn $method(self, other: $res) -> $res { 43 | // forward to ref-ref 44 | $imp::$method(self, &other) 45 | } 46 | } 47 | }; 48 | } 49 | 50 | macro_rules! forward_ref_val_binop_commutative { 51 | (impl $imp:ident for $res:ty, $method:ident) => { 52 | impl<'a> $imp<$res> for &'a $res { 53 | type Output = $res; 54 | 55 | #[inline] 56 | fn $method(self, other: $res) -> $res { 57 | // reverse, forward to val-ref 58 | $imp::$method(other, self) 59 | } 60 | } 61 | }; 62 | } 63 | 64 | macro_rules! forward_val_ref_binop { 65 | (impl $imp:ident for $res:ty, $method:ident) => { 66 | impl<'a> $imp<&'a $res> for $res { 67 | type Output = $res; 68 | 69 | #[inline] 70 | fn $method(self, other: &$res) -> $res { 71 | // forward to ref-ref 72 | $imp::$method(&self, other) 73 | } 74 | } 75 | }; 76 | } 77 | 78 | macro_rules! forward_ref_ref_binop { 79 | (impl $imp:ident for $res:ty, $method:ident) => { 80 | impl<'a, 'b> $imp<&'b $res> for &'a $res { 81 | type Output = $res; 82 | 83 | #[inline] 84 | fn $method(self, other: &$res) -> $res { 85 | // forward to val-ref 86 | $imp::$method(self.clone(), other) 87 | } 88 | } 89 | }; 90 | } 91 | 92 | macro_rules! forward_ref_ref_binop_commutative { 93 | (impl $imp:ident for $res:ty, $method:ident) => { 94 | impl<'a, 'b> $imp<&'b $res> for &'a $res { 95 | type Output = $res; 96 | 97 | #[inline] 98 | fn $method(self, other: &$res) -> $res { 99 | // forward to val-ref, choosing the larger to clone 100 | if self.len() >= other.len() { 101 | $imp::$method(self.clone(), other) 102 | } else { 103 | $imp::$method(other.clone(), self) 104 | } 105 | } 106 | } 107 | }; 108 | } 109 | 110 | macro_rules! forward_val_assign { 111 | (impl $imp:ident for $res:ty, $method:ident) => { 112 | impl $imp<$res> for $res { 113 | #[inline] 114 | fn $method(&mut self, other: $res) { 115 | self.$method(&other); 116 | } 117 | } 118 | }; 119 | } 120 | macro_rules! forward_val_assign_scalar { 121 | (impl $imp:ident for $res:ty, $scalar:ty, $method:ident) => { 122 | impl $imp<$res> for $scalar { 123 | #[inline] 124 | fn $method(&mut self, other: $res) { 125 | self.$method(&other); 126 | } 127 | } 128 | }; 129 | } 130 | 131 | macro_rules! forward_scalar_val_val_binop_commutative { 132 | (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => { 133 | impl $imp<$res> for $scalar { 134 | type Output = $res; 135 | 136 | #[inline] 137 | fn $method(self, other: $res) -> $res { 138 | $imp::$method(other, self) 139 | } 140 | } 141 | }; 142 | } 143 | 144 | macro_rules! forward_scalar_val_ref_binop { 145 | (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => { 146 | impl<'a> $imp<&'a $scalar> for $res { 147 | type Output = $res; 148 | 149 | #[inline] 150 | fn $method(self, other: &$scalar) -> $res { 151 | $imp::$method(self, *other) 152 | } 153 | } 154 | 155 | impl<'a> $imp<$res> for &'a $scalar { 156 | type Output = $res; 157 | 158 | #[inline] 159 | fn $method(self, other: $res) -> $res { 160 | $imp::$method(*self, other) 161 | } 162 | } 163 | }; 164 | } 165 | 166 | macro_rules! forward_scalar_ref_val_binop { 167 | (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => { 168 | impl<'a> $imp<$scalar> for &'a $res { 169 | type Output = $res; 170 | 171 | #[inline] 172 | fn $method(self, other: $scalar) -> $res { 173 | $imp::$method(self.clone(), other) 174 | } 175 | } 176 | 177 | impl<'a> $imp<&'a $res> for $scalar { 178 | type Output = $res; 179 | 180 | #[inline] 181 | fn $method(self, other: &$res) -> $res { 182 | $imp::$method(self, other.clone()) 183 | } 184 | } 185 | }; 186 | } 187 | 188 | macro_rules! forward_scalar_ref_ref_binop { 189 | (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => { 190 | impl<'a, 'b> $imp<&'b $scalar> for &'a $res { 191 | type Output = $res; 192 | 193 | #[inline] 194 | fn $method(self, other: &$scalar) -> $res { 195 | $imp::$method(self.clone(), *other) 196 | } 197 | } 198 | 199 | impl<'a, 'b> $imp<&'a $res> for &'b $scalar { 200 | type Output = $res; 201 | 202 | #[inline] 203 | fn $method(self, other: &$res) -> $res { 204 | $imp::$method(*self, other.clone()) 205 | } 206 | } 207 | }; 208 | } 209 | 210 | macro_rules! promote_scalars { 211 | (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => { 212 | $( 213 | forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method); 214 | 215 | impl $imp<$scalar> for $res { 216 | type Output = $res; 217 | 218 | #[inline] 219 | fn $method(self, other: $scalar) -> $res { 220 | $imp::$method(self, other as $promo) 221 | } 222 | } 223 | 224 | impl $imp<$res> for $scalar { 225 | type Output = $res; 226 | 227 | #[inline] 228 | fn $method(self, other: $res) -> $res { 229 | $imp::$method(self as $promo, other) 230 | } 231 | } 232 | )* 233 | } 234 | } 235 | macro_rules! promote_scalars_assign { 236 | (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => { 237 | $( 238 | impl $imp<$scalar> for $res { 239 | #[inline] 240 | fn $method(&mut self, other: $scalar) { 241 | self.$method(other as $promo); 242 | } 243 | } 244 | )* 245 | } 246 | } 247 | 248 | macro_rules! promote_unsigned_scalars { 249 | (impl $imp:ident for $res:ty, $method:ident) => { 250 | promote_scalars!(impl $imp for $res, $method, u8, u16); 251 | promote_scalars!(impl $imp for $res, $method, usize); 252 | } 253 | } 254 | 255 | macro_rules! promote_unsigned_scalars_assign { 256 | (impl $imp:ident for $res:ty, $method:ident) => { 257 | promote_scalars_assign!(impl $imp for $res, $method, u8, u16); 258 | promote_scalars_assign!(impl $imp for $res, $method, usize); 259 | } 260 | } 261 | 262 | macro_rules! promote_signed_scalars { 263 | (impl $imp:ident for $res:ty, $method:ident) => { 264 | promote_scalars!(impl $imp for $res, $method, i8, i16); 265 | promote_scalars!(impl $imp for $res, $method, isize); 266 | } 267 | } 268 | 269 | macro_rules! promote_signed_scalars_assign { 270 | (impl $imp:ident for $res:ty, $method:ident) => { 271 | promote_scalars_assign!(impl $imp for $res, $method, i8, i16); 272 | promote_scalars_assign!(impl $imp for $res, $method, isize); 273 | } 274 | } 275 | 276 | // Forward everything to ref-ref, when reusing storage is not helpful 277 | macro_rules! forward_all_binop_to_ref_ref { 278 | (impl $imp:ident for $res:ty, $method:ident) => { 279 | forward_val_val_binop!(impl $imp for $res, $method); 280 | forward_val_ref_binop!(impl $imp for $res, $method); 281 | forward_ref_val_binop!(impl $imp for $res, $method); 282 | }; 283 | } 284 | 285 | // Forward everything to val-ref, so LHS storage can be reused 286 | macro_rules! forward_all_binop_to_val_ref { 287 | (impl $imp:ident for $res:ty, $method:ident) => { 288 | forward_val_val_binop!(impl $imp for $res, $method); 289 | forward_ref_val_binop!(impl $imp for $res, $method); 290 | forward_ref_ref_binop!(impl $imp for $res, $method); 291 | }; 292 | } 293 | 294 | // Forward everything to val-ref, commutatively, so either LHS or RHS storage can be reused 295 | macro_rules! forward_all_binop_to_val_ref_commutative { 296 | (impl $imp:ident for $res:ty, $method:ident) => { 297 | forward_val_val_binop_commutative!(impl $imp for $res, $method); 298 | forward_ref_val_binop_commutative!(impl $imp for $res, $method); 299 | forward_ref_ref_binop_commutative!(impl $imp for $res, $method); 300 | }; 301 | } 302 | 303 | macro_rules! forward_all_scalar_binop_to_val_val { 304 | (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { 305 | forward_scalar_val_ref_binop!(impl $imp<$scalar> for $res, $method); 306 | forward_scalar_ref_val_binop!(impl $imp<$scalar> for $res, $method); 307 | forward_scalar_ref_ref_binop!(impl $imp<$scalar> for $res, $method); 308 | } 309 | } 310 | 311 | macro_rules! forward_all_scalar_binop_to_val_val_commutative { 312 | (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { 313 | forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method); 314 | forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method); 315 | } 316 | } 317 | 318 | macro_rules! promote_all_scalars { 319 | (impl $imp:ident for $res:ty, $method:ident) => { 320 | promote_unsigned_scalars!(impl $imp for $res, $method); 321 | promote_signed_scalars!(impl $imp for $res, $method); 322 | } 323 | } 324 | 325 | macro_rules! promote_all_scalars_assign { 326 | (impl $imp:ident for $res:ty, $method:ident) => { 327 | promote_unsigned_scalars_assign!(impl $imp for $res, $method); 328 | promote_signed_scalars_assign!(impl $imp for $res, $method); 329 | } 330 | } 331 | 332 | macro_rules! impl_sum_iter_type { 333 | ($res:ty) => { 334 | impl Sum for $res 335 | where 336 | $res: Add, 337 | { 338 | fn sum(iter: I) -> Self 339 | where 340 | I: Iterator, 341 | { 342 | iter.fold(Zero::zero(), <$res>::add) 343 | } 344 | } 345 | }; 346 | } 347 | 348 | macro_rules! impl_product_iter_type { 349 | ($res:ty) => { 350 | impl Product for $res 351 | where 352 | $res: Mul, 353 | { 354 | fn product(iter: I) -> Self 355 | where 356 | I: Iterator, 357 | { 358 | iter.fold(One::one(), <$res>::mul) 359 | } 360 | } 361 | }; 362 | } 363 | -------------------------------------------------------------------------------- /src/monty.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::many_single_char_names)] 2 | 3 | use alloc::vec::Vec; 4 | use core::ops::Shl; 5 | use num_traits::{One, Zero}; 6 | 7 | use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit}; 8 | use crate::biguint::BigUint; 9 | 10 | struct MontyReducer { 11 | n0inv: BigDigit, 12 | } 13 | 14 | // k0 = -m**-1 mod 2**BITS. Algorithm from: Dumas, J.G. "On Newton–Raphson 15 | // Iteration for Multiplicative Inverses Modulo Prime Powers". 16 | fn inv_mod_alt(b: BigDigit) -> BigDigit { 17 | assert_ne!(b & 1, 0); 18 | 19 | let mut k0 = 2 - b as SignedDoubleBigDigit; 20 | let mut t = (b - 1) as SignedDoubleBigDigit; 21 | let mut i = 1; 22 | while i < big_digit::BITS { 23 | t = t.wrapping_mul(t); 24 | k0 = k0.wrapping_mul(t + 1); 25 | 26 | i <<= 1; 27 | } 28 | -k0 as BigDigit 29 | } 30 | 31 | impl MontyReducer { 32 | fn new(n: &BigUint) -> Self { 33 | let n0inv = inv_mod_alt(n.data[0]); 34 | MontyReducer { n0inv } 35 | } 36 | } 37 | 38 | /// Computes z mod m = x * y * 2 ** (-n*_W) mod m 39 | /// assuming k = -1/m mod 2**_W 40 | /// See Gueron, "Efficient Software Implementations of Modular Exponentiation". 41 | /// https://eprint.iacr.org/2011/239.pdf 42 | /// In the terminology of that paper, this is an "Almost Montgomery Multiplication": 43 | /// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result 44 | /// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m. 45 | fn montgomery(z: &mut BigUint, x: &BigUint, y: &BigUint, m: &BigUint, k: BigDigit, n: usize) { 46 | // This code assumes x, y, m are all the same length, n. 47 | // (required by addMulVVW and the for loop). 48 | // It also assumes that x, y are already reduced mod m, 49 | // or else the result will not be properly reduced. 50 | assert!( 51 | x.data.len() == n && y.data.len() == n && m.data.len() == n, 52 | "{:?} {:?} {:?} {}", 53 | x, 54 | y, 55 | m, 56 | n 57 | ); 58 | 59 | z.data.clear(); 60 | z.data.resize(n * 2, 0); 61 | 62 | let mut c: BigDigit = 0; 63 | 64 | for i in 0..n { 65 | let c2 = add_mul_vvw(&mut z.data[i..n + i], &x.data, y.data[i]); 66 | let t = z.data[i].wrapping_mul(k); 67 | let c3 = add_mul_vvw(&mut z.data[i..n + i], &m.data, t); 68 | let cx = c.wrapping_add(c2); 69 | let cy = cx.wrapping_add(c3); 70 | z.data[n + i] = cy; 71 | c = if cx < c2 || cy < c3 { 1 } else { 0 }; 72 | } 73 | 74 | if c == 0 { 75 | let (first, second) = z.data.split_at_mut(n); 76 | first.swap_with_slice(&mut second[..]); 77 | } else { 78 | let (mut first, second) = z.data.split_at_mut(n); 79 | sub_vv(&mut first, &second, &m.data); 80 | } 81 | z.data.truncate(n); 82 | } 83 | 84 | #[inline] 85 | fn add_mul_vvw(z: &mut [BigDigit], x: &[BigDigit], y: BigDigit) -> BigDigit { 86 | let mut c = 0; 87 | for (zi, xi) in z.iter_mut().zip(x.iter()) { 88 | let (z1, z0) = mul_add_www(*xi, y, *zi); 89 | let (c_, zi_) = add_ww(z0, c, 0); 90 | *zi = zi_; 91 | c = c_ + z1; 92 | } 93 | 94 | c 95 | } 96 | 97 | /// The resulting carry c is either 0 or 1. 98 | #[inline] 99 | fn sub_vv(z: &mut [BigDigit], x: &[BigDigit], y: &[BigDigit]) -> BigDigit { 100 | let mut c = 0; 101 | for (i, (xi, yi)) in x.iter().zip(y.iter()).enumerate().take(z.len()) { 102 | let zi = xi.wrapping_sub(*yi).wrapping_sub(c); 103 | z[i] = zi; 104 | // see "Hacker's Delight", section 2-12 (overflow detection) 105 | c = ((yi & !xi) | ((yi | !xi) & zi)) >> (big_digit::BITS - 1) 106 | } 107 | 108 | c 109 | } 110 | 111 | /// z1<<_W + z0 = x+y+c, with c == 0 or 1 112 | #[inline] 113 | fn add_ww(x: BigDigit, y: BigDigit, c: BigDigit) -> (BigDigit, BigDigit) { 114 | let yc = y.wrapping_add(c); 115 | let z0 = x.wrapping_add(yc); 116 | let z1 = if z0 < x || yc < y { 1 } else { 0 }; 117 | 118 | (z1, z0) 119 | } 120 | 121 | /// z1 << _W + z0 = x * y + c 122 | #[inline] 123 | fn mul_add_www(x: BigDigit, y: BigDigit, c: BigDigit) -> (BigDigit, BigDigit) { 124 | let z = x as DoubleBigDigit * y as DoubleBigDigit + c as DoubleBigDigit; 125 | ((z >> big_digit::BITS) as BigDigit, z as BigDigit) 126 | } 127 | 128 | /// Calculates x ** y mod m using a fixed, 4-bit window. 129 | pub fn monty_modpow(x: &BigUint, y: &BigUint, m: &BigUint) -> BigUint { 130 | assert!(m.data[0] & 1 == 1); 131 | let mr = MontyReducer::new(m); 132 | let num_words = m.data.len(); 133 | 134 | let mut x = x.clone(); 135 | 136 | // We want the lengths of x and m to be equal. 137 | // It is OK if x >= m as long as len(x) == len(m). 138 | if x.data.len() > num_words { 139 | x %= m; 140 | // Note: now len(x) <= numWords, not guaranteed ==. 141 | } 142 | if x.data.len() < num_words { 143 | x.data.resize(num_words, 0); 144 | } 145 | 146 | // rr = 2**(2*_W*len(m)) mod m 147 | let mut rr = BigUint::one(); 148 | rr = (rr.shl(2 * num_words * big_digit::BITS)) % m; 149 | if rr.data.len() < num_words { 150 | rr.data.resize(num_words, 0); 151 | } 152 | // one = 1, with equal length to that of m 153 | let mut one = BigUint::one(); 154 | one.data.resize(num_words, 0); 155 | 156 | let n = 4; 157 | // powers[i] contains x^i 158 | let mut powers = Vec::with_capacity(1 << n); 159 | 160 | let mut v1 = BigUint::zero(); 161 | montgomery(&mut v1, &one, &rr, m, mr.n0inv, num_words); 162 | powers.push(v1); 163 | let mut v2 = BigUint::zero(); 164 | montgomery(&mut v2, &x, &rr, m, mr.n0inv, num_words); 165 | powers.push(v2); 166 | for i in 2..1 << n { 167 | let mut r = BigUint::zero(); 168 | montgomery(&mut r, &powers[i - 1], &powers[1], m, mr.n0inv, num_words); 169 | powers.push(r); 170 | } 171 | 172 | // initialize z = 1 (Montgomery 1) 173 | let mut z = powers[0].clone(); 174 | z.data.resize(num_words, 0); 175 | let mut zz = BigUint::zero(); 176 | zz.data.resize(num_words, 0); 177 | 178 | // same windowed exponent, but with Montgomery multiplications 179 | for i in (0..y.data.len()).rev() { 180 | let mut yi = y.data[i]; 181 | let mut j = 0; 182 | while j < big_digit::BITS { 183 | if i != y.data.len() - 1 || j != 0 { 184 | montgomery(&mut zz, &z, &z, m, mr.n0inv, num_words); 185 | montgomery(&mut z, &zz, &zz, m, mr.n0inv, num_words); 186 | montgomery(&mut zz, &z, &z, m, mr.n0inv, num_words); 187 | montgomery(&mut z, &zz, &zz, m, mr.n0inv, num_words); 188 | } 189 | montgomery( 190 | &mut zz, 191 | &z, 192 | &powers[(yi >> (big_digit::BITS - n)) as usize], 193 | m, 194 | mr.n0inv, 195 | num_words, 196 | ); 197 | core::mem::swap(&mut z, &mut zz); 198 | yi <<= n; 199 | j += n; 200 | } 201 | } 202 | 203 | // convert to regular number 204 | montgomery(&mut zz, &z, &one, m, mr.n0inv, num_words); 205 | 206 | zz.normalize(); 207 | // One last reduction, just in case. 208 | // See golang.org/issue/13907. 209 | if &zz >= m { 210 | // Common case is m has high bit set; in that case, 211 | // since zz is the same length as m, there can be just 212 | // one multiple of m to remove. Just subtract. 213 | // We think that the subtract should be sufficient in general, 214 | // so do that unconditionally, but double-check, 215 | // in case our beliefs are wrong. 216 | // The div is not expected to be reached. 217 | zz -= m; 218 | if &zz >= m { 219 | zz %= m; 220 | } 221 | } 222 | 223 | zz.normalize(); 224 | zz 225 | } 226 | -------------------------------------------------------------------------------- /src/prime.rs: -------------------------------------------------------------------------------- 1 | // https://github.com/RustCrypto/RSA/blob/master/src/prime.rs 2 | //! Implements probabilistic prime checkers. 3 | 4 | use integer::Integer; 5 | use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; 6 | use rand::rngs::StdRng; 7 | use rand::SeedableRng; 8 | 9 | use crate::algorithms::jacobi; 10 | use crate::big_digit; 11 | use crate::bigrand::RandBigInt; 12 | use crate::Sign::Plus; 13 | use crate::{BigInt, BigUint, IntoBigUint}; 14 | 15 | lazy_static! { 16 | pub(crate) static ref BIG_1: BigUint = BigUint::one(); 17 | pub(crate) static ref BIG_2: BigUint = BigUint::from_u64(2).unwrap(); 18 | pub(crate) static ref BIG_3: BigUint = BigUint::from_u64(3).unwrap(); 19 | pub(crate) static ref BIG_64: BigUint = BigUint::from_u64(64).unwrap(); 20 | } 21 | 22 | const PRIMES_A: u64 = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37; 23 | const PRIMES_B: u64 = 29 * 31 * 41 * 43 * 47 * 53; 24 | 25 | /// Records the primes < 64. 26 | const PRIME_BIT_MASK: u64 = 1 << 2 27 | | 1 << 3 28 | | 1 << 5 29 | | 1 << 7 30 | | 1 << 11 31 | | 1 << 13 32 | | 1 << 17 33 | | 1 << 19 34 | | 1 << 23 35 | | 1 << 29 36 | | 1 << 31 37 | | 1 << 37 38 | | 1 << 41 39 | | 1 << 43 40 | | 1 << 47 41 | | 1 << 53 42 | | 1 << 59 43 | | 1 << 61; 44 | 45 | /// ProbablyPrime reports whether x is probably prime, 46 | /// applying the Miller-Rabin test with n pseudorandomly chosen bases 47 | /// as well as a Baillie-PSW test. 48 | /// 49 | /// If x is prime, ProbablyPrime returns true. 50 | /// If x is chosen randomly and not prime, ProbablyPrime probably returns false. 51 | /// The probability of returning true for a randomly chosen non-prime is at most ¼ⁿ. 52 | /// 53 | /// ProbablyPrime is 100% accurate for inputs less than 2⁶⁴. 54 | /// See Menezes et al., Handbook of Applied Cryptography, 1997, pp. 145-149, 55 | /// and FIPS 186-4 Appendix F for further discussion of the error probabilities. 56 | /// 57 | /// ProbablyPrime is not suitable for judging primes that an adversary may 58 | /// have crafted to fool the test. 59 | /// 60 | /// This is a port of `ProbablyPrime` from the go std lib. 61 | pub fn probably_prime(x: &BigUint, n: usize) -> bool { 62 | if x.is_zero() { 63 | return false; 64 | } 65 | 66 | if x < &*BIG_64 { 67 | return (PRIME_BIT_MASK & (1 << x.to_u64().unwrap())) != 0; 68 | } 69 | 70 | if x.is_even() { 71 | return false; 72 | } 73 | 74 | let r_a = &(x % PRIMES_A); 75 | let r_b = &(x % PRIMES_B); 76 | 77 | if (r_a % 3u32).is_zero() 78 | || (r_a % 5u32).is_zero() 79 | || (r_a % 7u32).is_zero() 80 | || (r_a % 11u32).is_zero() 81 | || (r_a % 13u32).is_zero() 82 | || (r_a % 17u32).is_zero() 83 | || (r_a % 19u32).is_zero() 84 | || (r_a % 23u32).is_zero() 85 | || (r_a % 37u32).is_zero() 86 | || (r_b % 29u32).is_zero() 87 | || (r_b % 31u32).is_zero() 88 | || (r_b % 41u32).is_zero() 89 | || (r_b % 43u32).is_zero() 90 | || (r_b % 47u32).is_zero() 91 | || (r_b % 53u32).is_zero() 92 | { 93 | return false; 94 | } 95 | 96 | probably_prime_miller_rabin(x, n + 1, true) && probably_prime_lucas(x) 97 | } 98 | 99 | const NUMBER_OF_PRIMES: usize = 127; 100 | const PRIME_GAP: [u64; 167] = [ 101 | 2, 2, 4, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2, 4, 14, 4, 6, 102 | 2, 10, 2, 6, 6, 4, 6, 6, 2, 10, 2, 4, 2, 12, 12, 4, 2, 4, 6, 2, 10, 6, 6, 6, 2, 6, 4, 2, 10, 103 | 14, 4, 2, 4, 14, 6, 10, 2, 4, 6, 8, 6, 6, 4, 6, 8, 4, 8, 10, 2, 10, 2, 6, 4, 6, 8, 4, 2, 4, 12, 104 | 8, 4, 8, 4, 6, 12, 2, 18, 6, 10, 6, 6, 2, 6, 10, 6, 6, 2, 6, 6, 4, 2, 12, 10, 2, 4, 6, 6, 2, 105 | 12, 4, 6, 8, 10, 8, 10, 8, 6, 6, 4, 8, 6, 4, 8, 4, 14, 10, 12, 2, 10, 2, 4, 2, 10, 14, 4, 2, 4, 106 | 14, 4, 2, 4, 20, 4, 8, 10, 8, 4, 6, 6, 14, 4, 6, 6, 8, 6, 12, 107 | ]; 108 | 109 | const INCR_LIMIT: usize = 0x10000; 110 | 111 | /// Calculate the next larger prime, given a starting number `n`. 112 | pub fn next_prime(n: &BigUint) -> BigUint { 113 | if n < &*BIG_2 { 114 | return 2u32.into_biguint().unwrap(); 115 | } 116 | 117 | // We want something larger than our current number. 118 | let mut res = n + &*BIG_1; 119 | 120 | // Ensure we are odd. 121 | res |= &*BIG_1; 122 | 123 | // Handle values up to 7. 124 | if let Some(val) = res.to_u64() { 125 | if val < 7 { 126 | return res; 127 | } 128 | } 129 | 130 | let nbits = res.bits(); 131 | let prime_limit = if nbits / 2 >= NUMBER_OF_PRIMES { 132 | NUMBER_OF_PRIMES - 1 133 | } else { 134 | nbits / 2 135 | }; 136 | 137 | // Compute the residues modulo small odd primes 138 | let mut moduli = vec![BigUint::zero(); prime_limit]; 139 | 140 | 'outer: loop { 141 | let mut prime = 3; 142 | for i in 0..prime_limit { 143 | moduli[i] = &res % prime; 144 | prime += PRIME_GAP[i]; 145 | } 146 | 147 | // Check residues 148 | let mut difference: usize = 0; 149 | for incr in (0..INCR_LIMIT as u64).step_by(2) { 150 | let mut prime: u64 = 3; 151 | 152 | let mut cancel = false; 153 | for i in 0..prime_limit { 154 | let r = (&moduli[i] + incr) % prime; 155 | prime += PRIME_GAP[i]; 156 | 157 | if r.is_zero() { 158 | cancel = true; 159 | break; 160 | } 161 | } 162 | 163 | if !cancel { 164 | res += difference; 165 | difference = 0; 166 | if probably_prime(&res, 20) { 167 | break 'outer; 168 | } 169 | } 170 | 171 | difference += 2; 172 | } 173 | 174 | res += difference; 175 | } 176 | 177 | res 178 | } 179 | 180 | /// Reports whether n passes reps rounds of the Miller-Rabin primality test, using pseudo-randomly chosen bases. 181 | /// If `force2` is true, one of the rounds is forced to use base 2. 182 | /// 183 | /// See Handbook of Applied Cryptography, p. 139, Algorithm 4.24. 184 | pub fn probably_prime_miller_rabin(n: &BigUint, reps: usize, force2: bool) -> bool { 185 | // println!("miller-rabin: {}", n); 186 | let nm1 = n - &*BIG_1; 187 | // determine q, k such that nm1 = q << k 188 | let k = nm1.trailing_zeros().unwrap() as usize; 189 | let q = &nm1 >> k; 190 | 191 | let nm3 = n - &*BIG_2; 192 | 193 | let mut rng = StdRng::seed_from_u64(n.get_limb(0) as u64); 194 | 195 | 'nextrandom: for i in 0..reps { 196 | let x = if i == reps - 1 && force2 { 197 | BIG_2.clone() 198 | } else { 199 | rng.gen_biguint_below(&nm3) + &*BIG_2 200 | }; 201 | 202 | let mut y = x.modpow(&q, n); 203 | if y.is_one() || y == nm1 { 204 | continue; 205 | } 206 | 207 | for _ in 1..k { 208 | y = y.modpow(&*BIG_2, n); 209 | if y == nm1 { 210 | continue 'nextrandom; 211 | } 212 | if y.is_one() { 213 | return false; 214 | } 215 | } 216 | return false; 217 | } 218 | 219 | true 220 | } 221 | 222 | /// Reports whether n passes the "almost extra strong" Lucas probable prime test, 223 | /// using Baillie-OEIS parameter selection. This corresponds to "AESLPSP" on Jacobsen's tables (link below). 224 | /// The combination of this test and a Miller-Rabin/Fermat test with base 2 gives a Baillie-PSW test. 225 | /// 226 | /// 227 | /// References: 228 | /// 229 | /// Baillie and Wagstaff, "Lucas Pseudoprimes", Mathematics of Computation 35(152), 230 | /// October 1980, pp. 1391-1417, especially page 1401. 231 | /// http://www.ams.org/journals/mcom/1980-35-152/S0025-5718-1980-0583518-6/S0025-5718-1980-0583518-6.pdf 232 | /// 233 | /// Grantham, "Frobenius Pseudoprimes", Mathematics of Computation 70(234), 234 | /// March 2000, pp. 873-891. 235 | /// http://www.ams.org/journals/mcom/2001-70-234/S0025-5718-00-01197-2/S0025-5718-00-01197-2.pdf 236 | /// 237 | /// Baillie, "Extra strong Lucas pseudoprimes", OEIS A217719, https://oeis.org/A217719. 238 | /// 239 | /// Jacobsen, "Pseudoprime Statistics, Tables, and Data", http://ntheory.org/pseudoprimes.html. 240 | /// 241 | /// Nicely, "The Baillie-PSW Primality Test", http://www.trnicely.net/misc/bpsw.html. 242 | /// (Note that Nicely's definition of the "extra strong" test gives the wrong Jacobi condition, 243 | /// as pointed out by Jacobsen.) 244 | /// 245 | /// Crandall and Pomerance, Prime Numbers: A Computational Perspective, 2nd ed. 246 | /// Springer, 2005. 247 | pub fn probably_prime_lucas(n: &BigUint) -> bool { 248 | // println!("lucas: {}", n); 249 | // Discard 0, 1. 250 | if n.is_zero() || n.is_one() { 251 | return false; 252 | } 253 | 254 | // Two is the only even prime. 255 | if n.to_u64() == Some(2) { 256 | return false; 257 | } 258 | 259 | // Baillie-OEIS "method C" for choosing D, P, Q, 260 | // as in https://oeis.org/A217719/a217719.txt: 261 | // try increasing P ≥ 3 such that D = P² - 4 (so Q = 1) 262 | // until Jacobi(D, n) = -1. 263 | // The search is expected to succeed for non-square n after just a few trials. 264 | // After more than expected failures, check whether n is square 265 | // (which would cause Jacobi(D, n) = 1 for all D not dividing n). 266 | let mut p = 3u64; 267 | let n_int = BigInt::from_biguint(Plus, n.clone()); 268 | 269 | loop { 270 | if p > 10000 { 271 | // This is widely believed to be impossible. 272 | // If we get a report, we'll want the exact number n. 273 | panic!("internal error: cannot find (D/n) = -1 for {:?}", n) 274 | } 275 | 276 | let d_int = BigInt::from_u64(p * p - 4).unwrap(); 277 | let j = jacobi(&d_int, &n_int); 278 | 279 | if j == -1 { 280 | break; 281 | } 282 | if j == 0 { 283 | // d = p²-4 = (p-2)(p+2). 284 | // If (d/n) == 0 then d shares a prime factor with n. 285 | // Since the loop proceeds in increasing p and starts with p-2==1, 286 | // the shared prime factor must be p+2. 287 | // If p+2 == n, then n is prime; otherwise p+2 is a proper factor of n. 288 | return n_int.to_i64() == Some(p as i64 + 2); 289 | } 290 | if p == 40 { 291 | // We'll never find (d/n) = -1 if n is a square. 292 | // If n is a non-square we expect to find a d in just a few attempts on average. 293 | // After 40 attempts, take a moment to check if n is indeed a square. 294 | let t1 = n.sqrt(); 295 | let t1 = &t1 * &t1; 296 | if &t1 == n { 297 | return false; 298 | } 299 | } 300 | 301 | p += 1; 302 | } 303 | 304 | // Grantham definition of "extra strong Lucas pseudoprime", after Thm 2.3 on p. 876 305 | // (D, P, Q above have become Δ, b, 1): 306 | // 307 | // Let U_n = U_n(b, 1), V_n = V_n(b, 1), and Δ = b²-4. 308 | // An extra strong Lucas pseudoprime to base b is a composite n = 2^r s + Jacobi(Δ, n), 309 | // where s is odd and gcd(n, 2*Δ) = 1, such that either (i) U_s ≡ 0 mod n and V_s ≡ ±2 mod n, 310 | // or (ii) V_{2^t s} ≡ 0 mod n for some 0 ≤ t < r-1. 311 | // 312 | // We know gcd(n, Δ) = 1 or else we'd have found Jacobi(d, n) == 0 above. 313 | // We know gcd(n, 2) = 1 because n is odd. 314 | // 315 | // Arrange s = (n - Jacobi(Δ, n)) / 2^r = (n+1) / 2^r. 316 | let mut s = n + &*BIG_1; 317 | let r = s.trailing_zeros().unwrap() as usize; 318 | s = &s >> r; 319 | let nm2 = n - &*BIG_2; // n - 2 320 | 321 | // We apply the "almost extra strong" test, which checks the above conditions 322 | // except for U_s ≡ 0 mod n, which allows us to avoid computing any U_k values. 323 | // Jacobsen points out that maybe we should just do the full extra strong test: 324 | // "It is also possible to recover U_n using Crandall and Pomerance equation 3.13: 325 | // U_n = D^-1 (2V_{n+1} - PV_n) allowing us to run the full extra-strong test 326 | // at the cost of a single modular inversion. This computation is easy and fast in GMP, 327 | // so we can get the full extra-strong test at essentially the same performance as the 328 | // almost extra strong test." 329 | 330 | // Compute Lucas sequence V_s(b, 1), where: 331 | // 332 | // V(0) = 2 333 | // V(1) = P 334 | // V(k) = P V(k-1) - Q V(k-2). 335 | // 336 | // (Remember that due to method C above, P = b, Q = 1.) 337 | // 338 | // In general V(k) = α^k + β^k, where α and β are roots of x² - Px + Q. 339 | // Crandall and Pomerance (p.147) observe that for 0 ≤ j ≤ k, 340 | // 341 | // V(j+k) = V(j)V(k) - V(k-j). 342 | // 343 | // So in particular, to quickly double the subscript: 344 | // 345 | // V(2k) = V(k)² - 2 346 | // V(2k+1) = V(k) V(k+1) - P 347 | // 348 | // We can therefore start with k=0 and build up to k=s in log₂(s) steps. 349 | let mut vk = BIG_2.clone(); 350 | let mut vk1 = BigUint::from_u64(p).unwrap(); 351 | 352 | for i in (0..s.bits()).rev() { 353 | if is_bit_set(&s, i) { 354 | // k' = 2k+1 355 | // V(k') = V(2k+1) = V(k) V(k+1) - P 356 | let t1 = (&vk * &vk1) + n - p; 357 | vk = &t1 % n; 358 | // V(k'+1) = V(2k+2) = V(k+1)² - 2 359 | let t1 = (&vk1 * &vk1) + &nm2; 360 | vk1 = &t1 % n; 361 | } else { 362 | // k' = 2k 363 | // V(k'+1) = V(2k+1) = V(k) V(k+1) - P 364 | let t1 = (&vk * &vk1) + n - p; 365 | vk1 = &t1 % n; 366 | // V(k') = V(2k) = V(k)² - 2 367 | let t1 = (&vk * &vk) + &nm2; 368 | vk = &t1 % n; 369 | } 370 | } 371 | 372 | // Now k=s, so vk = V(s). Check V(s) ≡ ±2 (mod n). 373 | if vk.to_u64() == Some(2) || vk == nm2 { 374 | // Check U(s) ≡ 0. 375 | // As suggested by Jacobsen, apply Crandall and Pomerance equation 3.13: 376 | // 377 | // U(k) = D⁻¹ (2 V(k+1) - P V(k)) 378 | // 379 | // Since we are checking for U(k) == 0 it suffices to check 2 V(k+1) == P V(k) mod n, 380 | // or P V(k) - 2 V(k+1) == 0 mod n. 381 | let mut t1 = &vk * p; 382 | let mut t2 = &vk1 << 1; 383 | 384 | if t1 < t2 { 385 | core::mem::swap(&mut t1, &mut t2); 386 | } 387 | 388 | t1 -= t2; 389 | 390 | if (t1 % n).is_zero() { 391 | return true; 392 | } 393 | } 394 | 395 | // Check V(2^t s) ≡ 0 mod n for some 0 ≤ t < r-1. 396 | for _ in 0..r - 1 { 397 | if vk.is_zero() { 398 | return true; 399 | } 400 | 401 | // Optimization: V(k) = 2 is a fixed point for V(k') = V(k)² - 2, 402 | // so if V(k) = 2, we can stop: we will never find a future V(k) == 0. 403 | if vk.to_u64() == Some(2) { 404 | return false; 405 | } 406 | 407 | // k' = 2k 408 | // V(k') = V(2k) = V(k)² - 2 409 | let t1 = (&vk * &vk) - &*BIG_2; 410 | vk = &t1 % n; 411 | } 412 | 413 | false 414 | } 415 | 416 | /// Checks if the i-th bit is set 417 | #[inline] 418 | fn is_bit_set(x: &BigUint, i: usize) -> bool { 419 | get_bit(x, i) == 1 420 | } 421 | 422 | /// Returns the i-th bit. 423 | #[inline] 424 | fn get_bit(x: &BigUint, i: usize) -> u8 { 425 | let j = i / big_digit::BITS; 426 | // if is out of range of the set words, it is always false. 427 | if i >= x.bits() { 428 | return 0; 429 | } 430 | 431 | (x.get_limb(j) >> (i % big_digit::BITS) & 1) as u8 432 | } 433 | 434 | #[cfg(test)] 435 | mod tests { 436 | use super::*; 437 | use alloc::vec::Vec; 438 | // use RandBigInt; 439 | 440 | use crate::biguint::ToBigUint; 441 | 442 | lazy_static! { 443 | static ref PRIMES: Vec<&'static str> = vec![ 444 | "2", 445 | "3", 446 | "5", 447 | "7", 448 | "11", 449 | 450 | "13756265695458089029", 451 | "13496181268022124907", 452 | "10953742525620032441", 453 | "17908251027575790097", 454 | 455 | // https://golang.org/issue/638 456 | "18699199384836356663", 457 | 458 | "98920366548084643601728869055592650835572950932266967461790948584315647051443", 459 | "94560208308847015747498523884063394671606671904944666360068158221458669711639", 460 | 461 | // http://primes.utm.edu/lists/small/small3.html 462 | "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163", 463 | "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593", 464 | "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993", 465 | "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", 466 | // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02 467 | "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9 468 | "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19 469 | "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105 470 | "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17 471 | "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1 472 | ]; 473 | 474 | static ref COMPOSITES: Vec<&'static str> = vec![ 475 | "0", 476 | "1", 477 | 478 | "21284175091214687912771199898307297748211672914763848041968395774954376176754", 479 | "6084766654921918907427900243509372380954290099172559290432744450051395395951", 480 | "84594350493221918389213352992032324280367711247940675652888030554255915464401", 481 | "82793403787388584738507275144194252681", 482 | 483 | // Arnault, "Rabin-Miller Primality Test: Composite Numbers Which Pass It", 484 | // Mathematics of Computation, 64(209) (January 1995), pp. 335-361. 485 | "1195068768795265792518361315725116351898245581", // strong pseudoprime to prime bases 2 through 29 486 | // strong pseudoprime to all prime bases up to 200 487 | "8038374574536394912570796143419421081388376882875581458374889175222974273765333652186502336163960045457915042023603208766569966760987284043965408232928738791850869166857328267761771029389697739470167082304286871099974399765441448453411558724506334092790222752962294149842306881685404326457534018329786111298960644845216191652872597534901", 488 | 489 | // Extra-strong Lucas pseudoprimes. https://oeis.org/A217719 490 | "989", 491 | "3239", 492 | "5777", 493 | "10877", 494 | "27971", 495 | "29681", 496 | "30739", 497 | "31631", 498 | "39059", 499 | "72389", 500 | "73919", 501 | "75077", 502 | "100127", 503 | "113573", 504 | "125249", 505 | "137549", 506 | "137801", 507 | "153931", 508 | "155819", 509 | "161027", 510 | "162133", 511 | "189419", 512 | "218321", 513 | "231703", 514 | "249331", 515 | "370229", 516 | "429479", 517 | "430127", 518 | "459191", 519 | "473891", 520 | "480689", 521 | "600059", 522 | "621781", 523 | "632249", 524 | "635627", 525 | 526 | "3673744903", 527 | "3281593591", 528 | "2385076987", 529 | "2738053141", 530 | "2009621503", 531 | "1502682721", 532 | "255866131", 533 | "117987841", 534 | "587861", 535 | 536 | "6368689", 537 | "8725753", 538 | "80579735209", 539 | "105919633", 540 | ]; 541 | 542 | // Test Cases from #51 543 | static ref ISSUE_51: Vec<&'static str> = vec![ 544 | "1579751", 545 | "1884791", 546 | "3818929", 547 | "4080359", 548 | "4145951", 549 | ]; 550 | } 551 | 552 | #[test] 553 | fn test_primes() { 554 | for prime in PRIMES.iter() { 555 | let p = BigUint::parse_bytes(prime.as_bytes(), 10).unwrap(); 556 | for i in [0, 1, 20].iter() { 557 | assert!( 558 | probably_prime(&p, *i as usize), 559 | "{} is a prime ({})", 560 | prime, 561 | i, 562 | ); 563 | } 564 | } 565 | } 566 | 567 | #[test] 568 | fn test_composites() { 569 | for comp in COMPOSITES.iter() { 570 | let p = BigUint::parse_bytes(comp.as_bytes(), 10).unwrap(); 571 | for i in [0, 1, 20].iter() { 572 | assert!( 573 | !probably_prime(&p, *i as usize), 574 | "{} is a composite ({})", 575 | comp, 576 | i, 577 | ); 578 | } 579 | } 580 | } 581 | 582 | #[test] 583 | fn test_issue_51() { 584 | for num in ISSUE_51.iter() { 585 | let p = BigUint::parse_bytes(num.as_bytes(), 10).unwrap(); 586 | assert!(probably_prime(&p, 20), "{} is a prime number", num); 587 | } 588 | } 589 | 590 | macro_rules! test_pseudo_primes { 591 | ($name:ident, $cond:expr, $want:expr) => { 592 | #[test] 593 | fn $name() { 594 | let mut i = 3; 595 | let mut want = $want; 596 | while i < 100000 { 597 | let n = BigUint::from_u64(i).unwrap(); 598 | let pseudo = $cond(&n); 599 | if pseudo && (want.is_empty() || i != want[0]) { 600 | panic!("cond({}) = true, want false", i); 601 | } else if !pseudo && !want.is_empty() && i == want[0] { 602 | panic!("cond({}) = false, want true", i); 603 | } 604 | if !want.is_empty() && i == want[0] { 605 | want = want[1..].to_vec(); 606 | } 607 | i += 2; 608 | } 609 | 610 | if !want.is_empty() { 611 | panic!("forgot to test: {:?}", want); 612 | } 613 | } 614 | }; 615 | } 616 | 617 | test_pseudo_primes!( 618 | test_probably_prime_miller_rabin, 619 | |n| probably_prime_miller_rabin(n, 1, true) && !probably_prime_lucas(n), 620 | vec![ 621 | 2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141, 52633, 65281, 74665, 80581, 622 | 85489, 88357, 90751, 623 | ] 624 | ); 625 | 626 | test_pseudo_primes!( 627 | test_probably_prime_lucas, 628 | |n| probably_prime_lucas(n) && !probably_prime_miller_rabin(n, 1, true), 629 | vec![989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077,] 630 | ); 631 | 632 | #[test] 633 | fn test_bit_set() { 634 | let v = &vec![0b10101001]; 635 | let num = BigUint::from_slice(&v); 636 | assert!(is_bit_set(&num, 0)); 637 | assert!(!is_bit_set(&num, 1)); 638 | assert!(!is_bit_set(&num, 2)); 639 | assert!(is_bit_set(&num, 3)); 640 | assert!(!is_bit_set(&num, 4)); 641 | assert!(is_bit_set(&num, 5)); 642 | assert!(!is_bit_set(&num, 6)); 643 | assert!(is_bit_set(&num, 7)); 644 | } 645 | 646 | #[test] 647 | fn test_next_prime_basics() { 648 | let primes1 = (0..2048u32) 649 | .map(|i| next_prime(&i.to_biguint().unwrap())) 650 | .collect::>(); 651 | let primes2 = (0..2048u32) 652 | .map(|i| { 653 | let i = i.to_biguint().unwrap(); 654 | let p = next_prime(&i); 655 | assert!(&p > &i); 656 | p 657 | }) 658 | .collect::>(); 659 | 660 | for (p1, p2) in primes1.iter().zip(&primes2) { 661 | assert_eq!(p1, p2); 662 | assert!(probably_prime(p1, 25)); 663 | } 664 | } 665 | 666 | #[test] 667 | fn test_next_prime_bug_44() { 668 | let i = 1032989.to_biguint().unwrap(); 669 | let next = next_prime(&i); 670 | assert_eq!(1033001.to_biguint().unwrap(), next); 671 | } 672 | } 673 | -------------------------------------------------------------------------------- /src/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::BigInt; 2 | 3 | /// Generic trait to implement modular inverse. 4 | pub trait ModInverse: Sized { 5 | type Output: Sized; 6 | 7 | /// Function to calculate the [modular multiplicative 8 | /// inverse](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse) of an integer *a* modulo *m*. 9 | /// 10 | /// TODO: references 11 | /// Returns the modular inverse of `self`. 12 | /// If none exists it returns `None`. 13 | fn mod_inverse(self, m: R) -> Option; 14 | } 15 | 16 | /// Generic trait to implement extended GCD. 17 | /// Calculates the extended eucledian algorithm. 18 | /// See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm for details. 19 | /// The returned values are 20 | /// - greatest common divisor (1) 21 | /// - Bezout coefficients (2) 22 | pub trait ExtendedGcd: Sized { 23 | fn extended_gcd(self, other: R) -> (BigInt, BigInt, BigInt); 24 | } 25 | -------------------------------------------------------------------------------- /tests/bigint_bitwise.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint_dig as num_bigint; 2 | extern crate num_traits; 3 | 4 | use crate::num_bigint::{BigInt, Sign, ToBigInt}; 5 | use num_traits::ToPrimitive; 6 | use std::{i32, i64, u32}; 7 | 8 | enum ValueVec { 9 | N, 10 | P(&'static [u32]), 11 | M(&'static [u32]), 12 | } 13 | 14 | use crate::ValueVec::*; 15 | 16 | impl ToBigInt for ValueVec { 17 | fn to_bigint(&self) -> Option { 18 | match self { 19 | &N => Some(BigInt::from_slice(Sign::NoSign, &[])), 20 | &P(s) => Some(BigInt::from_slice(Sign::Plus, s)), 21 | &M(s) => Some(BigInt::from_slice(Sign::Minus, s)), 22 | } 23 | } 24 | } 25 | 26 | // a, !a 27 | const NOT_VALUES: &'static [(ValueVec, ValueVec)] = &[ 28 | (N, M(&[1])), 29 | (P(&[1]), M(&[2])), 30 | (P(&[2]), M(&[3])), 31 | (P(&[!0 - 2]), M(&[!0 - 1])), 32 | (P(&[!0 - 1]), M(&[!0])), 33 | (P(&[!0]), M(&[0, 1])), 34 | (P(&[0, 1]), M(&[1, 1])), 35 | (P(&[1, 1]), M(&[2, 1])), 36 | ]; 37 | 38 | // a, b, a & b, a | b, a ^ b 39 | const BITWISE_VALUES: &'static [(ValueVec, ValueVec, ValueVec, ValueVec, ValueVec)] = &[ 40 | (N, N, N, N, N), 41 | (N, P(&[1]), N, P(&[1]), P(&[1])), 42 | (N, P(&[!0]), N, P(&[!0]), P(&[!0])), 43 | (N, P(&[0, 1]), N, P(&[0, 1]), P(&[0, 1])), 44 | (N, M(&[1]), N, M(&[1]), M(&[1])), 45 | (N, M(&[!0]), N, M(&[!0]), M(&[!0])), 46 | (N, M(&[0, 1]), N, M(&[0, 1]), M(&[0, 1])), 47 | (P(&[1]), P(&[!0]), P(&[1]), P(&[!0]), P(&[!0 - 1])), 48 | (P(&[!0]), P(&[!0]), P(&[!0]), P(&[!0]), N), 49 | (P(&[!0]), P(&[1, 1]), P(&[1]), P(&[!0, 1]), P(&[!0 - 1, 1])), 50 | (P(&[1]), M(&[!0]), P(&[1]), M(&[!0]), M(&[0, 1])), 51 | (P(&[!0]), M(&[1]), P(&[!0]), M(&[1]), M(&[0, 1])), 52 | (P(&[!0]), M(&[!0]), P(&[1]), M(&[1]), M(&[2])), 53 | (P(&[!0]), M(&[1, 1]), P(&[!0]), M(&[1, 1]), M(&[0, 2])), 54 | (P(&[1, 1]), M(&[!0]), P(&[1, 1]), M(&[!0]), M(&[0, 2])), 55 | (M(&[1]), M(&[!0]), M(&[!0]), M(&[1]), P(&[!0 - 1])), 56 | (M(&[!0]), M(&[!0]), M(&[!0]), M(&[!0]), N), 57 | (M(&[!0]), M(&[1, 1]), M(&[!0, 1]), M(&[1]), P(&[!0 - 1, 1])), 58 | ]; 59 | 60 | const I32_MIN: i64 = i32::MIN as i64; 61 | const I32_MAX: i64 = i32::MAX as i64; 62 | const U32_MAX: i64 = u32::MAX as i64; 63 | 64 | // some corner cases 65 | const I64_VALUES: &'static [i64] = &[ 66 | i64::MIN, 67 | i64::MIN + 1, 68 | i64::MIN + 2, 69 | i64::MIN + 3, 70 | -U32_MAX - 3, 71 | -U32_MAX - 2, 72 | -U32_MAX - 1, 73 | -U32_MAX, 74 | -U32_MAX + 1, 75 | -U32_MAX + 2, 76 | -U32_MAX + 3, 77 | I32_MIN - 3, 78 | I32_MIN - 2, 79 | I32_MIN - 1, 80 | I32_MIN, 81 | I32_MIN + 1, 82 | I32_MIN + 2, 83 | I32_MIN + 3, 84 | -3, 85 | -2, 86 | -1, 87 | 0, 88 | 1, 89 | 2, 90 | 3, 91 | I32_MAX - 3, 92 | I32_MAX - 2, 93 | I32_MAX - 1, 94 | I32_MAX, 95 | I32_MAX + 1, 96 | I32_MAX + 2, 97 | I32_MAX + 3, 98 | U32_MAX - 3, 99 | U32_MAX - 2, 100 | U32_MAX - 1, 101 | U32_MAX, 102 | U32_MAX + 1, 103 | U32_MAX + 2, 104 | U32_MAX + 3, 105 | i64::MAX - 3, 106 | i64::MAX - 2, 107 | i64::MAX - 1, 108 | i64::MAX, 109 | ]; 110 | 111 | #[test] 112 | fn test_not() { 113 | for &(ref a, ref not) in NOT_VALUES.iter() { 114 | let a = a.to_bigint().unwrap(); 115 | let not = not.to_bigint().unwrap(); 116 | 117 | // sanity check for tests that fit in i64 118 | if let (Some(prim_a), Some(prim_not)) = (a.to_i64(), not.to_i64()) { 119 | assert_eq!(!prim_a, prim_not); 120 | } 121 | 122 | assert_eq!(!a.clone(), not, "!{:x}", a); 123 | assert_eq!(!not.clone(), a, "!{:x}", not); 124 | } 125 | } 126 | 127 | #[test] 128 | fn test_not_i64() { 129 | for &prim_a in I64_VALUES.iter() { 130 | let a = prim_a.to_bigint().unwrap(); 131 | let not = (!prim_a).to_bigint().unwrap(); 132 | assert_eq!(!a.clone(), not, "!{:x}", a); 133 | } 134 | } 135 | 136 | #[test] 137 | fn test_bitwise() { 138 | for &(ref a, ref b, ref and, ref or, ref xor) in BITWISE_VALUES.iter() { 139 | let a = a.to_bigint().unwrap(); 140 | let b = b.to_bigint().unwrap(); 141 | let and = and.to_bigint().unwrap(); 142 | let or = or.to_bigint().unwrap(); 143 | let xor = xor.to_bigint().unwrap(); 144 | 145 | // sanity check for tests that fit in i64 146 | if let (Some(prim_a), Some(prim_b)) = (a.to_i64(), b.to_i64()) { 147 | if let Some(prim_and) = and.to_i64() { 148 | assert_eq!(prim_a & prim_b, prim_and); 149 | } 150 | if let Some(prim_or) = or.to_i64() { 151 | assert_eq!(prim_a | prim_b, prim_or); 152 | } 153 | if let Some(prim_xor) = xor.to_i64() { 154 | assert_eq!(prim_a ^ prim_b, prim_xor); 155 | } 156 | } 157 | 158 | assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b); 159 | assert_eq!(b.clone() & &a, and, "{:x} & {:x}", b, a); 160 | assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b); 161 | assert_eq!(b.clone() | &a, or, "{:x} | {:x}", b, a); 162 | assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b); 163 | assert_eq!(b.clone() ^ &a, xor, "{:x} ^ {:x}", b, a); 164 | } 165 | } 166 | 167 | #[test] 168 | fn test_bitwise_i64() { 169 | for &prim_a in I64_VALUES.iter() { 170 | let a = prim_a.to_bigint().unwrap(); 171 | for &prim_b in I64_VALUES.iter() { 172 | let b = prim_b.to_bigint().unwrap(); 173 | let and = (prim_a & prim_b).to_bigint().unwrap(); 174 | let or = (prim_a | prim_b).to_bigint().unwrap(); 175 | let xor = (prim_a ^ prim_b).to_bigint().unwrap(); 176 | assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b); 177 | assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b); 178 | assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b); 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /tests/bigint_scalar.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint_dig as num_bigint; 2 | extern crate num_traits; 3 | 4 | use crate::num_bigint::BigInt; 5 | use crate::num_bigint::Sign::Plus; 6 | use num_traits::{Signed, ToPrimitive, Zero}; 7 | 8 | use std::ops::Neg; 9 | 10 | mod consts; 11 | use crate::consts::*; 12 | 13 | #[macro_use] 14 | mod macros; 15 | 16 | #[test] 17 | fn test_scalar_add() { 18 | fn check(x: &BigInt, y: &BigInt, z: &BigInt) { 19 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 20 | assert_signed_scalar_op!(x + y == z); 21 | } 22 | 23 | for elm in SUM_TRIPLES.iter() { 24 | let (a_vec, b_vec, c_vec) = *elm; 25 | let a = BigInt::from_slice(Plus, a_vec); 26 | let b = BigInt::from_slice(Plus, b_vec); 27 | let c = BigInt::from_slice(Plus, c_vec); 28 | let (na, nb, nc) = (-&a, -&b, -&c); 29 | 30 | check(&a, &b, &c); 31 | check(&b, &a, &c); 32 | check(&c, &na, &b); 33 | check(&c, &nb, &a); 34 | check(&a, &nc, &nb); 35 | check(&b, &nc, &na); 36 | check(&na, &nb, &nc); 37 | check(&a, &na, &Zero::zero()); 38 | } 39 | } 40 | 41 | #[test] 42 | fn test_scalar_sub() { 43 | fn check(x: &BigInt, y: &BigInt, z: &BigInt) { 44 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 45 | assert_signed_scalar_op!(x - y == z); 46 | } 47 | 48 | for elm in SUM_TRIPLES.iter() { 49 | let (a_vec, b_vec, c_vec) = *elm; 50 | let a = BigInt::from_slice(Plus, a_vec); 51 | let b = BigInt::from_slice(Plus, b_vec); 52 | let c = BigInt::from_slice(Plus, c_vec); 53 | let (na, nb, nc) = (-&a, -&b, -&c); 54 | 55 | check(&c, &a, &b); 56 | check(&c, &b, &a); 57 | check(&nb, &a, &nc); 58 | check(&na, &b, &nc); 59 | check(&b, &na, &c); 60 | check(&a, &nb, &c); 61 | check(&nc, &na, &nb); 62 | check(&a, &a, &Zero::zero()); 63 | } 64 | } 65 | 66 | #[test] 67 | fn test_scalar_mul() { 68 | fn check(x: &BigInt, y: &BigInt, z: &BigInt) { 69 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 70 | assert_signed_scalar_op!(x * y == z); 71 | } 72 | 73 | for elm in MUL_TRIPLES.iter() { 74 | let (a_vec, b_vec, c_vec) = *elm; 75 | let a = BigInt::from_slice(Plus, a_vec); 76 | let b = BigInt::from_slice(Plus, b_vec); 77 | let c = BigInt::from_slice(Plus, c_vec); 78 | let (na, nb, nc) = (-&a, -&b, -&c); 79 | 80 | check(&a, &b, &c); 81 | check(&b, &a, &c); 82 | check(&na, &nb, &c); 83 | 84 | check(&na, &b, &nc); 85 | check(&nb, &a, &nc); 86 | } 87 | } 88 | 89 | #[test] 90 | fn test_scalar_div_rem() { 91 | fn check_sub(a: &BigInt, b: u32, ans_q: &BigInt, ans_r: &BigInt) { 92 | let (q, r) = (a / b, a % b); 93 | if !r.is_zero() { 94 | assert_eq!(r.sign(), a.sign()); 95 | } 96 | assert!(r.abs() <= From::from(b)); 97 | assert!(*a == b * &q + &r); 98 | assert!(q == *ans_q); 99 | assert!(r == *ans_r); 100 | 101 | let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); 102 | assert_op!(a / b == ans_q); 103 | assert_op!(a % b == ans_r); 104 | 105 | if b <= i32::max_value() as u32 { 106 | let nb = -(b as i32); 107 | assert_op!(a / nb == -ans_q.clone()); 108 | assert_op!(a % nb == ans_r); 109 | } 110 | } 111 | 112 | fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) { 113 | check_sub(a, b, q, r); 114 | check_sub(&a.neg(), b, &q.neg(), &r.neg()); 115 | } 116 | 117 | for elm in MUL_TRIPLES.iter() { 118 | let (a_vec, b_vec, c_vec) = *elm; 119 | let a = BigInt::from_slice(Plus, a_vec); 120 | let b = BigInt::from_slice(Plus, b_vec); 121 | let c = BigInt::from_slice(Plus, c_vec); 122 | 123 | if a_vec.len() == 1 && a_vec[0] != 0 { 124 | let a = a_vec[0]; 125 | check(&c, a, &b, &Zero::zero()); 126 | } 127 | 128 | if b_vec.len() == 1 && b_vec[0] != 0 { 129 | let b = b_vec[0]; 130 | check(&c, b, &a, &Zero::zero()); 131 | } 132 | } 133 | 134 | for elm in DIV_REM_QUADRUPLES.iter() { 135 | let (a_vec, b_vec, c_vec, d_vec) = *elm; 136 | let a = BigInt::from_slice(Plus, a_vec); 137 | let c = BigInt::from_slice(Plus, c_vec); 138 | let d = BigInt::from_slice(Plus, d_vec); 139 | 140 | if b_vec.len() == 1 && b_vec[0] != 0 { 141 | let b = b_vec[0]; 142 | check(&a, b, &c, &d); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /tests/biguint_scalar.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint_dig as num_bigint; 2 | extern crate num_traits; 3 | 4 | use crate::num_bigint::BigUint; 5 | use num_traits::{ToPrimitive, Zero}; 6 | 7 | mod consts; 8 | use crate::consts::*; 9 | 10 | #[macro_use] 11 | mod macros; 12 | 13 | #[test] 14 | fn test_scalar_add() { 15 | fn check(x: &BigUint, y: &BigUint, z: &BigUint) { 16 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 17 | assert_unsigned_scalar_op!(x + y == z); 18 | } 19 | 20 | for elm in SUM_TRIPLES.iter() { 21 | let (a_vec, b_vec, c_vec) = *elm; 22 | let a = BigUint::from_slice(a_vec); 23 | let b = BigUint::from_slice(b_vec); 24 | let c = BigUint::from_slice(c_vec); 25 | 26 | check(&a, &b, &c); 27 | check(&b, &a, &c); 28 | } 29 | } 30 | 31 | #[test] 32 | fn test_scalar_sub() { 33 | fn check(x: &BigUint, y: &BigUint, z: &BigUint) { 34 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 35 | assert_unsigned_scalar_op!(x - y == z); 36 | } 37 | 38 | for elm in SUM_TRIPLES.iter() { 39 | let (a_vec, b_vec, c_vec) = *elm; 40 | let a = BigUint::from_slice(a_vec); 41 | let b = BigUint::from_slice(b_vec); 42 | let c = BigUint::from_slice(c_vec); 43 | 44 | check(&c, &a, &b); 45 | check(&c, &b, &a); 46 | } 47 | } 48 | 49 | #[test] 50 | fn test_scalar_mul() { 51 | fn check(x: &BigUint, y: &BigUint, z: &BigUint) { 52 | let (x, y, z) = (x.clone(), y.clone(), z.clone()); 53 | assert_unsigned_scalar_op!(x * y == z); 54 | } 55 | 56 | for elm in MUL_TRIPLES.iter() { 57 | let (a_vec, b_vec, c_vec) = *elm; 58 | let a = BigUint::from_slice(a_vec); 59 | let b = BigUint::from_slice(b_vec); 60 | let c = BigUint::from_slice(c_vec); 61 | 62 | check(&a, &b, &c); 63 | check(&b, &a, &c); 64 | } 65 | } 66 | 67 | #[test] 68 | fn test_scalar_div_rem() { 69 | fn check(x: &BigUint, y: &BigUint, z: &BigUint, r: &BigUint) { 70 | let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone()); 71 | assert_unsigned_scalar_op!(x / y == z); 72 | assert_unsigned_scalar_op!(x % y == r); 73 | } 74 | 75 | for elm in MUL_TRIPLES.iter() { 76 | let (a_vec, b_vec, c_vec) = *elm; 77 | let a = BigUint::from_slice(a_vec); 78 | let b = BigUint::from_slice(b_vec); 79 | let c = BigUint::from_slice(c_vec); 80 | 81 | if !a.is_zero() { 82 | check(&c, &a, &b, &Zero::zero()); 83 | } 84 | 85 | if !b.is_zero() { 86 | check(&c, &b, &a, &Zero::zero()); 87 | } 88 | } 89 | 90 | for elm in DIV_REM_QUADRUPLES.iter() { 91 | let (a_vec, b_vec, c_vec, d_vec) = *elm; 92 | let a = BigUint::from_slice(a_vec); 93 | let b = BigUint::from_slice(b_vec); 94 | let c = BigUint::from_slice(c_vec); 95 | let d = BigUint::from_slice(d_vec); 96 | 97 | if !b.is_zero() { 98 | check(&a, &b, &c, &d); 99 | assert_unsigned_scalar_op!(a / b == c); 100 | assert_unsigned_scalar_op!(a % b == d); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tests/consts/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | pub const N1: u32 = -1i32 as u32; 4 | pub const N2: u32 = -2i32 as u32; 5 | 6 | pub const SUM_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[ 7 | (&[], &[], &[]), 8 | (&[], &[1], &[1]), 9 | (&[1], &[1], &[2]), 10 | (&[1], &[1, 1], &[2, 1]), 11 | (&[1], &[N1], &[0, 1]), 12 | (&[1], &[N1, N1], &[0, 0, 1]), 13 | (&[N1, N1], &[N1, N1], &[N2, N1, 1]), 14 | (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), 15 | (&[2, 2, 1], &[N1, N2], &[1, 1, 2]), 16 | (&[1, 2, 2, 1], &[N1, N2], &[0, 1, 3, 1]), 17 | ]; 18 | 19 | pub const M: u32 = ::std::u32::MAX; 20 | pub const MUL_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[ 21 | (&[], &[], &[]), 22 | (&[], &[1], &[]), 23 | (&[2], &[], &[]), 24 | (&[1], &[1], &[1]), 25 | (&[2], &[3], &[6]), 26 | (&[1], &[1, 1, 1], &[1, 1, 1]), 27 | (&[1, 2, 3], &[3], &[3, 6, 9]), 28 | (&[1, 1, 1], &[N1], &[N1, N1, N1]), 29 | (&[1, 2, 3], &[N1], &[N1, N2, N2, 2]), 30 | (&[1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), 31 | (&[N1], &[N1], &[1, N2]), 32 | (&[N1, N1], &[N1], &[1, N1, N2]), 33 | (&[N1, N1, N1], &[N1], &[1, N1, N1, N2]), 34 | (&[N1, N1, N1, N1], &[N1], &[1, N1, N1, N1, N2]), 35 | (&[M / 2 + 1], &[2], &[0, 1]), 36 | (&[0, M / 2 + 1], &[2], &[0, 0, 1]), 37 | (&[1, 2], &[1, 2, 3], &[1, 4, 7, 6]), 38 | (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), 39 | (&[N1, N1, N1], &[N1, N1, N1, N1], &[1, 0, 0, N1, N2, N1, N1]), 40 | (&[0, 0, 1], &[1, 2, 3], &[0, 0, 1, 2, 3]), 41 | (&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]), 42 | ]; 43 | 44 | pub const DIV_REM_QUADRUPLES: &'static [( 45 | &'static [u32], 46 | &'static [u32], 47 | &'static [u32], 48 | &'static [u32], 49 | )] = &[ 50 | (&[1], &[2], &[], &[1]), 51 | (&[3], &[2], &[1], &[1]), 52 | (&[1, 1], &[2], &[M / 2 + 1], &[1]), 53 | (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), 54 | (&[0, 1], &[N1], &[1], &[1]), 55 | (&[N1, N1], &[N2], &[2, 1], &[3]), 56 | ]; 57 | -------------------------------------------------------------------------------- /tests/macros/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | /// Assert that an op works for all val/ref combinations 4 | macro_rules! assert_op { 5 | ($left:ident $op:tt $right:ident == $expected:expr) => { 6 | assert_eq!((&$left) $op (&$right), $expected); 7 | assert_eq!((&$left) $op $right.clone(), $expected); 8 | assert_eq!($left.clone() $op (&$right), $expected); 9 | assert_eq!($left.clone() $op $right.clone(), $expected); 10 | }; 11 | } 12 | 13 | /// Assert that an assign-op works for all val/ref combinations 14 | macro_rules! assert_assign_op { 15 | ($left:ident $op:tt $right:ident == $expected:expr) => {{ 16 | let mut left = $left.clone(); 17 | assert_eq!({ left $op &$right; left}, $expected); 18 | 19 | let mut left = $left.clone(); 20 | assert_eq!({ left $op $right.clone(); left}, $expected); 21 | }}; 22 | } 23 | 24 | /// Assert that an op works for scalar left or right 25 | macro_rules! assert_scalar_op { 26 | (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { 27 | $( 28 | if let Some(left) = $left.$to() { 29 | assert_op!(left $op $right == $expected); 30 | } 31 | if let Some(right) = $right.$to() { 32 | assert_op!($left $op right == $expected); 33 | } 34 | )* 35 | }; 36 | } 37 | 38 | #[cfg(not(has_i128))] 39 | macro_rules! assert_unsigned_scalar_op { 40 | ($left:ident $op:tt $right:ident == $expected:expr) => { 41 | assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) 42 | $left $op $right == $expected); 43 | }; 44 | } 45 | 46 | #[cfg(has_i128)] 47 | macro_rules! assert_unsigned_scalar_op { 48 | ($left:ident $op:tt $right:ident == $expected:expr) => { 49 | assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128) 50 | $left $op $right == $expected); 51 | }; 52 | } 53 | 54 | #[cfg(not(has_i128))] 55 | macro_rules! assert_signed_scalar_op { 56 | ($left:ident $op:tt $right:ident == $expected:expr) => { 57 | assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, 58 | to_i8, to_i16, to_i32, to_i64, to_isize) 59 | $left $op $right == $expected); 60 | }; 61 | } 62 | 63 | #[cfg(has_i128)] 64 | macro_rules! assert_signed_scalar_op { 65 | ($left:ident $op:tt $right:ident == $expected:expr) => { 66 | assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128, 67 | to_i8, to_i16, to_i32, to_i64, to_isize, to_i128) 68 | $left $op $right == $expected); 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /tests/modpow.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint_dig as num_bigint; 2 | extern crate num_integer; 3 | extern crate num_traits; 4 | 5 | static BIG_B: &'static str = "\ 6 | efac3c0a_0de55551_fee0bfe4_67fa017a_1a898fa1_6ca57cb1\ 7 | ca9e3248_cacc09a9_b99d6abc_38418d0f_82ae4238_d9a68832\ 8 | aadec7c1_ac5fed48_7a56a71b_67ac59d5_afb28022_20d9592d\ 9 | 247c4efc_abbd9b75_586088ee_1dc00dc4_232a8e15_6e8191dd\ 10 | 675b6ae0_c80f5164_752940bc_284b7cee_885c1e10_e495345b\ 11 | 8fbe9cfd_e5233fe1_19459d0b_d64be53c_27de5a02_a829976b\ 12 | 33096862_82dad291_bd38b6a9_be396646_ddaf8039_a2573c39\ 13 | 1b14e8bc_2cb53e48_298c047e_d9879e9c_5a521076_f0e27df3\ 14 | 990e1659_d3d8205b_6443ebc0_9918ebee_6764f668_9f2b2be3\ 15 | b59cbc76_d76d0dfc_d737c3ec_0ccf9c00_ad0554bf_17e776ad\ 16 | b4edf9cc_6ce540be_76229093_5c53893b"; 17 | 18 | static BIG_E: &'static str = "\ 19 | be0e6ea6_08746133_e0fbc1bf_82dba91e_e2b56231_a81888d2\ 20 | a833a1fc_f7ff002a_3c486a13_4f420bf3_a5435be9_1a5c8391\ 21 | 774d6e6c_085d8357_b0c97d4d_2bb33f7c_34c68059_f78d2541\ 22 | eacc8832_426f1816_d3be001e_b69f9242_51c7708e_e10efe98\ 23 | 449c9a4a_b55a0f23_9d797410_515da00d_3ea07970_4478a2ca\ 24 | c3d5043c_bd9be1b4_6dce479d_4302d344_84a939e6_0ab5ada7\ 25 | 12ae34b2_30cc473c_9f8ee69d_2cac5970_29f5bf18_bc8203e4\ 26 | f3e895a2_13c94f1e_24c73d77_e517e801_53661fdd_a2ce9e47\ 27 | a73dd7f8_2f2adb1e_3f136bf7_8ae5f3b8_08730de1_a4eff678\ 28 | e77a06d0_19a522eb_cbefba2a_9caf7736_b157c5c6_2d192591\ 29 | 17946850_2ddb1822_117b68a0_32f7db88"; 30 | 31 | // This modulus is the prime from the 2048-bit MODP DH group: 32 | // https://tools.ietf.org/html/rfc3526#section-3 33 | static BIG_M: &'static str = "\ 34 | FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\ 35 | 29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\ 36 | EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\ 37 | E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\ 38 | EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\ 39 | C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\ 40 | 83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\ 41 | 670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\ 42 | E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\ 43 | DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\ 44 | 15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF"; 45 | 46 | static BIG_R: &'static str = "\ 47 | a1468311_6e56edc9_7a98228b_5e924776_0dd7836e_caabac13\ 48 | eda5373b_4752aa65_a1454850_40dc770e_30aa8675_6be7d3a8\ 49 | 9d3085e4_da5155cf_b451ef62_54d0da61_cf2b2c87_f495e096\ 50 | 055309f7_77802bbb_37271ba8_1313f1b5_075c75d1_024b6c77\ 51 | fdb56f17_b05bce61_e527ebfd_2ee86860_e9907066_edd526e7\ 52 | 93d289bf_6726b293_41b0de24_eff82424_8dfd374b_4ec59542\ 53 | 35ced2b2_6b195c90_10042ffb_8f58ce21_bc10ec42_64fda779\ 54 | d352d234_3d4eaea6_a86111ad_a37e9555_43ca78ce_2885bed7\ 55 | 5a30d182_f1cf6834_dc5b6e27_1a41ac34_a2e91e11_33363ff0\ 56 | f88a7b04_900227c9_f6e6d06b_7856b4bb_4e354d61_060db6c8\ 57 | 109c4735_6e7db425_7b5d74c7_0b709508"; 58 | 59 | mod biguint { 60 | use crate::num_bigint::BigUint; 61 | use num_integer::Integer; 62 | use num_traits::Num; 63 | 64 | fn check_modpow>(b: T, e: T, m: T, r: T) { 65 | let b: BigUint = b.into(); 66 | let e: BigUint = e.into(); 67 | let m: BigUint = m.into(); 68 | let r: BigUint = r.into(); 69 | 70 | assert_eq!(b.modpow(&e, &m), r); 71 | 72 | let even_m = &m << 1; 73 | let even_modpow = b.modpow(&e, &even_m); 74 | assert!(even_modpow < even_m); 75 | assert_eq!(even_modpow.mod_floor(&m), r); 76 | } 77 | 78 | #[test] 79 | fn test_modpow_single() { 80 | check_modpow::(1, 0, 11, 1); 81 | check_modpow::(0, 15, 11, 0); 82 | check_modpow::(3, 7, 11, 9); 83 | check_modpow::(5, 117, 19, 1); 84 | } 85 | 86 | #[test] 87 | fn test_modpow_big() { 88 | let b = BigUint::from_str_radix(super::BIG_B, 16).unwrap(); 89 | let e = BigUint::from_str_radix(super::BIG_E, 16).unwrap(); 90 | let m = BigUint::from_str_radix(super::BIG_M, 16).unwrap(); 91 | let r = BigUint::from_str_radix(super::BIG_R, 16).unwrap(); 92 | 93 | assert_eq!(b.modpow(&e, &m), r); 94 | 95 | let even_m = &m << 1; 96 | let even_modpow = b.modpow(&e, &even_m); 97 | assert!(even_modpow < even_m); 98 | assert_eq!(even_modpow % m, r); 99 | } 100 | } 101 | 102 | mod bigint { 103 | use crate::num_bigint::BigInt; 104 | use num_integer::Integer; 105 | use num_traits::{Num, One, Signed, Zero}; 106 | 107 | fn check_modpow>(b: T, e: T, m: T, r: T) { 108 | fn check(b: &BigInt, e: &BigInt, m: &BigInt, r: &BigInt) { 109 | assert_eq!(&b.modpow(e, m), r, "{} ** {} (mod {}) != {}", b, e, m, r); 110 | 111 | let even_m = m << 1; 112 | let even_modpow = b.modpow(e, m); 113 | assert!(even_modpow.abs() < even_m.abs()); 114 | assert_eq!(&even_modpow.mod_floor(&m), r); 115 | 116 | // the sign of the result follows the modulus like `mod_floor`, not `rem` 117 | assert_eq!(b.modpow(&BigInt::one(), m), b.mod_floor(m)); 118 | } 119 | 120 | let b: BigInt = b.into(); 121 | let e: BigInt = e.into(); 122 | let m: BigInt = m.into(); 123 | let r: BigInt = r.into(); 124 | 125 | let neg_r = if r.is_zero() { BigInt::zero() } else { &m - &r }; 126 | 127 | check(&b, &e, &m, &r); 128 | check(&-&b, &e, &m, &neg_r); 129 | check(&b, &e, &-&m, &-neg_r); 130 | check(&-b, &e, &-m, &-r); 131 | } 132 | 133 | #[test] 134 | fn test_modpow() { 135 | check_modpow(1, 0, 11, 1); 136 | check_modpow(0, 15, 11, 0); 137 | check_modpow(3, 7, 11, 9); 138 | check_modpow(5, 117, 19, 1); 139 | } 140 | 141 | #[test] 142 | fn test_modpow_big() { 143 | let b = BigInt::from_str_radix(super::BIG_B, 16).unwrap(); 144 | let e = BigInt::from_str_radix(super::BIG_E, 16).unwrap(); 145 | let m = BigInt::from_str_radix(super::BIG_M, 16).unwrap(); 146 | let r = BigInt::from_str_radix(super::BIG_R, 16).unwrap(); 147 | 148 | check_modpow(b, e, m, r); 149 | } 150 | 151 | #[test] 152 | fn test_modpow_regressions() { 153 | let b = BigInt::from_str_radix("148481812629898028922243452517931778859", 10).unwrap(); 154 | let e = BigInt::from_str_radix("164350981728398375121965168123110934994905698786703672972672898604245122565384632665320229592664080184165678526847345884979164161361870788392677397259783361669997458210059361790185938355877563593929478714825040836748164957314359093451997607971771611547549257793609195252376766141281726486479115003799144714128183665696714578467393814120227526482585239840445787567632354733951957802345386715871248483047881497956525866247944829277967526068822788411625449554600640196891378473177802068346095758817143275166167483977379612377628733368341719053305460274294511350837763626861228995578887259487962243311935062225921128133638312621437945519992818288453465098708801352407433629892022649558518668739019522985290473827609521712606998009402034024115903168144255768042129320865368708422779323482567497680433767646272900161006545330040104288222657772869086562080890990921279729840054238397946649195066553267786045462193245099006103846313224069126654860364743773661528709159184162331890246026968468075854895004614440562563403966571088898841287746465509970812429808338370105314308176865461375659159994405123891266709337612303317811367850519031055517613606059551539655265079163631883411122545335469009188561490562340100241858667397070522833201378945082367080303930737460085913589781310332202843084405789975523360515518724292604959852907884723834109301037010981810400469821789426150300238378910637164951422912400649144069581318797904885229033199330969917473583627360277003209342444115817442334409699908719803971129585552217720163472715197434582192016473415220486410376364470209613934593616891157837722052159595619082131329052418471178979749070210646603488411877432337686669419064020146677994675645890784629031645629931044021516402055317993934721616608563696148934577409311708245083906757791103637690292510165547063401385527997056954121665477882557077292209554459496917982492339487229688141530763150692622623272795444529846010384212201717448354354471390313394944641420537729794077616571212880759114553942399699567974275501943806450519656537154820877876153351290438129999404025460264150569923247671803347738438612339550712022372942743592714754306573808282605717032033275819875343175553669801881988323385785362441046181380541210414863721994233865976156241919018538304838096986853747426670289401018164419516853632768820383362107004227976035106131118469545950224360356987548199429365053752748081699631233511074051178296391097574448304825464270687816512317401375349484673480301886627859649660082713607771750803606946084699744123429385446074215481141415144959640495628130348624468766836381762042510936781300722486115488063326027291451024039766392335908184086768228847596527550616790205674080213548408229763037392340969472676595602270556401071384048020604327909934501565252293793797207146346237353181180650897635078348651682864682545684947006709194254396944396423192353225297735761017692031892010530886940052190428897070608145423884897961731293039683402223509642109932203493243263084842325764879968428129677259371460792715707895715737224078949761353247616162380061037191950050487463467812528656164400320234629304223345519745970775250821617679739209663950777506253481666213838435163785552701719451996405973898572946407314707644934778581322359906640869284294008054618184044944168077716469330553710607919475086198736822731411106767940517513117067340920713956504198958381975020396473042592923524697202199789614266606522684257572874995317955495218327193196753831545046930031947998147927851349772167106931459070942284239583716608592952560598540897287777232908661009153651601604269678247020505664949407134130455848520117547622541906732872100446640944626050064890054058389328759836051637590769709964190451361835977224657258154841427245128343914641758799690579706226595910843566133142399343803084018750765024209423758381252111340434598457630441263172401042037129339512480216561859237485485179316642715257798126649381183656694101241603952597449444909120197153522721490913694897355020355204849405171656334281390879810015575579384526915097294240353667407269558059437125234100571601655058663167086384390197946929355280399788013937609353436082888066756321802952215535926645873241527518339318793147919520660517850111074815282027596328391301608794376252865467079832695530445147672411416273240414437731626856569247968458705303971664831520406276181645211389639682423522154589153857862875820332977990620041874779912534487054875146227333182840793848696822083435299675425290586091746886253719376517376476192979085056002906185495241899325295106611248170270201999129505310823968875198192620688215223646536583263434182903541968689220812272083266201543646730605107614994880972852396541610915266940027186999857045792946342509904360006232236385410875003200003710271753907829437379680408328394065483143578396887566566005407578049525700830381650375391369588237592292574983213859202661428243174328514293270384618273277544583385984487503069129233267053646486572518591625604138011396668605361469032350603582888850778247186965442140444404195860308517896349031637246734945680372839546785278479593824257340527474351027861885392290231378838449725230480694930523008277023154555844343297155030642104598551668450374495246522115798459878558197309686627849547255201282303229719213831030170763906878819183484135468001583820625287461250511735890029467608943110965462084671268661889450052241131060465481175469285658052200025128774690538495390259618074262588140655147228805545049873691855054152255770202829440165503982450624005234795768600340087204677562163377727571121882970611075470502776106556822809472703656347295866746124605204135016829660149143986183668195830353797312832360933413687525614207287013489308257746670458517988651073504753625204959605466094771204209964965541710217080544310915210188893650613899394914870323514246198819988568145291383437326992546113583363899966403356219181683992559908962490561664206795233711792893981773521595699751343042228013932508198601083950252622077065636311291522313149517311977225604486651761581102311245044441267458710690116324603014332726884757767675055064026627538150429094284462465936700805774875213555790247688992265287670483674835359537320362066496631237532066434198486983108134077101914489258787273151097982046578991716153170761170565232354349286283062140146535745514689289849445004028675192230268395088320480288024809248753472669586551981632827331574644655254527360946541171694009094534525965788372249561700117566619377612607784622980162705615061563640861523841144853582789547670660998574405213291156583471422472737024713335911128552519494928220447015458117896038528532736249462994191693731924310038783792155090734024701098844694228302557144109939199656035117618815047127207778455632893493029828318966843557912588160243215378697136562712636447184586542592233327626401267509598734844522240759857137220876909047828060336559766882884056292087298828311843464955622703622199634508141793685859364925637793777682016420351323859848010606623465396948369240631276472572232028281297280828901171208847997385162695745049130595743829108979357004406444046586221335176301152731273434672154904521807542045622667736615188377717166157412872030872463207532820694823277895456126315590200107172399501418780662873848899945555090581629304192293210512166806174241905318439297836572429492555945848426574436820804276431938356677265173902567516974372557048005931467724243514313618168555104937201562664655492712786862271369422893595407516698240054274482308875406045004002766861865486805088644548951780356707149274987632240062289750700451450662820311466431667428284851948473650031507800214161385241719742922217838238400711647126794748806174836882883940057722793324676878558204321525826413953232881576775548034368728022937081394740112688238217301103514009488899854828922756909485766733545511482058947421794810707669182386862066862732498731756283370966668219295546440670559968588114589890542419364782206557895743456359437472986220063749869820539379941257862675002615164658188357798105487865311641962685185181852938728255920848800712212039448123892624090215049822390599899936382039234469555489723925532717532999939422880433214314964121376053233983116473767598132603437846016981354171586132813499569707397461677048841971510919245413813114311724904074380969238678296194626059869912965335551790872571048158053224153865323110852167314493276323090198653641172199104636190926118630451555110729692658524817414978729750372126722731500043191633465954497667185630804110549483087599351274519782412871406368481080021704006725857372058573865218993668019024024208275108900357152765961057292140846117515718034378698161351291158047506515803497515956519959532767226029329927621693742244108404900014394147196418357662166818493187358701629972155595893579939701750218259082071634738306600756059735100899792211287340114305538026232183669968800789674455430940867429885716527243860641947991536204288665082058524860060114668806790606990321001884609501157240809649183919063321158567912329113896832740889245598107417790596778129724526582814454491169202690995589063942376974544174226050004223359926067502761530455570619313444306185650028516198954161354984900397079331598983284892569733533525469198148807066556718513506092297233405158834932205982055789299794670101612866721906061130211546399655425605752494047788017152677453616235600992059935426874231748721437691974116227927409158423042936833609068849541189", 10).unwrap(); 155 | let m = BigInt::from_str_radix("243440964008985994185807471607210276717", 10).unwrap(); 156 | let r = BigInt::from_str_radix("138995801145388806366366393471481216294", 10).unwrap(); 157 | 158 | check_modpow(b, e, m, r); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /tests/rand.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "rand")] 2 | 3 | extern crate num_bigint_dig as num_bigint; 4 | extern crate num_traits; 5 | extern crate rand; 6 | extern crate rand_chacha; 7 | extern crate rand_isaac; 8 | extern crate rand_xorshift; 9 | 10 | mod biguint { 11 | use crate::num_bigint::{BigUint, RandBigInt, RandomBits}; 12 | use num_traits::Zero; 13 | use rand::distributions::Uniform; 14 | use rand::{Rng, SeedableRng}; 15 | 16 | #[cfg(feature = "std")] 17 | fn thread_rng() -> impl Rng { 18 | rand::thread_rng() 19 | } 20 | #[cfg(not(feature = "std"))] 21 | fn thread_rng() -> impl Rng { 22 | // Chosen by fair dice roll 23 | rand::rngs::StdRng::seed_from_u64(4) 24 | } 25 | 26 | #[test] 27 | fn test_rand() { 28 | let mut rng = thread_rng(); 29 | let n: BigUint = rng.gen_biguint(137); 30 | assert!(n.bits() <= 137); 31 | assert!(rng.gen_biguint(0).is_zero()); 32 | } 33 | 34 | #[test] 35 | fn test_rand_bits() { 36 | let mut rng = thread_rng(); 37 | let n: BigUint = rng.sample(&RandomBits::new(137)); 38 | assert!(n.bits() <= 137); 39 | let z: BigUint = rng.sample(&RandomBits::new(0)); 40 | assert!(z.is_zero()); 41 | } 42 | 43 | #[test] 44 | fn test_rand_range() { 45 | let mut rng = thread_rng(); 46 | 47 | for _ in 0..10 { 48 | assert_eq!( 49 | rng.gen_biguint_range(&BigUint::from(236u32), &BigUint::from(237u32)), 50 | BigUint::from(236u32) 51 | ); 52 | } 53 | 54 | let l = BigUint::from(403469000u32 + 2352); 55 | let u = BigUint::from(403469000u32 + 3513); 56 | for _ in 0..1000 { 57 | let n: BigUint = rng.gen_biguint_below(&u); 58 | assert!(n < u); 59 | 60 | let n: BigUint = rng.gen_biguint_range(&l, &u); 61 | assert!(n >= l); 62 | assert!(n < u); 63 | } 64 | } 65 | 66 | #[test] 67 | #[should_panic] 68 | fn test_zero_rand_range() { 69 | thread_rng().gen_biguint_range(&BigUint::from(54u32), &BigUint::from(54u32)); 70 | } 71 | 72 | #[test] 73 | #[should_panic] 74 | fn test_negative_rand_range() { 75 | let mut rng = thread_rng(); 76 | let l = BigUint::from(2352u32); 77 | let u = BigUint::from(3513u32); 78 | // Switching u and l should fail: 79 | let _n: BigUint = rng.gen_biguint_range(&u, &l); 80 | } 81 | 82 | #[test] 83 | fn test_rand_uniform() { 84 | let mut rng = thread_rng(); 85 | 86 | let tiny = Uniform::new(BigUint::from(236u32), BigUint::from(237u32)); 87 | for _ in 0..10 { 88 | assert_eq!(rng.sample(&tiny), BigUint::from(236u32)); 89 | } 90 | 91 | let l = BigUint::from(403469000u32 + 2352); 92 | let u = BigUint::from(403469000u32 + 3513); 93 | let below = Uniform::new(BigUint::zero(), u.clone()); 94 | let range = Uniform::new(l.clone(), u.clone()); 95 | for _ in 0..1000 { 96 | let n: BigUint = rng.sample(&below); 97 | assert!(n < u); 98 | 99 | let n: BigUint = rng.sample(&range); 100 | assert!(n >= l); 101 | assert!(n < u); 102 | } 103 | } 104 | 105 | fn seeded_value_stability(expected: &[&str]) { 106 | let mut seed = ::default(); 107 | for (i, x) in seed.as_mut().iter_mut().enumerate() { 108 | *x = (i as u8).wrapping_mul(191); 109 | } 110 | let mut rng = R::from_seed(seed); 111 | for (i, &s) in expected.iter().enumerate() { 112 | let n: BigUint = s.parse().unwrap(); 113 | let r = rng.gen_biguint((1 << i) + i); 114 | assert_eq!(n, r, "expected {}, got {}", n, r); 115 | } 116 | } 117 | 118 | #[cfg(not(feature = "u64_digit"))] 119 | const EXPECTED_CHACHA: &[&str] = &[ 120 | "0", 121 | "0", 122 | "52", 123 | "84", 124 | "23780", 125 | "86502865016", 126 | "187057847319509867386", 127 | "34045731223080904464438757488196244981910", 128 | "23813754422987836414755953516143692594193066497413249270287126597896871975915808", 129 | "57401636903146945411652549098818446911814352529449356393690984105383482703074355\ 130 | 67088360974672291353736011718191813678720755501317478656550386324355699624671", 131 | ]; 132 | 133 | #[cfg(feature = "u64_digit")] 134 | const EXPECTED_CHACHA: &[&str] = &[ 135 | "0", 136 | "0", 137 | "8", 138 | "1861", 139 | "172076", 140 | "5194801951", 141 | "259202797457072892019", 142 | "2806086822955830608275100562233284760859", 143 | "28771276448190704455825316568337256462972770861366848469339788407170414346460023", 144 | "501572804396703231264118826164515310701005506447150057229826006447721882571235378\ 145 | 4765127362270091441643338804096337494157874113908470083557122824480944132407", 146 | ]; 147 | 148 | #[test] 149 | fn test_chacha_value_stability() { 150 | use rand_chacha::ChaChaRng; 151 | seeded_value_stability::(EXPECTED_CHACHA); 152 | } 153 | 154 | #[cfg(not(feature = "u64_digit"))] 155 | const EXPECTED_ISAAC: &[&str] = &[ 156 | "1", 157 | "4", 158 | "3", 159 | "649", 160 | "89116", 161 | "7730042024", 162 | "20773149082453254949", 163 | "35999009049239918667571895439206839620281", 164 | "10191757312714088681302309313551624007714035309632506837271600807524767413673006", 165 | "37805949268912387809989378008822038725134260145886913321084097194957861133272558\ 166 | 43458183365174899239251448892645546322463253898288141861183340823194379722556", 167 | ]; 168 | 169 | #[cfg(feature = "u64_digit")] 170 | const EXPECTED_ISAAC: &[&str] = &[ 171 | "1", 172 | "2", 173 | "51", 174 | "1198", 175 | "29707", 176 | "35688018574", 177 | "365090200586541225112", 178 | "14051533166427520604648370582738617763816", 179 | "26319846996091585801307964353534339679417889504909644767909019559631059772127122", 180 | "14567336733062747693583250833667292276083519237160662196899060257293814346680656\ 181 | 30951609693408423310563908301065751714778956255122249041917698392245727713420", 182 | ]; 183 | #[test] 184 | fn test_isaac_value_stability() { 185 | use rand_isaac::IsaacRng; 186 | seeded_value_stability::(EXPECTED_ISAAC); 187 | } 188 | 189 | #[cfg(not(feature = "u64_digit"))] 190 | const EXPECTED_XOR: &[&str] = &[ 191 | "1", 192 | "0", 193 | "37", 194 | "395", 195 | "181116", 196 | "122718231117", 197 | "1068467172329355695001", 198 | "28246925743544411614293300167064395633287", 199 | "12750053187017853048648861493745244146555950255549630854523304068318587267293038", 200 | "53041498719137109355568081064978196049094604705283682101683207799515709404788873\ 201 | 53417136457745727045473194367732849819278740266658219147356315674940229288531", 202 | ]; 203 | #[cfg(feature = "u64_digit")] 204 | const EXPECTED_XOR: &[&str] = &[ 205 | "0", 206 | "1", 207 | "36", 208 | "970", 209 | "940965", 210 | "61158366130", 211 | "590484965100191554896", 212 | "34050066418951688801044382442803594076612", 213 | "29147581645599998811521651062569705291155276949983132826461704326818089074318948", 214 | "4990842894093964353439376569956547459232523176881032246435842690389845516810345611554402412893818283310117202233021355634125020654279500443420515862554775828", 215 | ]; 216 | 217 | #[test] 218 | fn test_xorshift_value_stability() { 219 | use rand_xorshift::XorShiftRng; 220 | seeded_value_stability::(EXPECTED_XOR); 221 | } 222 | } 223 | 224 | mod bigint { 225 | use crate::num_bigint::{BigInt, RandBigInt, RandomBits}; 226 | use num_traits::Zero; 227 | use rand::distributions::Uniform; 228 | use rand::{Rng, SeedableRng}; 229 | 230 | #[cfg(feature = "std")] 231 | fn thread_rng() -> impl Rng { 232 | rand::thread_rng() 233 | } 234 | #[cfg(not(feature = "std"))] 235 | fn thread_rng() -> impl Rng { 236 | // Chosen by fair dice roll 237 | rand::rngs::StdRng::seed_from_u64(4) 238 | } 239 | 240 | #[test] 241 | fn test_rand() { 242 | let mut rng = thread_rng(); 243 | let n: BigInt = rng.gen_bigint(137); 244 | assert!(n.bits() <= 137); 245 | assert!(rng.gen_bigint(0).is_zero()); 246 | } 247 | 248 | #[test] 249 | fn test_rand_bits() { 250 | let mut rng = thread_rng(); 251 | let n: BigInt = rng.sample(&RandomBits::new(137)); 252 | assert!(n.bits() <= 137); 253 | let z: BigInt = rng.sample(&RandomBits::new(0)); 254 | assert!(z.is_zero()); 255 | } 256 | 257 | #[test] 258 | fn test_rand_range() { 259 | let mut rng = thread_rng(); 260 | 261 | for _ in 0..10 { 262 | assert_eq!( 263 | rng.gen_bigint_range(&BigInt::from(236), &BigInt::from(237)), 264 | BigInt::from(236) 265 | ); 266 | } 267 | 268 | fn check(l: BigInt, u: BigInt) { 269 | let mut rng = thread_rng(); 270 | for _ in 0..1000 { 271 | let n: BigInt = rng.gen_bigint_range(&l, &u); 272 | assert!(n >= l); 273 | assert!(n < u); 274 | } 275 | } 276 | let l: BigInt = BigInt::from(403469000 + 2352); 277 | let u: BigInt = BigInt::from(403469000 + 3513); 278 | check(l.clone(), u.clone()); 279 | check(-l.clone(), u.clone()); 280 | check(-u.clone(), -l.clone()); 281 | } 282 | 283 | #[test] 284 | #[should_panic] 285 | fn test_zero_rand_range() { 286 | thread_rng().gen_bigint_range(&BigInt::from(54), &BigInt::from(54)); 287 | } 288 | 289 | #[test] 290 | #[should_panic] 291 | fn test_negative_rand_range() { 292 | let mut rng = thread_rng(); 293 | let l = BigInt::from(2352); 294 | let u = BigInt::from(3513); 295 | // Switching u and l should fail: 296 | let _n: BigInt = rng.gen_bigint_range(&u, &l); 297 | } 298 | 299 | #[test] 300 | fn test_rand_uniform() { 301 | let mut rng = thread_rng(); 302 | 303 | let tiny = Uniform::new(BigInt::from(236u32), BigInt::from(237u32)); 304 | for _ in 0..10 { 305 | assert_eq!(rng.sample(&tiny), BigInt::from(236u32)); 306 | } 307 | 308 | fn check(l: BigInt, u: BigInt) { 309 | let mut rng = thread_rng(); 310 | let range = Uniform::new(l.clone(), u.clone()); 311 | for _ in 0..1000 { 312 | let n: BigInt = rng.sample(&range); 313 | assert!(n >= l); 314 | assert!(n < u); 315 | } 316 | } 317 | let l: BigInt = BigInt::from(403469000 + 2352); 318 | let u: BigInt = BigInt::from(403469000 + 3513); 319 | check(l.clone(), u.clone()); 320 | check(-l.clone(), u.clone()); 321 | check(-u.clone(), -l.clone()); 322 | } 323 | 324 | fn seeded_value_stability(expected: &[&str]) { 325 | let mut seed = ::default(); 326 | for (i, x) in seed.as_mut().iter_mut().enumerate() { 327 | *x = (i as u8).wrapping_mul(191); 328 | } 329 | let mut rng = R::from_seed(seed); 330 | for (i, &s) in expected.iter().enumerate() { 331 | let n: BigInt = s.parse().unwrap(); 332 | let r = rng.gen_bigint((1 << i) + i); 333 | assert_eq!(n, r, "expected {}, got {}", n, r); 334 | } 335 | } 336 | #[cfg(not(feature = "u64_digit"))] 337 | const EXPECTED_CHACHA: &[&str] = &[ 338 | "0", 339 | "-6", 340 | "-1", 341 | "1321", 342 | "-147247", 343 | "8486373526", 344 | "-272736656290199720696", 345 | "2731152629387534140535423510744221288522", 346 | "-28820024790651190394679732038637785320661450462089347915910979466834461433196572", 347 | "501454570554170484799723603981439288209930393334472085317977614690773821680884844\ 348 | 8530978478667288338327570972869032358120588620346111979053742269317702532328", 349 | ]; 350 | 351 | #[cfg(feature = "u64_digit")] 352 | const EXPECTED_CHACHA: &[&str] = &[ 353 | "0", 354 | "-7", 355 | "-62", 356 | "105", 357 | "13025", 358 | "-33857814162", 359 | "768483926407291599143", 360 | "-42356168828789885585553598574661841382586", 361 | "28813250216034838684899917677182169473483558650956121225920149068989083656174824", 362 | "27056553770481404639717657695702187062015359344716548489861498121037858109133467\ 363 | 99640556108506718020020878739044048067894089601665199172215093468287730555599", 364 | ]; 365 | 366 | #[test] 367 | fn test_chacha_value_stability() { 368 | use rand_chacha::ChaChaRng; 369 | seeded_value_stability::(EXPECTED_CHACHA); 370 | } 371 | 372 | #[cfg(not(feature = "u64_digit"))] 373 | const EXPECTED_ISAAC: &[&str] = &[ 374 | "1", 375 | "0", 376 | "5", 377 | "113", 378 | "-132240", 379 | "-36348760761", 380 | "-365690596708430705434", 381 | "-14090753008246284277803606722552430292432", 382 | "-26313941628626248579319341019368550803676255307056857978955881718727601479436059", 383 | "-14563174552421101848999036239003801073335703811160945137332228646111920972691151\ 384 | 88341090358094331641182310792892459091016794928947242043358702692294695845817", 385 | ]; 386 | #[cfg(feature = "u64_digit")] 387 | const EXPECTED_ISAAC: &[&str] = &[ 388 | "-1", 389 | "-4", 390 | "-29", 391 | "1621", 392 | "23872", 393 | "-40371956434", 394 | "-350815272425024298187", 395 | "-38554888817044546636456097200348998322457", 396 | "7474426176220721712055446211154990065592106428397966654956172383998793852911545", 397 | "6168955541726830487961394166772329653532583907235825721475483003506842180688827\ 398 | 391385624898257369023912466314791483731902392667906094226608113824795883754631", 399 | ]; 400 | 401 | #[test] 402 | fn test_isaac_value_stability() { 403 | use rand_isaac::IsaacRng; 404 | seeded_value_stability::(EXPECTED_ISAAC); 405 | } 406 | 407 | #[cfg(not(feature = "u64_digit"))] 408 | const EXPECTED_XOR: &[&str] = &[ 409 | "-1", 410 | "-4", 411 | "11", 412 | "-1802", 413 | "966495", 414 | "-62592045703", 415 | "-602281783447192077116", 416 | "-34335811410223060575607987996861632509125", 417 | "29156580925282215857325937227200350542000244609280383263289720243118706105351199", 418 | "49920038676141573457451407325930326489996232208489690499754573826911037849083623\ 419 | 24546142615325187412887314466195222441945661833644117700809693098722026764846", 420 | ]; 421 | 422 | #[cfg(feature = "u64_digit")] 423 | const EXPECTED_XOR: &[&str] = &[ 424 | "-1", 425 | "-3", 426 | "4", 427 | "-228", 428 | "377276", 429 | "32032893086", 430 | "885120221048601050706", 431 | "33404877924318663206979407569537287223622", 432 | "-15253093455306269007559295940333933266263385975865952571271093251749752787075084", 433 | "4502641950394305250103130679458759592222756470562408577296380915684757985604969904\ 434 | 381774527626485128207406911227296090734227576935034372181808818486328078978", 435 | ]; 436 | 437 | #[test] 438 | fn test_xorshift_value_stability() { 439 | use rand_xorshift::XorShiftRng; 440 | seeded_value_stability::(EXPECTED_XOR); 441 | } 442 | } 443 | 444 | #[cfg(feature = "prime")] 445 | mod prime { 446 | use num_bigint::prime::probably_prime; 447 | use num_bigint::RandPrime; 448 | use rand::prelude::*; 449 | 450 | #[test] 451 | fn test_prime_small() { 452 | let mut rng = StdRng::from_seed([0u8; 32]); 453 | for n in 2..10 { 454 | let p = rng.gen_prime(n); 455 | 456 | assert_eq!(p.bits(), n); 457 | assert!(probably_prime(&p, 32)); 458 | } 459 | } 460 | 461 | #[test] 462 | fn test_gen_prime_1024() { 463 | let mut rng = StdRng::from_seed([0u8; 32]); 464 | let p = rng.gen_prime(1024); 465 | assert_eq!(p.bits(), 1024); 466 | } 467 | } 468 | -------------------------------------------------------------------------------- /tests/roots.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint_dig as num_bigint; 2 | extern crate num_integer; 3 | extern crate num_traits; 4 | 5 | #[cfg(feature = "rand")] 6 | extern crate rand; 7 | 8 | mod biguint { 9 | use crate::num_bigint::BigUint; 10 | use num_traits::{One, Pow, Zero}; 11 | use std::{i32, u32}; 12 | 13 | fn check>(x: T, n: u32) { 14 | let x: BigUint = x.into(); 15 | let root = x.nth_root(n); 16 | //println!("check {}.nth_root({}) = {}", x, n, root); 17 | 18 | if n == 2 { 19 | assert_eq!(root, x.sqrt()) 20 | } else if n == 3 { 21 | assert_eq!(root, x.cbrt()) 22 | } 23 | 24 | let lo = root.pow(n); 25 | assert!(lo <= x); 26 | assert_eq!(lo.nth_root(n), root); 27 | if !lo.is_zero() { 28 | assert_eq!((&lo - 1u32).nth_root(n), &root - 1u32); 29 | } 30 | 31 | let hi = (&root + 1u32).pow(n); 32 | assert!(hi > x); 33 | assert_eq!(hi.nth_root(n), &root + 1u32); 34 | assert_eq!((&hi - 1u32).nth_root(n), root); 35 | } 36 | 37 | #[test] 38 | fn test_sqrt() { 39 | check(99u32, 2); 40 | check(100u32, 2); 41 | check(120u32, 2); 42 | } 43 | 44 | #[test] 45 | fn test_cbrt() { 46 | check(8u32, 3); 47 | check(26u32, 3); 48 | } 49 | 50 | #[test] 51 | fn test_nth_root() { 52 | check(0u32, 1); 53 | check(10u32, 1); 54 | check(100u32, 4); 55 | } 56 | 57 | #[test] 58 | #[should_panic] 59 | fn test_nth_root_n_is_zero() { 60 | check(4u32, 0); 61 | } 62 | 63 | #[test] 64 | fn test_nth_root_big() { 65 | let x = BigUint::from(123_456_789_u32); 66 | let expected = BigUint::from(6u32); 67 | 68 | assert_eq!(x.nth_root(10), expected); 69 | check(x, 10); 70 | } 71 | 72 | #[test] 73 | fn test_nth_root_googol() { 74 | let googol = BigUint::from(10u32).pow(100u32); 75 | 76 | // perfect divisors of 100 77 | for &n in &[2, 4, 5, 10, 20, 25, 50, 100] { 78 | let expected = BigUint::from(10u32).pow(100u32 / n); 79 | assert_eq!(googol.nth_root(n), expected); 80 | check(googol.clone(), n); 81 | } 82 | } 83 | 84 | #[test] 85 | fn test_nth_root_twos() { 86 | const EXP: u32 = 12; 87 | const LOG2: usize = 1 << EXP; 88 | let x = BigUint::one() << LOG2; 89 | 90 | // the perfect divisors are just powers of two 91 | for exp in 1..EXP + 1 { 92 | let n = 2u32.pow(exp); 93 | let expected = BigUint::one() << (LOG2 / n as usize); 94 | assert_eq!(x.nth_root(n), expected); 95 | check(x.clone(), n); 96 | } 97 | 98 | // degenerate cases should return quickly 99 | assert!(x.nth_root(x.bits() as u32).is_one()); 100 | assert!(x.nth_root(i32::MAX as u32).is_one()); 101 | assert!(x.nth_root(u32::MAX).is_one()); 102 | } 103 | 104 | #[cfg(feature = "rand")] 105 | #[test] 106 | fn test_roots_rand() { 107 | #[cfg(feature = "std")] 108 | fn thread_rng() -> impl rand::Rng { 109 | rand::thread_rng() 110 | } 111 | #[cfg(not(feature = "std"))] 112 | fn thread_rng() -> impl rand::Rng { 113 | use rand::SeedableRng; 114 | // Chosen by fair dice roll 115 | rand::rngs::StdRng::seed_from_u64(4) 116 | } 117 | 118 | use crate::num_bigint::RandBigInt; 119 | use rand::distributions::Uniform; 120 | use rand::Rng; 121 | 122 | let rng = &mut thread_rng(); 123 | let bit_range = Uniform::new(0, 2048); 124 | let sample_bits: Vec<_> = rng.sample_iter(&bit_range).take(100).collect(); 125 | for bits in sample_bits { 126 | let x = rng.gen_biguint(bits); 127 | for n in 2..11 { 128 | check(x.clone(), n); 129 | } 130 | check(x.clone(), 100); 131 | } 132 | } 133 | 134 | #[test] 135 | fn test_roots_rand1() { 136 | // A random input that found regressions 137 | let s = "575981506858479247661989091587544744717244516135539456183849\ 138 | 986593934723426343633698413178771587697273822147578889823552\ 139 | 182702908597782734558103025298880194023243541613924361007059\ 140 | 353344183590348785832467726433749431093350684849462759540710\ 141 | 026019022227591412417064179299354183441181373862905039254106\ 142 | 4781867"; 143 | let x: BigUint = s.parse().unwrap(); 144 | 145 | check(x.clone(), 2); 146 | check(x.clone(), 3); 147 | check(x.clone(), 10); 148 | check(x.clone(), 100); 149 | } 150 | } 151 | 152 | mod bigint { 153 | use crate::num_bigint::BigInt; 154 | use num_traits::{Pow, Signed}; 155 | 156 | fn check(x: i64, n: u32) { 157 | let big_x = BigInt::from(x); 158 | let res = big_x.nth_root(n); 159 | 160 | if n == 2 { 161 | assert_eq!(&res, &big_x.sqrt()) 162 | } else if n == 3 { 163 | assert_eq!(&res, &big_x.cbrt()) 164 | } 165 | 166 | if big_x.is_negative() { 167 | assert!(res.pow(n) >= big_x); 168 | assert!((res - 1u32).pow(n) < big_x); 169 | } else { 170 | assert!(res.pow(n) <= big_x); 171 | assert!((res + 1u32).pow(n) > big_x); 172 | } 173 | } 174 | 175 | #[test] 176 | fn test_nth_root() { 177 | check(-100, 3); 178 | } 179 | 180 | #[test] 181 | #[should_panic] 182 | fn test_nth_root_x_neg_n_even() { 183 | check(-100, 4); 184 | } 185 | 186 | #[test] 187 | #[should_panic] 188 | fn test_sqrt_x_neg() { 189 | check(-4, 2); 190 | } 191 | 192 | #[test] 193 | fn test_cbrt() { 194 | check(8, 3); 195 | check(-8, 3); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /tests/serde.rs: -------------------------------------------------------------------------------- 1 | //! Test serialization and deserialization of `BigUint` and `BigInt` 2 | //! 3 | //! The serialized formats should not change, even if we change our 4 | //! internal representation, because we want to preserve forward and 5 | //! backward compatibility of serialized data! 6 | 7 | #![cfg(feature = "serde")] 8 | 9 | extern crate num_bigint_dig as num_bigint; 10 | extern crate num_traits; 11 | extern crate serde_test; 12 | 13 | use crate::num_bigint::{BigInt, BigUint}; 14 | use num_traits::{One, Zero}; 15 | use serde_test::{assert_tokens, Token}; 16 | 17 | #[test] 18 | fn biguint_zero() { 19 | let tokens = [Token::Seq { len: Some(0) }, Token::SeqEnd]; 20 | assert_tokens(&BigUint::zero(), &tokens); 21 | } 22 | 23 | #[test] 24 | fn bigint_zero() { 25 | let tokens = [ 26 | Token::Tuple { len: 2 }, 27 | Token::I8(0), 28 | Token::Seq { len: Some(0) }, 29 | Token::SeqEnd, 30 | Token::TupleEnd, 31 | ]; 32 | assert_tokens(&BigInt::zero(), &tokens); 33 | } 34 | 35 | #[test] 36 | fn biguint_one() { 37 | let tokens = [Token::Seq { len: Some(1) }, Token::U32(1), Token::SeqEnd]; 38 | assert_tokens(&BigUint::one(), &tokens); 39 | } 40 | 41 | #[test] 42 | fn bigint_one() { 43 | let tokens = [ 44 | Token::Tuple { len: 2 }, 45 | Token::I8(1), 46 | Token::Seq { len: Some(1) }, 47 | Token::U32(1), 48 | Token::SeqEnd, 49 | Token::TupleEnd, 50 | ]; 51 | assert_tokens(&BigInt::one(), &tokens); 52 | } 53 | 54 | #[test] 55 | fn bigint_negone() { 56 | let tokens = [ 57 | Token::Tuple { len: 2 }, 58 | Token::I8(-1), 59 | Token::Seq { len: Some(1) }, 60 | Token::U32(1), 61 | Token::SeqEnd, 62 | Token::TupleEnd, 63 | ]; 64 | assert_tokens(&-BigInt::one(), &tokens); 65 | } 66 | 67 | // Generated independently from python `hex(factorial(100))` 68 | const FACTORIAL_100: &'static [u32] = &[ 69 | 0x00000000, 0x00000000, 0x00000000, 0x2735c61a, 0xee8b02ea, 0xb3b72ed2, 0x9420c6ec, 0x45570cca, 70 | 0xdf103917, 0x943a321c, 0xeb21b5b2, 0x66ef9a70, 0xa40d16e9, 0x28d54bbd, 0xdc240695, 0x964ec395, 71 | 0x1b30, 72 | ]; 73 | 74 | #[test] 75 | fn biguint_factorial_100() { 76 | let n: BigUint = (1u8..101).product(); 77 | 78 | let mut tokens = vec![]; 79 | tokens.push(Token::Seq { 80 | len: Some(FACTORIAL_100.len()), 81 | }); 82 | tokens.extend(FACTORIAL_100.iter().map(|&u| Token::U32(u))); 83 | tokens.push(Token::SeqEnd); 84 | 85 | assert_tokens(&n, &tokens); 86 | } 87 | 88 | #[test] 89 | fn bigint_factorial_100() { 90 | let n: BigInt = (1i8..101).product(); 91 | 92 | let mut tokens = vec![]; 93 | tokens.push(Token::Tuple { len: 2 }); 94 | tokens.push(Token::I8(1)); 95 | tokens.push(Token::Seq { 96 | len: Some(FACTORIAL_100.len()), 97 | }); 98 | tokens.extend(FACTORIAL_100.iter().map(|&u| Token::U32(u))); 99 | tokens.push(Token::SeqEnd); 100 | tokens.push(Token::TupleEnd); 101 | 102 | assert_tokens(&n, &tokens); 103 | } 104 | -------------------------------------------------------------------------------- /tests/torture.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "rand")] 2 | 3 | extern crate num_bigint_dig as num_bigint; 4 | extern crate num_traits; 5 | extern crate rand; 6 | 7 | use crate::num_bigint::RandBigInt; 8 | use num_traits::Zero; 9 | use rand::prelude::*; 10 | 11 | fn test_mul_divide_torture_count(count: usize) { 12 | let bits_max = 1 << 12; 13 | #[cfg(target_pointer_width = "32")] 14 | let seed = [ 15 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16 | ]; 17 | #[cfg(target_pointer_width = "64")] 18 | let seed = [ 19 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 20 | 26, 27, 28, 29, 30, 31, 32, 21 | ]; 22 | let mut rng = rand::rngs::SmallRng::from_seed(seed); 23 | 24 | for _ in 0..count { 25 | // Test with numbers of random sizes: 26 | let xbits = rng.gen_range(0..bits_max); 27 | let ybits = rng.gen_range(0..bits_max); 28 | 29 | let x = rng.gen_biguint(xbits); 30 | let y = rng.gen_biguint(ybits); 31 | 32 | if x.is_zero() || y.is_zero() { 33 | continue; 34 | } 35 | 36 | let prod = &x * &y; 37 | assert_eq!(&prod / &x, y); 38 | assert_eq!(&prod / &y, x); 39 | } 40 | } 41 | 42 | #[test] 43 | fn test_mul_divide_torture() { 44 | test_mul_divide_torture_count(1000); 45 | } 46 | 47 | #[test] 48 | #[ignore] 49 | fn test_mul_divide_torture_long() { 50 | test_mul_divide_torture_count(1000000); 51 | } 52 | --------------------------------------------------------------------------------