Add context tests and implement generator multiplication context

This commit introduces a new test file for context management, covering various scenarios for context creation, destruction, and capabilities. Additionally, it implements the generator multiplication context, enhancing the secp256k1 elliptic curve operations. The changes ensure comprehensive testing and improved functionality for context handling, contributing to the overall robustness of the implementation.
This commit is contained in:
2025-11-01 20:01:52 +00:00
parent 715bdff306
commit 5416381478
37 changed files with 2213 additions and 7833 deletions

View File

@@ -4,496 +4,138 @@ import (
"testing"
)
func TestGroupElementBasics(t *testing.T) {
func TestGroupElementAffine(t *testing.T) {
// Test infinity point
var inf GroupElementAffine
inf.setInfinity()
if !inf.isInfinity() {
t.Error("Infinity point should be infinity")
t.Error("setInfinity should create infinity point")
}
if !inf.isValid() {
t.Error("infinity point should be valid")
}
// Test generator point
gen := GeneratorAffine
if gen.isInfinity() {
t.Error("Generator should not be infinity")
if Generator.isInfinity() {
t.Error("generator should not be infinity")
}
if !Generator.isValid() {
t.Error("generator should be valid")
}
// Test validity
if !gen.isValid() {
t.Error("Generator should be valid")
// Test point negation
var neg GroupElementAffine
neg.negate(&Generator)
if neg.isInfinity() {
t.Error("negated generator should not be infinity")
}
if !neg.isValid() {
t.Error("negated generator should be valid")
}
// Test that G + (-G) = O (using Jacobian arithmetic)
var gJac, negJac, result GroupElementJacobian
gJac.setGE(&Generator)
negJac.setGE(&neg)
result.addVar(&gJac, &negJac)
if !result.isInfinity() {
t.Error("G + (-G) should equal infinity")
}
}
func TestGroupElementNegation(t *testing.T) {
// Test negation of generator
gen := GeneratorAffine
var negGen GroupElementAffine
negGen.negate(&gen)
func TestGroupElementJacobian(t *testing.T) {
// Test conversion between affine and Jacobian
var jac GroupElementJacobian
var aff GroupElementAffine
if negGen.isInfinity() {
t.Error("Negation of generator should not be infinity")
// Convert generator to Jacobian and back
jac.setGE(&Generator)
aff.setGEJ(&jac)
if !aff.equal(&Generator) {
t.Error("conversion G -> Jacobian -> affine should preserve point")
}
// 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)
doubled.double(&jac)
if doubled.isInfinity() {
t.Error("Doubled generator should not be infinity")
t.Error("2*G 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")
// Convert back to affine to validate
var doubledAff GroupElementAffine
doubledAff.setGEJ(&doubled)
if !doubledAff.isValid() {
t.Error("2*G should be valid point")
}
}
func TestGroupElementStorage(t *testing.T) {
// Test storage conversion
gen := GeneratorAffine
var storage GroupElementStorage
gen.toStorage(&storage)
var restored GroupElementAffine
// Store and restore generator
Generator.toStorage(&storage)
restored.fromStorage(&storage)
if !restored.equal(&gen) {
t.Error("Storage round-trip should preserve point")
if !restored.equal(&Generator) {
t.Error("storage conversion should preserve point")
}
// Test infinity storage
var inf GroupElementAffine
inf.setInfinity()
inf.toStorage(&storage)
restored.fromStorage(&storage)
if !restored.isInfinity() {
t.Error("infinity should be preserved in storage")
}
}
func TestGroupElementBytes(t *testing.T) {
// Test byte conversion
gen := GeneratorAffine
var bytes [64]byte
gen.toBytes(bytes[:])
var buf [64]byte
var restored GroupElementAffine
restored.fromBytes(bytes[:])
if !restored.equal(&gen) {
t.Error("Byte round-trip should preserve point")
}
}
// Test generator conversion
Generator.toBytes(buf[:])
restored.fromBytes(buf[:])
func TestGroupElementClear(t *testing.T) {
// Test clearing affine point
gen := GeneratorAffine
gen.clear()
if !gen.isInfinity() {
t.Error("Cleared affine point should be infinity")
if !restored.equal(&Generator) {
t.Error("byte conversion should preserve point")
}
// 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
// Test infinity conversion
var inf GroupElementAffine
inf.setInfinity()
inf.toBytes(buf[:])
restored.fromBytes(buf[:])
// 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")
if !restored.isInfinity() {
t.Error("infinity should be preserved in byte conversion")
}
}
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(&current)
powers[i].setGEJ(&current)
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)
func BenchmarkGroupDouble(b *testing.B) {
var jac GroupElementJacobian
jac.setGE(&Generator)
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.double(&genJ)
jac.double(&jac)
}
}
func BenchmarkGroupElementAddVar(b *testing.B) {
gen := GeneratorAffine
var genJ, doubled, result GroupElementJacobian
genJ.setGE(&gen)
doubled.double(&genJ)
func BenchmarkGroupAdd(b *testing.B) {
var jac1, jac2 GroupElementJacobian
jac1.setGE(&Generator)
jac2.setGE(&Generator)
jac2.double(&jac2) // Make it 2*G
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)
jac1.addVar(&jac1, &jac2)
}
}