foxmath 0.3.0__tar.gz → 0.4.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.
- {foxmath-0.3.0/src/foxmath.egg-info → foxmath-0.4.0}/PKG-INFO +13 -3
- {foxmath-0.3.0 → foxmath-0.4.0}/README.md +12 -2
- {foxmath-0.3.0 → foxmath-0.4.0}/pyproject.toml +1 -1
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath/foxmath.py +63 -8
- {foxmath-0.3.0 → foxmath-0.4.0/src/foxmath.egg-info}/PKG-INFO +13 -3
- {foxmath-0.3.0 → foxmath-0.4.0}/tests/test_cli.py +23 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/tests/test_foxmath.py +24 -1
- {foxmath-0.3.0 → foxmath-0.4.0}/LICENSE +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/setup.cfg +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath/__init__.py +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath.egg-info/SOURCES.txt +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath.egg-info/dependency_links.txt +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath.egg-info/entry_points.txt +0 -0
- {foxmath-0.3.0 → foxmath-0.4.0}/src/foxmath.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foxmath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Minimalist CLI for math & cryptography exploration 🦊
|
|
5
5
|
Author-email: Abhrankan Chakrabarti <abhrankan@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -28,12 +28,13 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
28
28
|
## Features
|
|
29
29
|
- Legendre symbol
|
|
30
30
|
- Euler/Hermann Machin-like π approximation
|
|
31
|
-
- Elliptic curve point addition (over finite fields)
|
|
31
|
+
- Elliptic curve point addition (over finite fields), including
|
|
32
|
+
named curves (secp256k1) with on-curve result validation
|
|
32
33
|
- Chinese Remainder Theorem solver (handles non-coprime moduli)
|
|
33
34
|
- Continued fraction expansion and convergents
|
|
34
35
|
- Symlink-friendly (foxmath-legendre, foxmath-pi, foxmath-ecadd, foxmath-crt, foxmath-cf)
|
|
35
36
|
- JSON output mode
|
|
36
|
-
- Coming soon: challenge mode
|
|
37
|
+
- Coming soon: challenge mode
|
|
37
38
|
|
|
38
39
|
## Installation
|
|
39
40
|
|
|
@@ -72,6 +73,15 @@ foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
|
72
73
|
Result point: (14, 2)
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
```bash
|
|
77
|
+
# Named curve (secp256k1) — computes 2G by default
|
|
78
|
+
foxmath ecadd --curve secp256k1
|
|
79
|
+
```
|
|
80
|
+
```
|
|
81
|
+
Result point: (89565891926547004231252920425935692360644145829622209833684329913297188986597, 12158399299693830322967808612713398636155367887041628176798871954788371653930)
|
|
82
|
+
✓ on curve
|
|
83
|
+
```
|
|
84
|
+
|
|
75
85
|
```bash
|
|
76
86
|
# Chinese Remainder Theorem
|
|
77
87
|
foxmath crt --r 2 3 2 --m 3 5 7
|
|
@@ -9,12 +9,13 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
9
9
|
## Features
|
|
10
10
|
- Legendre symbol
|
|
11
11
|
- Euler/Hermann Machin-like π approximation
|
|
12
|
-
- Elliptic curve point addition (over finite fields)
|
|
12
|
+
- Elliptic curve point addition (over finite fields), including
|
|
13
|
+
named curves (secp256k1) with on-curve result validation
|
|
13
14
|
- Chinese Remainder Theorem solver (handles non-coprime moduli)
|
|
14
15
|
- Continued fraction expansion and convergents
|
|
15
16
|
- Symlink-friendly (foxmath-legendre, foxmath-pi, foxmath-ecadd, foxmath-crt, foxmath-cf)
|
|
16
17
|
- JSON output mode
|
|
17
|
-
- Coming soon: challenge mode
|
|
18
|
+
- Coming soon: challenge mode
|
|
18
19
|
|
|
19
20
|
## Installation
|
|
20
21
|
|
|
@@ -53,6 +54,15 @@ foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
|
53
54
|
Result point: (14, 2)
|
|
54
55
|
```
|
|
55
56
|
|
|
57
|
+
```bash
|
|
58
|
+
# Named curve (secp256k1) — computes 2G by default
|
|
59
|
+
foxmath ecadd --curve secp256k1
|
|
60
|
+
```
|
|
61
|
+
```
|
|
62
|
+
Result point: (89565891926547004231252920425935692360644145829622209833684329913297188986597, 12158399299693830322967808612713398636155367887041628176798871954788371653930)
|
|
63
|
+
✓ on curve
|
|
64
|
+
```
|
|
65
|
+
|
|
56
66
|
```bash
|
|
57
67
|
# Chinese Remainder Theorem
|
|
58
68
|
foxmath crt --r 2 3 2 --m 3 5 7
|
|
@@ -54,6 +54,28 @@ def ec_point_add(x1, y1, x2, y2, a, p):
|
|
|
54
54
|
y3 = (lam * (x1 - x3) - y1) % p
|
|
55
55
|
return x3, y3
|
|
56
56
|
|
|
57
|
+
# Named curve presets: a, b, p, and the standard generator point G (if defined).
|
|
58
|
+
CURVES = {
|
|
59
|
+
"secp256k1": {
|
|
60
|
+
"a": 0,
|
|
61
|
+
"b": 7,
|
|
62
|
+
"p": 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,
|
|
63
|
+
"gx": 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
|
|
64
|
+
"gy": 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
|
|
65
|
+
},
|
|
66
|
+
"toy97": { # small curve for quick hand-checkable examples: y^2 = x^3 + 2x + 3 (mod 97)
|
|
67
|
+
"a": 2,
|
|
68
|
+
"b": 3,
|
|
69
|
+
"p": 97,
|
|
70
|
+
"gx": 3,
|
|
71
|
+
"gy": 6,
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
def is_on_curve(x: int, y: int, a: int, b: int, p: int) -> bool:
|
|
76
|
+
"""Check y^2 = x^3 + a*x + b (mod p)."""
|
|
77
|
+
return (y * y - (x ** 3 + a * x + b)) % p == 0
|
|
78
|
+
|
|
57
79
|
def _extended_gcd(a: int, b: int):
|
|
58
80
|
"""Returns (g, x, y) such that a*x + b*y == g == gcd(a, b)."""
|
|
59
81
|
old_r, r = a, b
|
|
@@ -171,12 +193,14 @@ def main():
|
|
|
171
193
|
|
|
172
194
|
# Elliptic curve add
|
|
173
195
|
ec = subparsers.add_parser("ecadd", help="Elliptic curve point addition")
|
|
174
|
-
ec.add_argument("--
|
|
175
|
-
|
|
176
|
-
ec.add_argument("--
|
|
177
|
-
ec.add_argument("--
|
|
178
|
-
ec.add_argument("--
|
|
179
|
-
ec.add_argument("--
|
|
196
|
+
ec.add_argument("--curve", choices=sorted(CURVES.keys()),
|
|
197
|
+
help="Named curve (provides a, b, p, and generator G)")
|
|
198
|
+
ec.add_argument("--x1", type=int, help="Defaults to G's x if --curve is given")
|
|
199
|
+
ec.add_argument("--y1", type=int, help="Defaults to G's y if --curve is given")
|
|
200
|
+
ec.add_argument("--x2", type=int, help="Defaults to (x1,y1) if omitted (i.e. doubling)")
|
|
201
|
+
ec.add_argument("--y2", type=int, help="Defaults to (x1,y1) if omitted (i.e. doubling)")
|
|
202
|
+
ec.add_argument("--a", type=int, help="Curve parameter a (overrides --curve if given)")
|
|
203
|
+
ec.add_argument("--p", type=int, help="Prime modulus (overrides --curve if given)")
|
|
180
204
|
|
|
181
205
|
# Chinese Remainder Theorem
|
|
182
206
|
crt = subparsers.add_parser("crt", help="Solve a system of congruences x = r (mod m)")
|
|
@@ -207,10 +231,41 @@ def main():
|
|
|
207
231
|
print(f"π ≈ {approx} ({args.terms} terms)")
|
|
208
232
|
|
|
209
233
|
elif cmd == "ecadd" or args.command == "ecadd":
|
|
210
|
-
|
|
211
|
-
|
|
234
|
+
a, b = args.a, None
|
|
235
|
+
p = args.p
|
|
236
|
+
x1, y1 = args.x1, args.y1
|
|
237
|
+
|
|
238
|
+
if args.curve:
|
|
239
|
+
preset = CURVES[args.curve]
|
|
240
|
+
a = preset["a"] if a is None else a
|
|
241
|
+
p = preset["p"] if p is None else p
|
|
242
|
+
b = preset["b"]
|
|
243
|
+
if x1 is None:
|
|
244
|
+
x1, y1 = preset["gx"], preset["gy"]
|
|
245
|
+
elif a is None:
|
|
246
|
+
a = -3 # historical default for manual (non-curve) mode
|
|
247
|
+
|
|
248
|
+
if a is None or p is None or x1 is None or y1 is None:
|
|
249
|
+
raise ValueError(
|
|
250
|
+
"Provide --curve NAME, or at least --p --x1 --y1 manually "
|
|
251
|
+
"(--a defaults to -3 if omitted)."
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
x2 = x1 if args.x2 is None else args.x2
|
|
255
|
+
y2 = y1 if args.y2 is None else args.y2
|
|
256
|
+
|
|
257
|
+
x3, y3 = ec_point_add(x1, y1, x2, y2, a, p)
|
|
258
|
+
result.update({
|
|
259
|
+
"command": "ecadd", "curve": args.curve,
|
|
260
|
+
"p1": [x1, y1], "p2": [x2, y2], "result": (x3, y3),
|
|
261
|
+
})
|
|
262
|
+
if b is not None:
|
|
263
|
+
result["result_on_curve"] = is_on_curve(x3, y3, a, b, p)
|
|
212
264
|
if not json_output:
|
|
213
265
|
print(f"Result point: ({x3}, {y3})")
|
|
266
|
+
if b is not None:
|
|
267
|
+
status = "✓ on curve" if result["result_on_curve"] else "✗ NOT on curve"
|
|
268
|
+
print(f" {status}")
|
|
214
269
|
|
|
215
270
|
elif cmd == "crt" or args.command == "crt":
|
|
216
271
|
x, m = crt_solve(args.r, args.m)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foxmath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Minimalist CLI for math & cryptography exploration 🦊
|
|
5
5
|
Author-email: Abhrankan Chakrabarti <abhrankan@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -28,12 +28,13 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
28
28
|
## Features
|
|
29
29
|
- Legendre symbol
|
|
30
30
|
- Euler/Hermann Machin-like π approximation
|
|
31
|
-
- Elliptic curve point addition (over finite fields)
|
|
31
|
+
- Elliptic curve point addition (over finite fields), including
|
|
32
|
+
named curves (secp256k1) with on-curve result validation
|
|
32
33
|
- Chinese Remainder Theorem solver (handles non-coprime moduli)
|
|
33
34
|
- Continued fraction expansion and convergents
|
|
34
35
|
- Symlink-friendly (foxmath-legendre, foxmath-pi, foxmath-ecadd, foxmath-crt, foxmath-cf)
|
|
35
36
|
- JSON output mode
|
|
36
|
-
- Coming soon: challenge mode
|
|
37
|
+
- Coming soon: challenge mode
|
|
37
38
|
|
|
38
39
|
## Installation
|
|
39
40
|
|
|
@@ -72,6 +73,15 @@ foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
|
72
73
|
Result point: (14, 2)
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
```bash
|
|
77
|
+
# Named curve (secp256k1) — computes 2G by default
|
|
78
|
+
foxmath ecadd --curve secp256k1
|
|
79
|
+
```
|
|
80
|
+
```
|
|
81
|
+
Result point: (89565891926547004231252920425935692360644145829622209833684329913297188986597, 12158399299693830322967808612713398636155367887041628176798871954788371653930)
|
|
82
|
+
✓ on curve
|
|
83
|
+
```
|
|
84
|
+
|
|
75
85
|
```bash
|
|
76
86
|
# Chinese Remainder Theorem
|
|
77
87
|
foxmath crt --r 2 3 2 --m 3 5 7
|
|
@@ -110,6 +110,29 @@ class TestNormalUsage(unittest.TestCase):
|
|
|
110
110
|
self.assertEqual(code, 1)
|
|
111
111
|
self.assertIn("point at infinity", err)
|
|
112
112
|
|
|
113
|
+
def test_ecadd_curve_secp256k1_defaults_to_doubling_generator(self):
|
|
114
|
+
code, out, err = run("ecadd", "--curve", "secp256k1")
|
|
115
|
+
self.assertEqual(code, 0)
|
|
116
|
+
self.assertIn("89565891926547004231252920425935692360644145829622209833684329913297188986597", out)
|
|
117
|
+
self.assertIn("on curve", out)
|
|
118
|
+
|
|
119
|
+
def test_ecadd_curve_manual_a_override(self):
|
|
120
|
+
# --a explicitly provided should override the curve preset's a.
|
|
121
|
+
code, out, err = run("ecadd", "--curve", "toy97", "--a", "2")
|
|
122
|
+
self.assertEqual(code, 0)
|
|
123
|
+
|
|
124
|
+
def test_ecadd_no_args_at_all_errors_clearly(self):
|
|
125
|
+
code, out, err = run("ecadd")
|
|
126
|
+
self.assertEqual(code, 1)
|
|
127
|
+
self.assertIn("Error", err)
|
|
128
|
+
|
|
129
|
+
def test_ecadd_backward_compatible_manual_call(self):
|
|
130
|
+
# Original documented usage: --a omitted, defaults to -3.
|
|
131
|
+
code, out, err = run("ecadd", "--x1", "1", "--y1", "2",
|
|
132
|
+
"--x2", "3", "--y2", "4", "--p", "17")
|
|
133
|
+
self.assertEqual(code, 0)
|
|
134
|
+
self.assertIn("Result point: (14, 2)", out)
|
|
135
|
+
|
|
113
136
|
def test_crt(self):
|
|
114
137
|
code, out, err = run("crt", "--r", "2", "3", "2", "--m", "3", "5", "7")
|
|
115
138
|
self.assertEqual(code, 0)
|
|
@@ -14,7 +14,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..",
|
|
|
14
14
|
|
|
15
15
|
from foxmath.foxmath import (
|
|
16
16
|
legendre_symbol, euler_hermann_pi_approx, ec_point_add, crt_solve,
|
|
17
|
-
continued_fraction, cf_convergents,
|
|
17
|
+
continued_fraction, cf_convergents, CURVES, is_on_curve,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
# Reference pi digits (mpmath, 250 dps of working precision), "3" + fractional digits.
|
|
@@ -152,5 +152,28 @@ class TestContinuedFractions(unittest.TestCase):
|
|
|
152
152
|
self.assertEqual(convs[-1], (expected.numerator, expected.denominator))
|
|
153
153
|
|
|
154
154
|
|
|
155
|
+
class TestNamedCurves(unittest.TestCase):
|
|
156
|
+
def test_secp256k1_generator_is_on_curve(self):
|
|
157
|
+
c = CURVES["secp256k1"]
|
|
158
|
+
self.assertTrue(is_on_curve(c["gx"], c["gy"], c["a"], c["b"], c["p"]))
|
|
159
|
+
|
|
160
|
+
def test_secp256k1_doubling_matches_known_value(self):
|
|
161
|
+
# Cross-checked independently against the `ecdsa` library's
|
|
162
|
+
# SECP256k1.generator * 2.
|
|
163
|
+
c = CURVES["secp256k1"]
|
|
164
|
+
x2, y2 = ec_point_add(c["gx"], c["gy"], c["gx"], c["gy"], c["a"], c["p"])
|
|
165
|
+
self.assertEqual(
|
|
166
|
+
x2, 89565891926547004231252920425935692360644145829622209833684329913297188986597
|
|
167
|
+
)
|
|
168
|
+
self.assertEqual(
|
|
169
|
+
y2, 12158399299693830322967808612713398636155367887041628176798871954788371653930
|
|
170
|
+
)
|
|
171
|
+
self.assertTrue(is_on_curve(x2, y2, c["a"], c["b"], c["p"]))
|
|
172
|
+
|
|
173
|
+
def test_toy97_generator_is_on_curve(self):
|
|
174
|
+
c = CURVES["toy97"]
|
|
175
|
+
self.assertTrue(is_on_curve(c["gx"], c["gy"], c["a"], c["b"], c["p"]))
|
|
176
|
+
|
|
177
|
+
|
|
155
178
|
if __name__ == "__main__":
|
|
156
179
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|