aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md6
-rw-r--r--code/rust/Cargo.toml10
-rw-r--r--code/rust/src/main.rs106
4 files changed, 124 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e639424
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
1code/rust/Cargo.lock
2code/rust/target
diff --git a/README.md b/README.md
index 75f495a..7052d71 100644
--- a/README.md
+++ b/README.md
@@ -61,3 +61,9 @@ The folder `code/cpp` contains an experimental implementation of the ECM
61algorithm in C++. It works, but it is very slow: it requires suppport 61algorithm in C++. It works, but it is very slow: it requires suppport
62for compile-time big integers, which I implement in an inefficient way. I 62for compile-time big integers, which I implement in an inefficient way. I
63may optimize this code in the future. 63may optimize this code in the future.
64
65### Rust code
66
67This is pretty much the same as the Python code, I added it here because
68I wanted to play around with rust. From the `code/rust` folder you
69can run it with e.g. `cargo run -r -- 255000007030000033`.
diff --git a/code/rust/Cargo.toml b/code/rust/Cargo.toml
new file mode 100644
index 0000000..13d1df8
--- /dev/null
+++ b/code/rust/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "ecm"
3version = "0.1.0"
4edition = "2024"
5
6[dependencies]
7rand = "=0.8.5"
8num-integer = "=0.1.46"
9num-traits = "=0.2.19"
10num-bigint = { version = "=0.4.6", features = ["rand"] }
diff --git a/code/rust/src/main.rs b/code/rust/src/main.rs
new file mode 100644
index 0000000..ded1f59
--- /dev/null
+++ b/code/rust/src/main.rs
@@ -0,0 +1,106 @@
1use std::env;
2use std::fmt;
3use std::cmp;
4use rand::Rng;
5use num_integer::Integer;
6use num_traits::identities::{Zero, One};
7use num_bigint::{BigInt, RandomBits};
8
9#[derive(Clone)]
10enum Point {
11 NonZero((BigInt, BigInt)),
12 Zero
13}
14
15impl fmt::Display for Point {
16 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17 match self {
18 Point::NonZero((x, y)) => write!(f, "({x}, {y})"),
19 Point::Zero => write!(f, "∞")
20 }
21 }
22}
23
24fn inverse_mod(a: &BigInt, n: &BigInt) -> Result<BigInt, BigInt> {
25 let egcd = a.extended_gcd(n);
26 if egcd.gcd.is_one() { Ok(egcd.x) } else { Err(egcd.gcd) }
27}
28
29fn ec_sum(p: &Point, q: &Point, a: &BigInt, n: &BigInt) -> Result<Point, BigInt> {
30 // TODO: this should use references
31 let (px, py) = if let Point::NonZero((x, y)) = p {
32 (x, y)
33 } else {
34 return Ok(q.clone());
35 };
36
37 let (qx, qy) = if let Point::NonZero((x, y)) = q {
38 (x, y)
39 } else {
40 return Ok(p.clone());
41 };
42
43 if ((px - qx) % n).is_zero() && ((py + qy) % n).is_zero() {
44 return Ok(Point::Zero);
45 }
46
47 let k = if px != qx {
48 (py - qy) * inverse_mod(&(px - qx), n)?
49 } else {
50 (3 * px * px + a) * inverse_mod(&(py + qy), n)?
51 };
52
53 let x = &k * &k - px - qx;
54 let y = k * (px - &x) - py;
55
56 Ok(Point::NonZero((x.clone() % n, y.clone() % n)))
57}
58
59fn ec_mul(m: &BigInt, p: &Point, a: &BigInt, n: &BigInt) -> Result<Point, BigInt> {
60 if m.is_zero() {
61 return Ok(Point::Zero);
62 }
63
64 if (m % BigInt::from(2)).is_zero() {
65 ec_mul(&(m / 2), &ec_sum(p, p, a, n)?, a, n)
66 } else {
67 ec_sum(p, &ec_mul(&(m - 1), p, a, n)?, a, n)
68 }
69}
70
71
72// Elliptic curve factorization method
73// If n is prime, this method goes into an infinite loop
74fn find_factor(n: &BigInt) -> BigInt {
75 let mut rng = rand::thread_rng();
76 let bound = cmp::max(n.sqrt().sqrt().sqrt() + 2, BigInt::from(256));
77
78 loop {
79 let a = rng.sample::<BigInt, _>(RandomBits::new(256)) % n;
80 let x = rng.sample::<BigInt, _>(RandomBits::new(256)) % n;
81 let y = rng.sample::<BigInt, _>(RandomBits::new(256)) % n;
82 let mut p = Point::NonZero((x, y));
83
84 let mut m = BigInt::from(2);
85 while m < bound && !matches!(p, Point::Zero) {
86 match ec_mul(&m, &p, &a, n) {
87 Err(f) => {
88 println!("Factor {f} found with a = {a}, m = {m} and p = {p}");
89 return f;
90 },
91 Ok(new_p) => p = new_p
92 }
93 m += 1;
94 }
95 }
96}
97
98fn main() {
99 let args: Vec<String> = env::args().collect();
100 if let Ok(n) = args[1].parse::<BigInt>() {
101 let f = find_factor(&n);
102 println!("{} = {} * {}", &n, &f, &n / &f);
103 } else {
104 println!("Invalid argument {} (cannot convert to number)", args[1]);
105 }
106}

Generated with cgit - Back to sebastiano.tronto.net