square-rulerpack-native 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,249 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "crossbeam-deque"
13
+ version = "0.8.8"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
16
+ dependencies = [
17
+ "crossbeam-epoch",
18
+ "crossbeam-utils",
19
+ ]
20
+
21
+ [[package]]
22
+ name = "crossbeam-epoch"
23
+ version = "0.9.21"
24
+ source = "registry+https://github.com/rust-lang/crates.io-index"
25
+ checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
26
+ dependencies = [
27
+ "crossbeam-utils",
28
+ ]
29
+
30
+ [[package]]
31
+ name = "crossbeam-utils"
32
+ version = "0.8.23"
33
+ source = "registry+https://github.com/rust-lang/crates.io-index"
34
+ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
35
+
36
+ [[package]]
37
+ name = "either"
38
+ version = "1.19.0"
39
+ source = "registry+https://github.com/rust-lang/crates.io-index"
40
+ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
41
+
42
+ [[package]]
43
+ name = "heck"
44
+ version = "0.5.0"
45
+ source = "registry+https://github.com/rust-lang/crates.io-index"
46
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
47
+
48
+ [[package]]
49
+ name = "libc"
50
+ version = "0.2.191"
51
+ source = "registry+https://github.com/rust-lang/crates.io-index"
52
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
53
+
54
+ [[package]]
55
+ name = "num-bigint"
56
+ version = "0.4.8"
57
+ source = "registry+https://github.com/rust-lang/crates.io-index"
58
+ checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
59
+ dependencies = [
60
+ "num-integer",
61
+ "num-traits",
62
+ ]
63
+
64
+ [[package]]
65
+ name = "num-integer"
66
+ version = "0.1.47"
67
+ source = "registry+https://github.com/rust-lang/crates.io-index"
68
+ checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
69
+ dependencies = [
70
+ "num-traits",
71
+ ]
72
+
73
+ [[package]]
74
+ name = "num-traits"
75
+ version = "0.2.19"
76
+ source = "registry+https://github.com/rust-lang/crates.io-index"
77
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
78
+ dependencies = [
79
+ "autocfg",
80
+ ]
81
+
82
+ [[package]]
83
+ name = "once_cell"
84
+ version = "1.21.4"
85
+ source = "registry+https://github.com/rust-lang/crates.io-index"
86
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
87
+
88
+ [[package]]
89
+ name = "portable-atomic"
90
+ version = "1.15.0"
91
+ source = "registry+https://github.com/rust-lang/crates.io-index"
92
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
93
+
94
+ [[package]]
95
+ name = "proc-macro2"
96
+ version = "1.0.107"
97
+ source = "registry+https://github.com/rust-lang/crates.io-index"
98
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
99
+ dependencies = [
100
+ "unicode-ident",
101
+ ]
102
+
103
+ [[package]]
104
+ name = "pyo3"
105
+ version = "0.30.1"
106
+ source = "registry+https://github.com/rust-lang/crates.io-index"
107
+ checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
108
+ dependencies = [
109
+ "libc",
110
+ "num-bigint",
111
+ "num-traits",
112
+ "once_cell",
113
+ "portable-atomic",
114
+ "pyo3-build-config",
115
+ "pyo3-ffi",
116
+ "pyo3-macros",
117
+ ]
118
+
119
+ [[package]]
120
+ name = "pyo3-build-config"
121
+ version = "0.30.1"
122
+ source = "registry+https://github.com/rust-lang/crates.io-index"
123
+ checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
124
+ dependencies = [
125
+ "target-lexicon",
126
+ ]
127
+
128
+ [[package]]
129
+ name = "pyo3-ffi"
130
+ version = "0.30.1"
131
+ source = "registry+https://github.com/rust-lang/crates.io-index"
132
+ checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
133
+ dependencies = [
134
+ "libc",
135
+ "pyo3-build-config",
136
+ ]
137
+
138
+ [[package]]
139
+ name = "pyo3-macros"
140
+ version = "0.30.1"
141
+ source = "registry+https://github.com/rust-lang/crates.io-index"
142
+ checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
143
+ dependencies = [
144
+ "proc-macro2",
145
+ "pyo3-macros-backend",
146
+ "quote",
147
+ "syn",
148
+ ]
149
+
150
+ [[package]]
151
+ name = "pyo3-macros-backend"
152
+ version = "0.30.1"
153
+ source = "registry+https://github.com/rust-lang/crates.io-index"
154
+ checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
155
+ dependencies = [
156
+ "heck",
157
+ "proc-macro2",
158
+ "quote",
159
+ "syn",
160
+ ]
161
+
162
+ [[package]]
163
+ name = "quote"
164
+ version = "1.0.47"
165
+ source = "registry+https://github.com/rust-lang/crates.io-index"
166
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
167
+ dependencies = [
168
+ "proc-macro2",
169
+ ]
170
+
171
+ [[package]]
172
+ name = "rayon"
173
+ version = "1.12.0"
174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
175
+ checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
176
+ dependencies = [
177
+ "either",
178
+ "rayon-core",
179
+ ]
180
+
181
+ [[package]]
182
+ name = "rayon-core"
183
+ version = "1.13.0"
184
+ source = "registry+https://github.com/rust-lang/crates.io-index"
185
+ checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
186
+ dependencies = [
187
+ "crossbeam-deque",
188
+ "crossbeam-utils",
189
+ ]
190
+
191
+ [[package]]
192
+ name = "rulerpack"
193
+ version = "0.3.1"
194
+ source = "registry+https://github.com/rust-lang/crates.io-index"
195
+ checksum = "5719c79cb15f909462649c00e447e222e20d79fd14b193882800679872b42cc3"
196
+ dependencies = [
197
+ "num-bigint",
198
+ "num-integer",
199
+ "num-traits",
200
+ "rayon",
201
+ ]
202
+
203
+ [[package]]
204
+ name = "square-rulerpack"
205
+ version = "0.2.0"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "6ed52ed5e1dc61c06ad2e25fa633abc9bd7fda94c5357d7b7802d18c5a5e6935"
208
+ dependencies = [
209
+ "num-bigint",
210
+ "num-integer",
211
+ "num-traits",
212
+ "rayon",
213
+ "rulerpack",
214
+ ]
215
+
216
+ [[package]]
217
+ name = "square-rulerpack-native"
218
+ version = "0.2.0"
219
+ dependencies = [
220
+ "num-bigint",
221
+ "num-traits",
222
+ "pyo3",
223
+ "rayon",
224
+ "rulerpack",
225
+ "square-rulerpack",
226
+ ]
227
+
228
+ [[package]]
229
+ name = "syn"
230
+ version = "3.0.10"
231
+ source = "registry+https://github.com/rust-lang/crates.io-index"
232
+ checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79"
233
+ dependencies = [
234
+ "proc-macro2",
235
+ "quote",
236
+ "unicode-ident",
237
+ ]
238
+
239
+ [[package]]
240
+ name = "target-lexicon"
241
+ version = "0.13.6"
242
+ source = "registry+https://github.com/rust-lang/crates.io-index"
243
+ checksum = "8c447be3a2abfa84b2d91680c56600bd6b2873866de27b36ec911be705e291da"
244
+
245
+ [[package]]
246
+ name = "unicode-ident"
247
+ version = "1.0.27"
248
+ source = "registry+https://github.com/rust-lang/crates.io-index"
249
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
@@ -0,0 +1,26 @@
1
+ [package]
2
+ name = "square-rulerpack-native"
3
+ version = "0.2.0"
4
+ edition = "2021"
5
+ license = "MIT"
6
+ description = "Lars Rocha's square-rulerpack quadratic sieve (Rust) as a Python extension module."
7
+ repository = "https://github.com/oppressionslayer/square-rulerpack-py"
8
+ authors = ["Lars Rocha"]
9
+ readme = "README.md"
10
+
11
+ [lib]
12
+ name = "square_rulerpack_native"
13
+ crate-type = ["cdylib"]
14
+
15
+ [dependencies]
16
+ pyo3 = { version = "0.30", features = ["extension-module", "abi3-py310", "num-bigint"] }
17
+ square-rulerpack = "0.2.0"
18
+ rulerpack = { version = "0.3.1", features = ["big"] }
19
+ num-bigint = "0.4"
20
+ num-traits = "0.2"
21
+ rayon = "1"
22
+
23
+ [profile.release]
24
+ opt-level = 3
25
+ lto = "thin"
26
+ codegen-units = 1
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lars Rocha
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.4
2
+ Name: square-rulerpack-native
3
+ Version: 0.2.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Science/Research
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Rust
8
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
9
+ License-File: LICENSE
10
+ Summary: Lars Rocha's square-rulerpack quadratic sieve (Rust, double large primes, AVX2) compiled as a Python extension: factor 40-100 digit numbers from Python at native speed.
11
+ Keywords: quadratic-sieve,siqs,factorization,number-theory,rust,pyo3
12
+ Author: Lars Rocha
13
+ License-Expression: MIT
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
16
+ Project-URL: Homepage, https://github.com/oppressionslayer/square-rulerpack-py
17
+ Project-URL: Pure Python package, https://pypi.org/project/square-rulerpack/
18
+ Project-URL: Rust crate, https://crates.io/crates/square-rulerpack
19
+
20
+ # square-rulerpack-native
21
+
22
+ Lars Rocha's [square-rulerpack](https://crates.io/crates/square-rulerpack) factoring engine
23
+ (self-initialising quadratic sieve with double large primes, AVX2 kernels, rayon threads, in Rust)
24
+ compiled as a Python extension module with PyO3. It is the fast path of the pure-Python
25
+ [square-rulerpack](https://pypi.org/project/square-rulerpack/) package, which does the teaching;
26
+ this module does the factoring.
27
+
28
+ ```sh
29
+ pip install square-rulerpack[native] # or: pip install square-rulerpack-native
30
+ ```
31
+
32
+ ```python
33
+ import square_rulerpack_native as srn
34
+ srn.factor_completely(50726044447758565750355444206008211963939957754977146054012847169421070122136537, threads=8)
35
+ srn.factor(n, threads=8) # one nontrivial factor from the sieve, or None
36
+ srn.is_prime(2**61 - 1) # strong probable-prime test
37
+ srn.factor_completely(n, threads=8, progress=lambda stage, full, need, partials, polys: print(stage, full, need))
38
+ ```
39
+
40
+ Through the pure package it is the default engine once installed:
41
+
42
+ ```python
43
+ import square_rulerpack as sq
44
+ sq.factor_completely(n, workers=8) # engine="auto": Rust when installed, Python otherwise
45
+ ```
46
+
47
+ Python ints cross as big integers (no string round trip). The GIL is released while the sieve
48
+ runs; Ctrl-C does not interrupt it. The engine's switches (`SIQS_Q2`, `SIQS_SMALL`, `SIQS_EXACT`,
49
+ `SIQS_DLP`, …) are read from the environment at call time, exactly as the Rust CLI reads them;
50
+ the pure package sets them from its `Settings`. Wheels are abi3 (one wheel per platform for
51
+ every Python ≥ 3.10); building from the sdist needs a Rust toolchain.
52
+
53
+ MIT, as the crate.
54
+
@@ -0,0 +1,34 @@
1
+ # square-rulerpack-native
2
+
3
+ Lars Rocha's [square-rulerpack](https://crates.io/crates/square-rulerpack) factoring engine
4
+ (self-initialising quadratic sieve with double large primes, AVX2 kernels, rayon threads, in Rust)
5
+ compiled as a Python extension module with PyO3. It is the fast path of the pure-Python
6
+ [square-rulerpack](https://pypi.org/project/square-rulerpack/) package, which does the teaching;
7
+ this module does the factoring.
8
+
9
+ ```sh
10
+ pip install square-rulerpack[native] # or: pip install square-rulerpack-native
11
+ ```
12
+
13
+ ```python
14
+ import square_rulerpack_native as srn
15
+ srn.factor_completely(50726044447758565750355444206008211963939957754977146054012847169421070122136537, threads=8)
16
+ srn.factor(n, threads=8) # one nontrivial factor from the sieve, or None
17
+ srn.is_prime(2**61 - 1) # strong probable-prime test
18
+ srn.factor_completely(n, threads=8, progress=lambda stage, full, need, partials, polys: print(stage, full, need))
19
+ ```
20
+
21
+ Through the pure package it is the default engine once installed:
22
+
23
+ ```python
24
+ import square_rulerpack as sq
25
+ sq.factor_completely(n, workers=8) # engine="auto": Rust when installed, Python otherwise
26
+ ```
27
+
28
+ Python ints cross as big integers (no string round trip). The GIL is released while the sieve
29
+ runs; Ctrl-C does not interrupt it. The engine's switches (`SIQS_Q2`, `SIQS_SMALL`, `SIQS_EXACT`,
30
+ `SIQS_DLP`, …) are read from the environment at call time, exactly as the Rust CLI reads them;
31
+ the pure package sets them from its `Settings`. Wheels are abi3 (one wheel per platform for
32
+ every Python ≥ 3.10); building from the sdist needs a Rust toolchain.
33
+
34
+ MIT, as the crate.
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.7,<2.0"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "square-rulerpack-native"
7
+ version = "0.2.0"
8
+ description = "Lars Rocha's square-rulerpack quadratic sieve (Rust, double large primes, AVX2) compiled as a Python extension: factor 40-100 digit numbers from Python at native speed."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{name = "Lars Rocha"}]
14
+ keywords = ["quadratic-sieve", "siqs", "factorization", "number-theory", "rust", "pyo3"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Science/Research",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Rust",
20
+ "Topic :: Scientific/Engineering :: Mathematics",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/oppressionslayer/square-rulerpack-py"
25
+ "Rust crate" = "https://crates.io/crates/square-rulerpack"
26
+ "Pure Python package" = "https://pypi.org/project/square-rulerpack/"
27
+
28
+ [tool.maturin]
29
+ module-name = "square_rulerpack_native"
30
+ features = ["pyo3/extension-module"]
31
+ strip = true
@@ -0,0 +1,156 @@
1
+ //! square-rulerpack for Python. Python ints cross as `BigUint` (pyo3's `num-bigint` feature), the
2
+ //! sieve runs with the GIL released on a rayon pool of the requested size, and the engine's
3
+ //! progress hook can call back into Python.
4
+ //!
5
+ //! The engine reads its switches (`SIQS_Q2`, `SIQS_SMALL`, `SIQS_EXACT`, …) from the process
6
+ //! environment at call time; the pure-Python package sets them from its `Settings` before calling.
7
+ use std::sync::Mutex;
8
+
9
+ use num_bigint::BigUint;
10
+ use num_traits::{One, Zero};
11
+ use pyo3::exceptions::{PyRuntimeError, PyValueError};
12
+ use pyo3::prelude::*;
13
+
14
+ /// The Python callable the progress hook forwards to (set for the duration of one call).
15
+ static PROGRESS: Mutex<Option<Py<PyAny>>> = Mutex::new(None);
16
+
17
+ /// The engine's hook is a plain `fn` pointer kept in a thread-local, so it fires on the thread
18
+ /// that called `factor`; that thread has released the GIL, so we re-attach to call Python.
19
+ fn py_hook(stage: u32, full: usize, need: usize, partials: usize, polys: usize) {
20
+ let cb = PROGRESS.lock().ok().and_then(|g| g.as_ref().map(|c| c.clone_ref_detached()));
21
+ if let Some(cb) = cb {
22
+ Python::attach(|py| {
23
+ if let Err(e) = cb.call1(py, (stage, full, need, partials, polys)) {
24
+ e.print(py);
25
+ }
26
+ });
27
+ }
28
+ }
29
+
30
+ trait CloneDetached {
31
+ fn clone_ref_detached(&self) -> Py<PyAny>;
32
+ }
33
+ impl CloneDetached for Py<PyAny> {
34
+ fn clone_ref_detached(&self) -> Py<PyAny> {
35
+ Python::attach(|py| self.clone_ref(py))
36
+ }
37
+ }
38
+
39
+ fn pool(threads: Option<usize>) -> PyResult<rayon::ThreadPool> {
40
+ let t = match threads {
41
+ Some(0) | None => std::thread::available_parallelism().map(|n| (n.get() / 2).max(1)).unwrap_or(1),
42
+ Some(t) => t,
43
+ };
44
+ rayon::ThreadPoolBuilder::new()
45
+ .num_threads(t)
46
+ .build()
47
+ .map_err(|e| PyRuntimeError::new_err(format!("rayon pool: {e}")))
48
+ }
49
+
50
+ fn with_progress<T>(py: Python<'_>, progress: Option<Py<PyAny>>, threads: Option<usize>,
51
+ f: impl FnOnce() -> T + Send) -> PyResult<T>
52
+ where
53
+ T: Send,
54
+ {
55
+ let pool = pool(threads)?;
56
+ let hooked = progress.is_some();
57
+ if let Some(cb) = progress {
58
+ *PROGRESS.lock().map_err(|_| PyRuntimeError::new_err("progress lock"))? = Some(cb);
59
+ }
60
+ let out = py.detach(|| {
61
+ pool.install(|| {
62
+ if hooked {
63
+ square_rulerpack::siqs::set_progress_hook(Some(py_hook));
64
+ }
65
+ let r = f();
66
+ square_rulerpack::siqs::set_progress_hook(None);
67
+ r
68
+ })
69
+ });
70
+ if hooked {
71
+ if let Ok(mut g) = PROGRESS.lock() {
72
+ *g = None;
73
+ }
74
+ }
75
+ Ok(out)
76
+ }
77
+
78
+ fn check(n: &BigUint) -> PyResult<()> {
79
+ if n.is_zero() {
80
+ return Err(PyValueError::new_err("n must be a positive integer"));
81
+ }
82
+ Ok(())
83
+ }
84
+
85
+ /// The complete factorisation of n: sorted prime factors with multiplicity (small primes by
86
+ /// trial division, perfect powers, then the self-initialising quadratic sieve on every composite
87
+ /// piece). `threads` is the rayon pool size (default half the hardware threads). `progress`, if
88
+ /// given, is called as progress(stage, full, need, partials, polys) with stage 0 preparing,
89
+ /// 1 collecting, 2 matrix, 3 square root. The GIL is released while the sieve runs; Ctrl-C does
90
+ /// not interrupt it.
91
+ #[pyfunction]
92
+ #[pyo3(signature = (n, threads=None, progress=None))]
93
+ fn factor_completely(py: Python<'_>, n: BigUint, threads: Option<usize>, progress: Option<Py<PyAny>>) -> PyResult<Vec<BigUint>> {
94
+ check(&n)?;
95
+ if n.is_one() {
96
+ return Ok(vec![]);
97
+ }
98
+ with_progress(py, progress, threads, move || square_rulerpack::siqs::factor_completely(&n))
99
+ }
100
+
101
+ /// One nontrivial factor of n from the sieve alone, or None (prime, a prime power the sieve
102
+ /// does not handle, too small, or unlucky). Use `factor_completely` for the whole factorisation.
103
+ #[pyfunction]
104
+ #[pyo3(signature = (n, threads=None, progress=None))]
105
+ fn factor(py: Python<'_>, n: BigUint, threads: Option<usize>, progress: Option<Py<PyAny>>) -> PyResult<Option<BigUint>> {
106
+ check(&n)?;
107
+ with_progress(py, progress, threads, move || square_rulerpack::siqs::factor(&n))
108
+ }
109
+
110
+ /// Primality: deterministic Miller–Rabin below 2^64 (the engine's `is_prime_u64`), rulerpack's
111
+ /// strong probable-prime test above. (rulerpack 0.3.1's `is_prime_big` returns false for the
112
+ /// primes it uses as witnesses, 2..37, so small n must not go through it.)
113
+ #[pyfunction]
114
+ fn is_prime(n: BigUint) -> bool {
115
+ match u64::try_from(&n) {
116
+ Ok(v) => square_rulerpack::siqs::is_prime_u64(v),
117
+ Err(_) => rulerpack::big::is_prime_big(&n),
118
+ }
119
+ }
120
+
121
+ /// The version of this binding.
122
+ #[pyfunction]
123
+ fn version() -> &'static str {
124
+ env!("CARGO_PKG_VERSION")
125
+ }
126
+
127
+ /// The version of the square-rulerpack engine crate linked in.
128
+ #[pyfunction]
129
+ fn engine_version() -> &'static str {
130
+ "0.2.0"
131
+ }
132
+
133
+ /// Whether the engine will use its AVX2 kernels on this machine.
134
+ #[pyfunction]
135
+ fn have_avx2() -> bool {
136
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
137
+ {
138
+ std::env::var("SIQS_NO_AVX2").is_err() && std::arch::is_x86_feature_detected!("avx2")
139
+ }
140
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
141
+ {
142
+ false
143
+ }
144
+ }
145
+
146
+ #[pymodule]
147
+ fn square_rulerpack_native(m: &Bound<'_, PyModule>) -> PyResult<()> {
148
+ m.add_function(wrap_pyfunction!(factor_completely, m)?)?;
149
+ m.add_function(wrap_pyfunction!(factor, m)?)?;
150
+ m.add_function(wrap_pyfunction!(is_prime, m)?)?;
151
+ m.add_function(wrap_pyfunction!(version, m)?)?;
152
+ m.add_function(wrap_pyfunction!(engine_version, m)?)?;
153
+ m.add_function(wrap_pyfunction!(have_avx2, m)?)?;
154
+ m.add("__version__", env!("CARGO_PKG_VERSION"))?;
155
+ Ok(())
156
+ }