aboutsummaryrefslogtreecommitdiffstats
path: root/point_test.go
blob: ba129774f0e40a116b19abf3fc6e2ef076239a5c (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package main

import (
	"math/big"
	"testing"
)

func TestGeneratorIsOnCurve(t *testing.T) {
	if !G.IsOnCurve() {
		t.Error("generator point G should be on the curve")
	}
}

func TestInfinityIsOnCurve(t *testing.T) {
	inf := Infinity()
	if !inf.IsOnCurve() {
		t.Error("point at infinity should be considered on curve")
	}
}

func TestPointNotOnCurve(t *testing.T) {
	// (1, 1) is not on y² = x³ + 7
	// y² = 1, x³ + 7 = 8, so 1 ≠ 8
	x := NewFieldElementFromInt64(1)
	y := NewFieldElementFromInt64(1)
	_, err := NewPoint(x, y)
	if err == nil {
		t.Error("(1, 1) should not be on the curve")
	}
}

func TestAddInfinity(t *testing.T) {
	inf := Infinity()

	// G + infinity = G
	result := G.Add(inf)
	if !result.Equal(G) {
		t.Error("G + infinity should equal G")
	}

	// infinity + G = G
	result = inf.Add(G)
	if !result.Equal(G) {
		t.Error("infinity + G should equal G")
	}

	// infinity + infinity = infinity
	result = inf.Add(inf)
	if !result.IsInfinity() {
		t.Error("infinity + infinity should be infinity")
	}
}

func TestAddInverseGivesInfinity(t *testing.T) {
	// G + (-G) = infinity
	negG := G.Negate()
	result := G.Add(negG)
	if !result.IsInfinity() {
		t.Error("G + (-G) should be infinity")
	}
}

func TestDoubleGenerator(t *testing.T) {
	// 2G should be on the curve
	twoG := G.Double()
	if !twoG.IsOnCurve() {
		t.Error("2G should be on the curve")
	}

	// 2G should not be infinity
	if twoG.IsInfinity() {
		t.Error("2G should not be infinity")
	}

	// 2G should not equal G
	if twoG.Equal(G) {
		t.Error("2G should not equal G")
	}
}

func TestAddEqualsDouble(t *testing.T) {
	// G + G should equal G.Double()
	sum := G.Add(G)
	doubled := G.Double()
	if !sum.Equal(doubled) {
		t.Error("G + G should equal 2G")
	}
}

func TestScalarMulByOne(t *testing.T) {
	// 1 * G = G
	one := big.NewInt(1)
	result := G.ScalarMul(one)
	if !result.Equal(G) {
		t.Error("1 * G should equal G")
	}
}

func TestScalarMulByTwo(t *testing.T) {
	// 2 * G = G + G
	two := big.NewInt(2)
	result := G.ScalarMul(two)
	expected := G.Double()
	if !result.Equal(expected) {
		t.Error("2 * G should equal G.Double()")
	}
}

func TestScalarMulByThree(t *testing.T) {
	// 3 * G = G + G + G
	three := big.NewInt(3)
	result := G.ScalarMul(three)
	expected := G.Double().Add(G)
	if !result.Equal(expected) {
		t.Error("3 * G should equal 2G + G")
	}

	// Result should be on curve
	if !result.IsOnCurve() {
		t.Error("3G should be on the curve")
	}
}

func TestScalarMulByN(t *testing.T) {
	// N * G = infinity (curve order)
	result := G.ScalarMul(N)
	if !result.IsInfinity() {
		t.Error("N * G should be infinity (curve order)")
	}
}

func TestScalarMulAssociative(t *testing.T) {
	// (a * b) * G = a * (b * G)
	a := big.NewInt(7)
	b := big.NewInt(11)
	ab := new(big.Int).Mul(a, b) // 77

	left := G.ScalarMul(ab)
	right := G.ScalarMul(b).ScalarMul(a)

	if !left.Equal(right) {
		t.Error("scalar multiplication should be associative")
	}
}

func TestNegateOnCurve(t *testing.T) {
	negG := G.Negate()
	if !negG.IsOnCurve() {
		t.Error("-G should be on the curve")
	}
}

func TestDoubleNegateEqualsOriginal(t *testing.T) {
	// -(-G) = G
	result := G.Negate().Negate()
	if !result.Equal(G) {
		t.Error("-(-G) should equal G")
	}
}

func TestPointEquality(t *testing.T) {
	// Same point should be equal
	if !G.Equal(G) {
		t.Error("G should equal itself")
	}

	// Different points should not be equal
	twoG := G.Double()
	if G.Equal(twoG) {
		t.Error("G should not equal 2G")
	}

	// Infinity equals infinity
	inf1 := Infinity()
	inf2 := Infinity()
	if !inf1.Equal(inf2) {
		t.Error("infinity should equal infinity")
	}
}

// Known test vector from Bitcoin
func TestKnownVector2G(t *testing.T) {
	// 2G has known coordinates (verified against bitcoin wiki)
	expectedX, _ := new(big.Int).SetString("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5", 16)
	expectedY, _ := new(big.Int).SetString("1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A", 16)

	twoG := G.Double()

	if twoG.x.value.Cmp(expectedX) != 0 {
		t.Errorf("2G.x = %s, want %x", twoG.x.String(), expectedX)
	}
	if twoG.y.value.Cmp(expectedY) != 0 {
		t.Errorf("2G.y = %s, want %x", twoG.y.String(), expectedY)
	}
}