aboutsummaryrefslogtreecommitdiffstats
path: root/field.go
blob: 8b865ad7d2fa2f77ae49a13827a38be740f3cf45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main

import (
	"fmt"
	"math/big"
)

// The prime for secp256k1: 2^256 - 2^32 - 977
// All field arithmetic happens mod this number
var P, _ = new(big.Int).SetString(
	"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
	16,
)

// FieldElement represents a number in our finite field (mod P)
type FieldElement struct {
	value *big.Int
}

// NewFieldElement creates a field element from a big.Int
// It automatically reduces mod P
func NewFieldElement(v *big.Int) *FieldElement {
	result := new(big.Int).Mod(v, P)
	return &FieldElement{value: result}
}

// NewFieldElementFromInt64 is a convenience for small numbers
func NewFieldElementFromInt64(v int64) *FieldElement {
	return NewFieldElement(big.NewInt(v))
}

// Add returns (a + b) mod P
func (a *FieldElement) Add(b *FieldElement) *FieldElement {
	result := new(big.Int).Add(a.value, b.value)
	return NewFieldElement(result)
}

// Sub returns (a - b) mod P
func (a *FieldElement) Sub(b *FieldElement) *FieldElement {
	result := new(big.Int).Sub(a.value, b.value)
	return NewFieldElement(result)
}

// Mul returns (a * b) mod P
func (a *FieldElement) Mul(b *FieldElement) *FieldElement {
	result := new(big.Int).Mul(a.value, b.value)
	return NewFieldElement(result)
}

// Div returns (a / b) mod P
// Division in a field = multiply by the inverse
func (a *FieldElement) Div(b *FieldElement) *FieldElement {
	// a / b = a * b^(-1)
	// b^(-1) mod P = b^(P-2) mod P  (Fermat's little theorem)
	inverse := b.Inverse()
	return a.Mul(inverse)
}

// Inverse returns a^(-1) mod P using Fermat's little theorem
// a^(-1) = a^(P-2) mod P
func (a *FieldElement) Inverse() *FieldElement {
	// P - 2
	exp := new(big.Int).Sub(P, big.NewInt(2))
	// a^(P-2) mod P
	result := new(big.Int).Exp(a.value, exp, P)
	return &FieldElement{value: result}
}

// Square returns a² mod P (convenience method)
func (a *FieldElement) Square() *FieldElement {
	return a.Mul(a)
}

// Equal checks if two field elements are the same
func (a *FieldElement) Equal(b *FieldElement) bool {
	return a.value.Cmp(b.value) == 0
}

// IsZero checks if the element is zero
func (a *FieldElement) IsZero() bool {
	return a.value.Sign() == 0
}

// String returns hex representation
func (a *FieldElement) String() string {
	return fmt.Sprintf("%064x", a.value)
}

// Clone returns a copy
func (a *FieldElement) Clone() *FieldElement {
	return &FieldElement{value: new(big.Int).Set(a.value)}
}