Files
p256k1/ecmult_comprehensive_test.go

484 lines
11 KiB
Go

package p256k1
import (
"crypto/rand"
"testing"
)
func TestEcmultGen(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Test multiplication by zero
var zero Scalar
zero.setInt(0)
var result GroupElementJacobian
ecmultGen(&ctx.ecmultGenCtx, &result, &zero)
if !result.isInfinity() {
t.Error("0 * G should be infinity")
}
// Test multiplication by one
var one Scalar
one.setInt(1)
ecmultGen(&ctx.ecmultGenCtx, &result, &one)
if result.isInfinity() {
t.Error("1 * G should not be infinity")
}
// Convert to affine and compare with generator
var resultAffine GroupElementAffine
resultAffine.setGEJ(&result)
if !resultAffine.equal(&GeneratorAffine) {
t.Error("1 * G should equal the generator point")
}
// Test multiplication by two
var two Scalar
two.setInt(2)
ecmultGen(&ctx.ecmultGenCtx, &result, &two)
// Should equal G + G
var doubled GroupElementJacobian
var genJ GroupElementJacobian
genJ.setGE(&GeneratorAffine)
doubled.double(&genJ)
var resultAffine2, doubledAffine GroupElementAffine
resultAffine2.setGEJ(&result)
doubledAffine.setGEJ(&doubled)
if !resultAffine2.equal(&doubledAffine) {
t.Error("2 * G should equal G + G")
}
}
func TestEcmultGenRandomScalars(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Test with random scalars
for i := 0; i < 20; i++ {
var bytes [32]byte
rand.Read(bytes[:])
bytes[0] &= 0x7F // Ensure no overflow
var scalar Scalar
scalar.setB32(bytes[:])
if scalar.isZero() {
continue // Skip zero
}
var result GroupElementJacobian
ecmultGen(&ctx.ecmultGenCtx, &result, &scalar)
if result.isInfinity() {
t.Errorf("Random scalar %d should not produce infinity", i)
}
// Test that different scalars produce different results
var scalar2 Scalar
scalar2.setInt(1)
scalar2.add(&scalar, &scalar2) // scalar + 1
var result2 GroupElementJacobian
ecmultGen(&ctx.ecmultGenCtx, &result2, &scalar2)
var resultAffine, result2Affine GroupElementAffine
resultAffine.setGEJ(&result)
result2Affine.setGEJ(&result2)
if resultAffine.equal(&result2Affine) {
t.Errorf("Different scalars should produce different points (test %d)", i)
}
}
}
func TestEcmultConst(t *testing.T) {
// Test constant-time scalar multiplication
var point GroupElementAffine
point = GeneratorAffine
// Test multiplication by zero
var zero Scalar
zero.setInt(0)
var result GroupElementJacobian
EcmultConst(&result, &zero, &point)
if !result.isInfinity() {
t.Error("0 * P should be infinity")
}
// Test multiplication by one
var one Scalar
one.setInt(1)
EcmultConst(&result, &one, &point)
var resultAffine GroupElementAffine
resultAffine.setGEJ(&result)
if !resultAffine.equal(&point) {
t.Error("1 * P should equal P")
}
// Test multiplication by two
var two Scalar
two.setInt(2)
EcmultConst(&result, &two, &point)
// Should equal P + P
var pointJ GroupElementJacobian
pointJ.setGE(&point)
var doubled GroupElementJacobian
doubled.double(&pointJ)
var doubledAffine GroupElementAffine
resultAffine.setGEJ(&result)
doubledAffine.setGEJ(&doubled)
if !resultAffine.equal(&doubledAffine) {
t.Error("2 * P should equal P + P")
}
}
func TestEcmultConstVsGen(t *testing.T) {
// Test that EcmultConst with generator gives same result as EcmultGen
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
for i := 1; i <= 10; i++ {
var scalar Scalar
scalar.setInt(uint(i))
// Use EcmultGen
var resultGen GroupElementJacobian
ecmultGen(&ctx.ecmultGenCtx, &resultGen, &scalar)
// Use EcmultConst with generator
var resultConst GroupElementJacobian
EcmultConst(&resultConst, &scalar, &GeneratorAffine)
// Convert to affine for comparison
var genAffine, constAffine GroupElementAffine
genAffine.setGEJ(&resultGen)
constAffine.setGEJ(&resultConst)
if !genAffine.equal(&constAffine) {
t.Errorf("EcmultGen and EcmultConst should give same result for scalar %d", i)
}
}
}
func TestEcmultMulti(t *testing.T) {
// Test multi-scalar multiplication
var points [3]*GroupElementAffine
var scalars [3]*Scalar
// Initialize test data
for i := 0; i < 3; i++ {
points[i] = &GroupElementAffine{}
*points[i] = GeneratorAffine
scalars[i] = &Scalar{}
scalars[i].setInt(uint(i + 1))
}
var result GroupElementJacobian
EcmultMulti(&result, scalars[:], points[:])
if result.isInfinity() {
t.Error("Multi-scalar multiplication should not result in infinity for non-zero inputs")
}
// Verify result equals sum of individual multiplications
var expected GroupElementJacobian
expected.setInfinity()
for i := 0; i < 3; i++ {
var individual GroupElementJacobian
EcmultConst(&individual, scalars[i], points[i])
expected.addVar(&expected, &individual)
}
var resultAffine, expectedAffine GroupElementAffine
resultAffine.setGEJ(&result)
expectedAffine.setGEJ(&expected)
if !resultAffine.equal(&expectedAffine) {
t.Error("Multi-scalar multiplication should equal sum of individual multiplications")
}
}
func TestEcmultMultiEdgeCases(t *testing.T) {
// Test with empty arrays
var result GroupElementJacobian
EcmultMulti(&result, nil, nil)
if !result.isInfinity() {
t.Error("Multi-scalar multiplication with empty arrays should be infinity")
}
// Test with single element
var points [1]*GroupElementAffine
var scalars [1]*Scalar
points[0] = &GeneratorAffine
scalars[0] = &Scalar{}
scalars[0].setInt(5)
EcmultMulti(&result, scalars[:], points[:])
// Should equal 5 * G
var expected GroupElementJacobian
EcmultConst(&expected, scalars[0], points[0])
var resultAffine, expectedAffine GroupElementAffine
resultAffine.setGEJ(&result)
expectedAffine.setGEJ(&expected)
if !resultAffine.equal(&expectedAffine) {
t.Error("Single-element multi-scalar multiplication should equal individual multiplication")
}
}
func TestEcmultMultiWithZeros(t *testing.T) {
// Test multi-scalar multiplication with some zero scalars
var points [3]*GroupElementAffine
var scalars [3]*Scalar
for i := 0; i < 3; i++ {
points[i] = &GroupElementAffine{}
*points[i] = GeneratorAffine
scalars[i] = &Scalar{}
if i == 1 {
scalars[i].setInt(0) // Middle scalar is zero
} else {
scalars[i].setInt(uint(i + 1))
}
}
var result GroupElementJacobian
EcmultMulti(&result, scalars[:], points[:])
// Should equal 1*G + 0*G + 3*G = 1*G + 3*G = 4*G
var expected GroupElementJacobian
var four Scalar
four.setInt(4)
EcmultConst(&expected, &four, &GeneratorAffine)
var resultAffine, expectedAffine GroupElementAffine
resultAffine.setGEJ(&result)
expectedAffine.setGEJ(&expected)
if !resultAffine.equal(&expectedAffine) {
t.Error("Multi-scalar multiplication with zeros should skip zero terms")
}
}
func TestEcmultProperties(t *testing.T) {
// Test linearity: k1*P + k2*P = (k1 + k2)*P
var k1, k2, sum Scalar
k1.setInt(7)
k2.setInt(11)
sum.add(&k1, &k2)
var result1, result2, resultSum GroupElementJacobian
EcmultConst(&result1, &k1, &GeneratorAffine)
EcmultConst(&result2, &k2, &GeneratorAffine)
EcmultConst(&resultSum, &sum, &GeneratorAffine)
// result1 + result2 should equal resultSum
var combined GroupElementJacobian
combined.addVar(&result1, &result2)
var combinedAffine, sumAffine GroupElementAffine
combinedAffine.setGEJ(&combined)
sumAffine.setGEJ(&resultSum)
if !combinedAffine.equal(&sumAffine) {
t.Error("Linearity property should hold: k1*P + k2*P = (k1 + k2)*P")
}
}
func TestEcmultDistributivity(t *testing.T) {
// Test distributivity: k*(P + Q) = k*P + k*Q
var k Scalar
k.setInt(5)
// Create two different points
var p, q GroupElementAffine
p = GeneratorAffine
var two Scalar
two.setInt(2)
var qJ GroupElementJacobian
EcmultConst(&qJ, &two, &p) // Q = 2*P
q.setGEJ(&qJ)
// Compute P + Q
var pJ GroupElementJacobian
pJ.setGE(&p)
var pPlusQJ GroupElementJacobian
pPlusQJ.addGE(&pJ, &q)
var pPlusQ GroupElementAffine
pPlusQ.setGEJ(&pPlusQJ)
// Compute k*(P + Q)
var leftSide GroupElementJacobian
EcmultConst(&leftSide, &k, &pPlusQ)
// Compute k*P + k*Q
var kP, kQ GroupElementJacobian
EcmultConst(&kP, &k, &p)
EcmultConst(&kQ, &k, &q)
var rightSide GroupElementJacobian
rightSide.addVar(&kP, &kQ)
var leftAffine, rightAffine GroupElementAffine
leftAffine.setGEJ(&leftSide)
rightAffine.setGEJ(&rightSide)
if !leftAffine.equal(&rightAffine) {
t.Error("Distributivity should hold: k*(P + Q) = k*P + k*Q")
}
}
func TestEcmultLargeScalars(t *testing.T) {
// Test with large scalars (close to group order)
var largeScalar Scalar
largeBytes := [32]byte{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40,
} // n - 1
largeScalar.setB32(largeBytes[:])
var result GroupElementJacobian
EcmultConst(&result, &largeScalar, &GeneratorAffine)
if result.isInfinity() {
t.Error("(n-1) * G should not be infinity")
}
// (n-1) * G + G should equal infinity (since n * G = infinity)
var genJ GroupElementJacobian
genJ.setGE(&GeneratorAffine)
result.addVar(&result, &genJ)
if !result.isInfinity() {
t.Error("(n-1) * G + G should equal infinity")
}
}
func TestEcmultNegativeScalars(t *testing.T) {
// Test with negative scalars (using negation)
var k Scalar
k.setInt(7)
var negK Scalar
negK.negate(&k)
var result, negResult GroupElementJacobian
EcmultConst(&result, &k, &GeneratorAffine)
EcmultConst(&negResult, &negK, &GeneratorAffine)
// negResult should be the negation of result
var negResultNegated GroupElementJacobian
negResultNegated.negate(&negResult)
var resultAffine, negatedAffine GroupElementAffine
resultAffine.setGEJ(&result)
negatedAffine.setGEJ(&negResultNegated)
if !resultAffine.equal(&negatedAffine) {
t.Error("(-k) * P should equal -(k * P)")
}
}
// Benchmark tests
func BenchmarkEcmultGen(b *testing.B) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
b.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
var scalar Scalar
scalar.setInt(12345)
var result GroupElementJacobian
b.ResetTimer()
for i := 0; i < b.N; i++ {
ecmultGen(&ctx.ecmultGenCtx, &result, &scalar)
}
}
func BenchmarkEcmultConst(b *testing.B) {
var point GroupElementAffine
point = GeneratorAffine
var scalar Scalar
scalar.setInt(12345)
var result GroupElementJacobian
b.ResetTimer()
for i := 0; i < b.N; i++ {
EcmultConst(&result, &scalar, &point)
}
}
func BenchmarkEcmultMulti3Points(b *testing.B) {
var points [3]*GroupElementAffine
var scalars [3]*Scalar
for i := 0; i < 3; i++ {
points[i] = &GroupElementAffine{}
*points[i] = GeneratorAffine
scalars[i] = &Scalar{}
scalars[i].setInt(uint(i + 1000))
}
var result GroupElementJacobian
b.ResetTimer()
for i := 0; i < b.N; i++ {
EcmultMulti(&result, scalars[:], points[:])
}
}
func BenchmarkEcmultMulti10Points(b *testing.B) {
var points [10]*GroupElementAffine
var scalars [10]*Scalar
for i := 0; i < 10; i++ {
points[i] = &GroupElementAffine{}
*points[i] = GeneratorAffine
scalars[i] = &Scalar{}
scalars[i].setInt(uint(i + 1000))
}
var result GroupElementJacobian
b.ResetTimer()
for i := 0; i < b.N; i++ {
EcmultMulti(&result, scalars[:], points[:])
}
}