500 lines
11 KiB
Go
500 lines
11 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestGroupElementBasics(t *testing.T) {
|
|
// Test infinity point
|
|
var inf GroupElementAffine
|
|
inf.setInfinity()
|
|
if !inf.isInfinity() {
|
|
t.Error("Infinity point should be infinity")
|
|
}
|
|
|
|
// Test generator point
|
|
gen := GeneratorAffine
|
|
if gen.isInfinity() {
|
|
t.Error("Generator should not be infinity")
|
|
}
|
|
|
|
// Test validity
|
|
if !gen.isValid() {
|
|
t.Error("Generator should be valid")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementNegation(t *testing.T) {
|
|
// Test negation of generator
|
|
gen := GeneratorAffine
|
|
var negGen GroupElementAffine
|
|
negGen.negate(&gen)
|
|
|
|
if negGen.isInfinity() {
|
|
t.Error("Negation of generator should not be infinity")
|
|
}
|
|
|
|
// Test double negation
|
|
var doubleNeg GroupElementAffine
|
|
doubleNeg.negate(&negGen)
|
|
|
|
if !doubleNeg.equal(&gen) {
|
|
t.Error("Double negation should return original point")
|
|
}
|
|
|
|
// Test negation of infinity
|
|
var inf, negInf GroupElementAffine
|
|
inf.setInfinity()
|
|
negInf.negate(&inf)
|
|
|
|
if !negInf.isInfinity() {
|
|
t.Error("Negation of infinity should be infinity")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementSetXY(t *testing.T) {
|
|
// Test setting coordinates
|
|
var point GroupElementAffine
|
|
var x, y FieldElement
|
|
x.setInt(1)
|
|
y.setInt(1)
|
|
|
|
point.setXY(&x, &y)
|
|
|
|
if point.isInfinity() {
|
|
t.Error("Point with coordinates should not be infinity")
|
|
}
|
|
|
|
// Test that coordinates are preserved
|
|
if !point.x.equal(&x) {
|
|
t.Error("X coordinate should be preserved")
|
|
}
|
|
if !point.y.equal(&y) {
|
|
t.Error("Y coordinate should be preserved")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementSetXOVar(t *testing.T) {
|
|
// Test setting from X coordinate and oddness
|
|
var x FieldElement
|
|
x.setInt(1) // This may not be on the curve, but test the function
|
|
|
|
var point GroupElementAffine
|
|
// Try both odd and even Y
|
|
success := point.setXOVar(&x, false)
|
|
if success && point.isInfinity() {
|
|
t.Error("Successfully created point should not be infinity")
|
|
}
|
|
|
|
success = point.setXOVar(&x, true)
|
|
if success && point.isInfinity() {
|
|
t.Error("Successfully created point should not be infinity")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementEquality(t *testing.T) {
|
|
// Test equality with same point
|
|
gen := GeneratorAffine
|
|
var gen2 GroupElementAffine
|
|
gen2 = gen
|
|
|
|
if !gen.equal(&gen2) {
|
|
t.Error("Same points should be equal")
|
|
}
|
|
|
|
// Test inequality with different points
|
|
var negGen GroupElementAffine
|
|
negGen.negate(&gen)
|
|
|
|
if gen.equal(&negGen) {
|
|
t.Error("Generator and its negation should not be equal")
|
|
}
|
|
|
|
// Test equality of infinity points
|
|
var inf1, inf2 GroupElementAffine
|
|
inf1.setInfinity()
|
|
inf2.setInfinity()
|
|
|
|
if !inf1.equal(&inf2) {
|
|
t.Error("Two infinity points should be equal")
|
|
}
|
|
|
|
// Test inequality between infinity and non-infinity
|
|
if gen.equal(&inf1) {
|
|
t.Error("Generator and infinity should not be equal")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementJacobianBasics(t *testing.T) {
|
|
// Test infinity
|
|
var inf GroupElementJacobian
|
|
inf.setInfinity()
|
|
if !inf.isInfinity() {
|
|
t.Error("Jacobian infinity should be infinity")
|
|
}
|
|
|
|
// Test conversion from affine
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
if genJ.isInfinity() {
|
|
t.Error("Jacobian generator should not be infinity")
|
|
}
|
|
|
|
// Test conversion back to affine
|
|
var genBack GroupElementAffine
|
|
genBack.setGEJ(&genJ)
|
|
|
|
if !genBack.equal(&gen) {
|
|
t.Error("Round-trip conversion should preserve point")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementJacobianDoubling(t *testing.T) {
|
|
// Test point doubling
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var doubled GroupElementJacobian
|
|
doubled.double(&genJ)
|
|
|
|
if doubled.isInfinity() {
|
|
t.Error("Doubled generator should not be infinity")
|
|
}
|
|
|
|
// Test doubling infinity
|
|
var inf, doubledInf GroupElementJacobian
|
|
inf.setInfinity()
|
|
doubledInf.double(&inf)
|
|
|
|
if !doubledInf.isInfinity() {
|
|
t.Error("Doubled infinity should be infinity")
|
|
}
|
|
|
|
// Test that 2*P != P (for non-zero points)
|
|
var doubledAffine GroupElementAffine
|
|
doubledAffine.setGEJ(&doubled)
|
|
|
|
if doubledAffine.equal(&gen) {
|
|
t.Error("2*G should not equal G")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementJacobianAddition(t *testing.T) {
|
|
// Test P + O = P (where O is infinity)
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var inf GroupElementJacobian
|
|
inf.setInfinity()
|
|
|
|
var result GroupElementJacobian
|
|
result.addVar(&genJ, &inf)
|
|
|
|
var resultAffine GroupElementAffine
|
|
resultAffine.setGEJ(&result)
|
|
|
|
if !resultAffine.equal(&gen) {
|
|
t.Error("P + O should equal P")
|
|
}
|
|
|
|
// Test O + P = P
|
|
result.addVar(&inf, &genJ)
|
|
resultAffine.setGEJ(&result)
|
|
|
|
if !resultAffine.equal(&gen) {
|
|
t.Error("O + P should equal P")
|
|
}
|
|
|
|
// Test P + (-P) = O
|
|
var negGen GroupElementAffine
|
|
negGen.negate(&gen)
|
|
var negGenJ GroupElementJacobian
|
|
negGenJ.setGE(&negGen)
|
|
|
|
result.addVar(&genJ, &negGenJ)
|
|
|
|
if !result.isInfinity() {
|
|
t.Error("P + (-P) should equal infinity")
|
|
}
|
|
|
|
// Test P + P = 2P (should equal doubling)
|
|
var sum, doubled GroupElementJacobian
|
|
sum.addVar(&genJ, &genJ)
|
|
doubled.double(&genJ)
|
|
|
|
var sumAffine, doubledAffine GroupElementAffine
|
|
sumAffine.setGEJ(&sum)
|
|
doubledAffine.setGEJ(&doubled)
|
|
|
|
if !sumAffine.equal(&doubledAffine) {
|
|
t.Error("P + P should equal 2*P")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementAddGE(t *testing.T) {
|
|
// Test mixed addition (Jacobian + Affine)
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var negGen GroupElementAffine
|
|
negGen.negate(&gen)
|
|
|
|
var result GroupElementJacobian
|
|
result.addGE(&genJ, &negGen)
|
|
|
|
if !result.isInfinity() {
|
|
t.Error("P + (-P) should equal infinity in mixed addition")
|
|
}
|
|
|
|
// Test adding infinity
|
|
var inf GroupElementAffine
|
|
inf.setInfinity()
|
|
|
|
result.addGE(&genJ, &inf)
|
|
var resultAffine GroupElementAffine
|
|
resultAffine.setGEJ(&result)
|
|
|
|
if !resultAffine.equal(&gen) {
|
|
t.Error("P + O should equal P in mixed addition")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementNegationJacobian(t *testing.T) {
|
|
// Test Jacobian negation
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var negGenJ GroupElementJacobian
|
|
negGenJ.negate(&genJ)
|
|
|
|
if negGenJ.isInfinity() {
|
|
t.Error("Negated Jacobian point should not be infinity")
|
|
}
|
|
|
|
// Convert back to affine and compare
|
|
var negGenAffine, expectedNegAffine GroupElementAffine
|
|
negGenAffine.setGEJ(&negGenJ)
|
|
expectedNegAffine.negate(&gen)
|
|
|
|
if !negGenAffine.equal(&expectedNegAffine) {
|
|
t.Error("Jacobian negation should match affine negation")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementStorage(t *testing.T) {
|
|
// Test storage conversion
|
|
gen := GeneratorAffine
|
|
var storage GroupElementStorage
|
|
gen.toStorage(&storage)
|
|
|
|
var restored GroupElementAffine
|
|
restored.fromStorage(&storage)
|
|
|
|
if !restored.equal(&gen) {
|
|
t.Error("Storage round-trip should preserve point")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementBytes(t *testing.T) {
|
|
// Test byte conversion
|
|
gen := GeneratorAffine
|
|
var bytes [64]byte
|
|
gen.toBytes(bytes[:])
|
|
|
|
var restored GroupElementAffine
|
|
restored.fromBytes(bytes[:])
|
|
|
|
if !restored.equal(&gen) {
|
|
t.Error("Byte round-trip should preserve point")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementClear(t *testing.T) {
|
|
// Test clearing affine point
|
|
gen := GeneratorAffine
|
|
gen.clear()
|
|
|
|
if !gen.isInfinity() {
|
|
t.Error("Cleared affine point should be infinity")
|
|
}
|
|
|
|
// Test clearing Jacobian point
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&GeneratorAffine)
|
|
genJ.clear()
|
|
|
|
if !genJ.isInfinity() {
|
|
t.Error("Cleared Jacobian point should be infinity")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementRandomOperations(t *testing.T) {
|
|
// Test with random scalar multiplications (simplified)
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
// Test associativity: (P + P) + P = P + (P + P)
|
|
var p_plus_p, left, right GroupElementJacobian
|
|
p_plus_p.addVar(&genJ, &genJ)
|
|
left.addVar(&p_plus_p, &genJ)
|
|
right.addVar(&genJ, &p_plus_p)
|
|
|
|
var leftAffine, rightAffine GroupElementAffine
|
|
leftAffine.setGEJ(&left)
|
|
rightAffine.setGEJ(&right)
|
|
|
|
if !leftAffine.equal(&rightAffine) {
|
|
t.Error("Addition should be associative")
|
|
}
|
|
|
|
// Test commutativity: P + Q = Q + P
|
|
var doubled GroupElementJacobian
|
|
doubled.double(&genJ)
|
|
|
|
var sum1, sum2 GroupElementJacobian
|
|
sum1.addVar(&genJ, &doubled)
|
|
sum2.addVar(&doubled, &genJ)
|
|
|
|
var sum1Affine, sum2Affine GroupElementAffine
|
|
sum1Affine.setGEJ(&sum1)
|
|
sum2Affine.setGEJ(&sum2)
|
|
|
|
if !sum1Affine.equal(&sum2Affine) {
|
|
t.Error("Addition should be commutative")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementEdgeCases(t *testing.T) {
|
|
// Test operations with infinity
|
|
var inf GroupElementAffine
|
|
inf.setInfinity()
|
|
|
|
// Test negation of infinity
|
|
var negInf GroupElementAffine
|
|
negInf.negate(&inf)
|
|
if !negInf.isInfinity() {
|
|
t.Error("Negation of infinity should be infinity")
|
|
}
|
|
|
|
// Test setting infinity to coordinates (should remain infinity)
|
|
var x, y FieldElement
|
|
x.setInt(0)
|
|
y.setInt(0)
|
|
inf.setXY(&x, &y)
|
|
if inf.isInfinity() {
|
|
t.Error("Setting coordinates should make point non-infinity")
|
|
}
|
|
|
|
// Reset to infinity for next test
|
|
inf.setInfinity()
|
|
|
|
// Test conversion of infinity to Jacobian
|
|
var infJ GroupElementJacobian
|
|
infJ.setGE(&inf)
|
|
if !infJ.isInfinity() {
|
|
t.Error("Jacobian conversion of infinity should be infinity")
|
|
}
|
|
|
|
// Test conversion back
|
|
var infBack GroupElementAffine
|
|
infBack.setGEJ(&infJ)
|
|
if !infBack.isInfinity() {
|
|
t.Error("Affine conversion of Jacobian infinity should be infinity")
|
|
}
|
|
}
|
|
|
|
func TestGroupElementMultipleDoubling(t *testing.T) {
|
|
// Test multiple doublings: 2^n * G
|
|
gen := GeneratorAffine
|
|
var current GroupElementJacobian
|
|
current.setGE(&gen)
|
|
|
|
var powers [8]GroupElementAffine
|
|
powers[0] = gen
|
|
|
|
// Compute 2^i * G for i = 1..7
|
|
for i := 1; i < 8; i++ {
|
|
current.double(¤t)
|
|
powers[i].setGEJ(¤t)
|
|
|
|
if powers[i].isInfinity() {
|
|
t.Errorf("2^%d * G should not be infinity", i)
|
|
}
|
|
|
|
// Check that each power is different from previous ones
|
|
for j := 0; j < i; j++ {
|
|
if powers[i].equal(&powers[j]) {
|
|
t.Errorf("2^%d * G should not equal 2^%d * G", i, j)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkGroupElementDouble(b *testing.B) {
|
|
gen := GeneratorAffine
|
|
var genJ, result GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result.double(&genJ)
|
|
}
|
|
}
|
|
|
|
func BenchmarkGroupElementAddVar(b *testing.B) {
|
|
gen := GeneratorAffine
|
|
var genJ, doubled, result GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
doubled.double(&genJ)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result.addVar(&genJ, &doubled)
|
|
}
|
|
}
|
|
|
|
func BenchmarkGroupElementAddGE(b *testing.B) {
|
|
gen := GeneratorAffine
|
|
var genJ, result GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var negGen GroupElementAffine
|
|
negGen.negate(&gen)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result.addGE(&genJ, &negGen)
|
|
}
|
|
}
|
|
|
|
func BenchmarkGroupElementSetGEJ(b *testing.B) {
|
|
gen := GeneratorAffine
|
|
var genJ GroupElementJacobian
|
|
genJ.setGE(&gen)
|
|
|
|
var result GroupElementAffine
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result.setGEJ(&genJ)
|
|
}
|
|
}
|
|
|
|
func BenchmarkGroupElementNegate(b *testing.B) {
|
|
gen := GeneratorAffine
|
|
var result GroupElementAffine
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result.negate(&gen)
|
|
}
|
|
}
|