Files
p256k1/field_test.go

340 lines
6.6 KiB
Go

package p256k1
import (
"crypto/rand"
"testing"
)
// Test field element creation and basic operations
func TestFieldElementBasics(t *testing.T) {
// Test zero element
var zero FieldElement
zero.setInt(0)
if !zero.isZero() {
t.Error("Zero element should be zero")
}
// Test one element
var one FieldElement
one.setInt(1)
if one.isZero() {
t.Error("One element should not be zero")
}
// Test normalization
one.normalize()
if !one.normalized {
t.Error("Element should be normalized after normalize()")
}
// Test equality
var one2 FieldElement
one2.setInt(1)
one2.normalize()
if !one.equal(&one2) {
t.Error("Two normalized ones should be equal")
}
}
func TestFieldElementSetB32(t *testing.T) {
// Test setting from 32-byte array
testCases := []struct {
name string
bytes [32]byte
}{
{
name: "zero",
bytes: [32]byte{},
},
{
name: "one",
bytes: [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
},
{
name: "max_value",
bytes: [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var fe FieldElement
fe.setB32(tc.bytes[:])
// Test round-trip
var result [32]byte
fe.normalize()
fe.getB32(result[:])
// For field modulus reduction, we need to check if the result is valid
if tc.name == "max_value" {
// This should be reduced modulo p
var expected FieldElement
expected.setInt(0) // p - 1 mod p = 0
expected.normalize()
if !fe.equal(&expected) {
t.Error("Field modulus should reduce to zero")
}
}
})
}
}
func TestFieldElementArithmetic(t *testing.T) {
// Test addition
var a, b, c FieldElement
a.setInt(5)
b.setInt(7)
c = a
c.add(&b)
c.normalize()
var expected FieldElement
expected.setInt(12)
expected.normalize()
if !c.equal(&expected) {
t.Error("5 + 7 should equal 12")
}
// Test negation
var neg FieldElement
neg.negate(&a, 1)
neg.normalize()
var sum FieldElement
sum = a
sum.add(&neg)
sum.normalize()
if !sum.isZero() {
t.Error("a + (-a) should equal zero")
}
}
func TestFieldElementMultiplication(t *testing.T) {
// Test multiplication by small integers
var a, result FieldElement
a.setInt(3)
result = a
result.mulInt(4)
result.normalize()
var expected FieldElement
expected.setInt(12)
expected.normalize()
if !result.equal(&expected) {
t.Error("3 * 4 should equal 12")
}
// Test multiplication by zero
result = a
result.mulInt(0)
result.normalize()
if !result.isZero() {
t.Error("a * 0 should equal zero")
}
}
func TestFieldElementNormalization(t *testing.T) {
var fe FieldElement
fe.setInt(42)
// Test weak normalization
fe.normalizeWeak()
if fe.magnitude != 1 {
t.Error("Weak normalization should set magnitude to 1")
}
// Test full normalization
fe.normalize()
if !fe.normalized {
t.Error("Full normalization should set normalized flag")
}
if fe.magnitude != 1 {
t.Error("Full normalization should set magnitude to 1")
}
}
func TestFieldElementOddness(t *testing.T) {
// Test even number
var even FieldElement
even.setInt(42)
even.normalize()
if even.isOdd() {
t.Error("42 should be even")
}
// Test odd number
var odd FieldElement
odd.setInt(43)
odd.normalize()
if !odd.isOdd() {
t.Error("43 should be odd")
}
}
func TestFieldElementConditionalMove(t *testing.T) {
var a, b, result FieldElement
a.setInt(10)
b.setInt(20)
result = a
// Test conditional move with flag = 0 (no move)
result.cmov(&b, 0)
result.normalize()
a.normalize()
if !result.equal(&a) {
t.Error("cmov with flag=0 should not change value")
}
// Test conditional move with flag = 1 (move)
result = a
result.cmov(&b, 1)
result.normalize()
b.normalize()
if !result.equal(&b) {
t.Error("cmov with flag=1 should change value")
}
}
func TestFieldElementStorage(t *testing.T) {
var fe FieldElement
fe.setInt(12345)
fe.normalize()
// Test conversion to storage format
var storage FieldElementStorage
fe.toStorage(&storage)
// Test conversion back from storage
var restored FieldElement
restored.fromStorage(&storage)
if !fe.equal(&restored) {
t.Error("Storage round-trip should preserve value")
}
}
func TestFieldElementRandomOperations(t *testing.T) {
// Test with random values
for i := 0; i < 100; i++ {
var bytes1, bytes2 [32]byte
rand.Read(bytes1[:])
rand.Read(bytes2[:])
var a, b, sum, diff FieldElement
a.setB32(bytes1[:])
b.setB32(bytes2[:])
// Test a + b - b = a
sum = a
sum.add(&b)
diff = sum
var negB FieldElement
negB.negate(&b, b.magnitude)
diff.add(&negB)
diff.normalize()
a.normalize()
if !diff.equal(&a) {
t.Errorf("Random test %d: (a + b) - b should equal a", i)
}
}
}
func TestFieldElementEdgeCases(t *testing.T) {
// Test field modulus boundary
// Set to p-1 (field modulus minus 1)
// p-1 = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2E
p_minus_1 := [32]byte{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2E,
}
var fe FieldElement
fe.setB32(p_minus_1[:])
fe.normalize()
// Add 1 should give 0
var one FieldElement
one.setInt(1)
fe.add(&one)
fe.normalize()
if !fe.isZero() {
t.Error("(p-1) + 1 should equal 0 in field arithmetic")
}
}
func TestFieldElementClear(t *testing.T) {
var fe FieldElement
fe.setInt(12345)
fe.clear()
// After clearing, should be zero and normalized
if !fe.isZero() {
t.Error("Cleared field element should be zero")
}
if !fe.normalized {
t.Error("Cleared field element should be normalized")
}
}
// Benchmark tests
func BenchmarkFieldElementSetB32(b *testing.B) {
var bytes [32]byte
rand.Read(bytes[:])
var fe FieldElement
b.ResetTimer()
for i := 0; i < b.N; i++ {
fe.setB32(bytes[:])
}
}
func BenchmarkFieldElementNormalize(b *testing.B) {
var fe FieldElement
fe.setInt(12345)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fe.normalize()
}
}
func BenchmarkFieldElementAdd(b *testing.B) {
var a, c FieldElement
a.setInt(12345)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.add(&a)
}
}
func BenchmarkFieldElementMulInt(b *testing.B) {
var fe FieldElement
fe.setInt(12345)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fe.mulInt(7)
}
}
func BenchmarkFieldElementNegate(b *testing.B) {
var a, result FieldElement
a.setInt(12345)
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.negate(&a, 1)
}
}