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.
300 lines
6.2 KiB
Go
300 lines
6.2 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"testing"
|
|
)
|
|
|
|
func TestScalarBasics(t *testing.T) {
|
|
// Test zero scalar
|
|
var zero Scalar
|
|
if !zero.isZero() {
|
|
t.Error("Zero scalar should be zero")
|
|
}
|
|
|
|
// Test one scalar
|
|
var one Scalar
|
|
one.setInt(1)
|
|
if !one.isOne() {
|
|
t.Error("One scalar should be one")
|
|
}
|
|
|
|
// Test equality
|
|
var one2 Scalar
|
|
one2.setInt(1)
|
|
if !one.equal(&one2) {
|
|
t.Error("Two ones should be equal")
|
|
}
|
|
}
|
|
|
|
func TestScalarSetB32(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: "group_order_minus_one",
|
|
bytes: [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},
|
|
},
|
|
{
|
|
name: "group_order",
|
|
bytes: [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, 0x41},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var s Scalar
|
|
overflow := s.setB32(tc.bytes[:])
|
|
|
|
// Test round-trip
|
|
var result [32]byte
|
|
s.getB32(result[:])
|
|
|
|
// For group order, should reduce to zero
|
|
if tc.name == "group_order" {
|
|
if !s.isZero() {
|
|
t.Error("Group order should reduce to zero")
|
|
}
|
|
if !overflow {
|
|
t.Error("Group order should cause overflow")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestScalarSetB32Seckey(t *testing.T) {
|
|
// Test valid secret key
|
|
validKey := [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}
|
|
var s Scalar
|
|
if !s.setB32Seckey(validKey[:]) {
|
|
t.Error("Valid secret key should be accepted")
|
|
}
|
|
|
|
// Test zero key (invalid)
|
|
zeroKey := [32]byte{}
|
|
if s.setB32Seckey(zeroKey[:]) {
|
|
t.Error("Zero secret key should be rejected")
|
|
}
|
|
|
|
// Test group order key (invalid)
|
|
orderKey := [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, 0x41}
|
|
if s.setB32Seckey(orderKey[:]) {
|
|
t.Error("Group order secret key should be rejected")
|
|
}
|
|
}
|
|
|
|
func TestScalarArithmetic(t *testing.T) {
|
|
// Test addition
|
|
var a, b, c Scalar
|
|
a.setInt(5)
|
|
b.setInt(7)
|
|
c.add(&a, &b)
|
|
|
|
var expected Scalar
|
|
expected.setInt(12)
|
|
if !c.equal(&expected) {
|
|
t.Error("5 + 7 should equal 12")
|
|
}
|
|
|
|
// Test multiplication
|
|
var mult Scalar
|
|
mult.mul(&a, &b)
|
|
|
|
expected.setInt(35)
|
|
if !mult.equal(&expected) {
|
|
t.Error("5 * 7 should equal 35")
|
|
}
|
|
|
|
// Test negation
|
|
var neg Scalar
|
|
neg.negate(&a)
|
|
|
|
var sum Scalar
|
|
sum.add(&a, &neg)
|
|
|
|
if !sum.isZero() {
|
|
t.Error("a + (-a) should equal zero")
|
|
}
|
|
}
|
|
|
|
func TestScalarInverse(t *testing.T) {
|
|
// Test inverse of small numbers
|
|
for i := uint(1); i <= 10; i++ {
|
|
var a, inv, product Scalar
|
|
a.setInt(i)
|
|
inv.inverse(&a)
|
|
product.mul(&a, &inv)
|
|
|
|
if !product.isOne() {
|
|
t.Errorf("a * a^(-1) should equal 1 for a = %d", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestScalarHalf(t *testing.T) {
|
|
// Test halving
|
|
var a, half, doubled Scalar
|
|
|
|
// Test even number
|
|
a.setInt(14)
|
|
half.half(&a)
|
|
doubled.add(&half, &half)
|
|
if !doubled.equal(&a) {
|
|
t.Error("2 * (14/2) should equal 14")
|
|
}
|
|
|
|
// Test odd number
|
|
a.setInt(7)
|
|
half.half(&a)
|
|
doubled.add(&half, &half)
|
|
if !doubled.equal(&a) {
|
|
t.Error("2 * (7/2) should equal 7")
|
|
}
|
|
}
|
|
|
|
func TestScalarProperties(t *testing.T) {
|
|
var a Scalar
|
|
a.setInt(6)
|
|
|
|
// Test even/odd
|
|
if !a.isEven() {
|
|
t.Error("6 should be even")
|
|
}
|
|
|
|
a.setInt(7)
|
|
if a.isEven() {
|
|
t.Error("7 should be odd")
|
|
}
|
|
}
|
|
|
|
func TestScalarConditionalNegate(t *testing.T) {
|
|
var a, original Scalar
|
|
a.setInt(5)
|
|
original = a
|
|
|
|
// Test conditional negate with flag = 0
|
|
a.condNegate(0)
|
|
if !a.equal(&original) {
|
|
t.Error("Conditional negate with flag=0 should not change value")
|
|
}
|
|
|
|
// Test conditional negate with flag = 1
|
|
a.condNegate(1)
|
|
var neg Scalar
|
|
neg.negate(&original)
|
|
if !a.equal(&neg) {
|
|
t.Error("Conditional negate with flag=1 should negate value")
|
|
}
|
|
}
|
|
|
|
func TestScalarGetBits(t *testing.T) {
|
|
var a Scalar
|
|
a.setInt(0x12345678)
|
|
|
|
// Test getting bits
|
|
bits := a.getBits(0, 8)
|
|
if bits != 0x78 {
|
|
t.Errorf("Expected 0x78, got 0x%x", bits)
|
|
}
|
|
|
|
bits = a.getBits(8, 8)
|
|
if bits != 0x56 {
|
|
t.Errorf("Expected 0x56, got 0x%x", bits)
|
|
}
|
|
}
|
|
|
|
func TestScalarConditionalMove(t *testing.T) {
|
|
var a, b, original Scalar
|
|
a.setInt(5)
|
|
b.setInt(10)
|
|
original = a
|
|
|
|
// Test conditional move with flag = 0
|
|
a.cmov(&b, 0)
|
|
if !a.equal(&original) {
|
|
t.Error("Conditional move with flag=0 should not change value")
|
|
}
|
|
|
|
// Test conditional move with flag = 1
|
|
a.cmov(&b, 1)
|
|
if !a.equal(&b) {
|
|
t.Error("Conditional move with flag=1 should copy value")
|
|
}
|
|
}
|
|
|
|
func TestScalarClear(t *testing.T) {
|
|
var s Scalar
|
|
s.setInt(12345)
|
|
|
|
s.clear()
|
|
|
|
// After clearing, should be zero
|
|
if !s.isZero() {
|
|
t.Error("Cleared scalar should be zero")
|
|
}
|
|
}
|
|
|
|
func TestScalarRandomOperations(t *testing.T) {
|
|
// Test with random values
|
|
for i := 0; i < 50; i++ {
|
|
var aBytes, bBytes [32]byte
|
|
rand.Read(aBytes[:])
|
|
rand.Read(bBytes[:])
|
|
|
|
var a, b Scalar
|
|
a.setB32(aBytes[:])
|
|
b.setB32(bBytes[:])
|
|
|
|
// Skip if either is zero
|
|
if a.isZero() || b.isZero() {
|
|
continue
|
|
}
|
|
|
|
// Test (a + b) - a = b
|
|
var sum, diff Scalar
|
|
sum.add(&a, &b)
|
|
diff.sub(&sum, &a)
|
|
if !diff.equal(&b) {
|
|
t.Errorf("Random test %d: (a + b) - a should equal b", i)
|
|
}
|
|
|
|
// Test (a * b) / a = b
|
|
var prod, quot Scalar
|
|
prod.mul(&a, &b)
|
|
var aInv Scalar
|
|
aInv.inverse(&a)
|
|
quot.mul(&prod, &aInv)
|
|
if !quot.equal(&b) {
|
|
t.Errorf("Random test %d: (a * b) / a should equal b", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestScalarEdgeCases(t *testing.T) {
|
|
// Test n-1 + 1 = 0
|
|
nMinus1 := [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}
|
|
|
|
var s Scalar
|
|
s.setB32(nMinus1[:])
|
|
|
|
// Add 1 should give 0
|
|
var one Scalar
|
|
one.setInt(1)
|
|
s.add(&s, &one)
|
|
|
|
if !s.isZero() {
|
|
t.Error("(n-1) + 1 should equal 0 in scalar arithmetic")
|
|
}
|
|
}
|