aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClawd <ai@clawd.bot>2026-02-19 20:21:41 -0800
committerClawd <ai@clawd.bot>2026-02-19 20:21:41 -0800
commite0f87d3752edd792b7993d64622c216ebda225f4 (patch)
treed11888bb28e70f4abce7502dd307dba5d2a31631
parent90e12ea00741861bdf53ffb5826cb4a97ae0106a (diff)
Add field arithmetic (mod p operations)
-rw-r--r--field.go92
-rw-r--r--go.mod3
-rw-r--r--main.go33
3 files changed, 128 insertions, 0 deletions
diff --git a/field.go b/field.go
new file mode 100644
index 0000000..8b865ad
--- /dev/null
+++ b/field.go
@@ -0,0 +1,92 @@
1package main
2
3import (
4 "fmt"
5 "math/big"
6)
7
8// The prime for secp256k1: 2^256 - 2^32 - 977
9// All field arithmetic happens mod this number
10var P, _ = new(big.Int).SetString(
11 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
12 16,
13)
14
15// FieldElement represents a number in our finite field (mod P)
16type FieldElement struct {
17 value *big.Int
18}
19
20// NewFieldElement creates a field element from a big.Int
21// It automatically reduces mod P
22func NewFieldElement(v *big.Int) *FieldElement {
23 result := new(big.Int).Mod(v, P)
24 return &FieldElement{value: result}
25}
26
27// NewFieldElementFromInt64 is a convenience for small numbers
28func NewFieldElementFromInt64(v int64) *FieldElement {
29 return NewFieldElement(big.NewInt(v))
30}
31
32// Add returns (a + b) mod P
33func (a *FieldElement) Add(b *FieldElement) *FieldElement {
34 result := new(big.Int).Add(a.value, b.value)
35 return NewFieldElement(result)
36}
37
38// Sub returns (a - b) mod P
39func (a *FieldElement) Sub(b *FieldElement) *FieldElement {
40 result := new(big.Int).Sub(a.value, b.value)
41 return NewFieldElement(result)
42}
43
44// Mul returns (a * b) mod P
45func (a *FieldElement) Mul(b *FieldElement) *FieldElement {
46 result := new(big.Int).Mul(a.value, b.value)
47 return NewFieldElement(result)
48}
49
50// Div returns (a / b) mod P
51// Division in a field = multiply by the inverse
52func (a *FieldElement) Div(b *FieldElement) *FieldElement {
53 // a / b = a * b^(-1)
54 // b^(-1) mod P = b^(P-2) mod P (Fermat's little theorem)
55 inverse := b.Inverse()
56 return a.Mul(inverse)
57}
58
59// Inverse returns a^(-1) mod P using Fermat's little theorem
60// a^(-1) = a^(P-2) mod P
61func (a *FieldElement) Inverse() *FieldElement {
62 // P - 2
63 exp := new(big.Int).Sub(P, big.NewInt(2))
64 // a^(P-2) mod P
65 result := new(big.Int).Exp(a.value, exp, P)
66 return &FieldElement{value: result}
67}
68
69// Square returns a² mod P (convenience method)
70func (a *FieldElement) Square() *FieldElement {
71 return a.Mul(a)
72}
73
74// Equal checks if two field elements are the same
75func (a *FieldElement) Equal(b *FieldElement) bool {
76 return a.value.Cmp(b.value) == 0
77}
78
79// IsZero checks if the element is zero
80func (a *FieldElement) IsZero() bool {
81 return a.value.Sign() == 0
82}
83
84// String returns hex representation
85func (a *FieldElement) String() string {
86 return fmt.Sprintf("%064x", a.value)
87}
88
89// Clone returns a copy
90func (a *FieldElement) Clone() *FieldElement {
91 return &FieldElement{value: new(big.Int).Set(a.value)}
92}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..f8eed0f
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
1module secp256k1-learn
2
3go 1.23.5
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..9e19d35
--- /dev/null
+++ b/main.go
@@ -0,0 +1,33 @@
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("=== secp256k1 from scratch ===")
7 fmt.Println()
8
9 // Test field arithmetic with small numbers first
10 fmt.Println("Testing field arithmetic:")
11
12 a := NewFieldElementFromInt64(7)
13 b := NewFieldElementFromInt64(5)
14
15 fmt.Printf("a = %d\n", 7)
16 fmt.Printf("b = %d\n", 5)
17 fmt.Printf("a + b = %s (should end in ...c)\n", a.Add(b).String())
18 fmt.Printf("a - b = %s (should end in ...2)\n", a.Sub(b).String())
19 fmt.Printf("a * b = %s (should end in ...23, which is 35)\n", a.Mul(b).String())
20
21 // Test division: 10 / 5 = 2
22 ten := NewFieldElementFromInt64(10)
23 five := NewFieldElementFromInt64(5)
24 fmt.Printf("10 / 5 = %s (should end in ...2)\n", ten.Div(five).String())
25
26 // Test inverse: 5 * inverse(5) should = 1
27 inv := five.Inverse()
28 product := five.Mul(inv)
29 fmt.Printf("5 * inverse(5) = %s (should end in ...1)\n", product.String())
30
31 fmt.Println()
32 fmt.Println("Field arithmetic works!")
33}