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.
- square_rulerpack_native-0.2.0/Cargo.lock +249 -0
- square_rulerpack_native-0.2.0/Cargo.toml +26 -0
- square_rulerpack_native-0.2.0/LICENSE +21 -0
- square_rulerpack_native-0.2.0/PKG-INFO +54 -0
- square_rulerpack_native-0.2.0/README.md +34 -0
- square_rulerpack_native-0.2.0/pyproject.toml +31 -0
- square_rulerpack_native-0.2.0/src/lib.rs +156 -0
|
@@ -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
|
+
}
|