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:
267
pubkey_test.go
Normal file
267
pubkey_test.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package p256k1
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestECPubkeyCreate(t *testing.T) {
|
||||
// Generate a random private key
|
||||
seckey := make([]byte, 32)
|
||||
if _, err := rand.Read(seckey); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ensure it's a valid private key (not zero, not >= order)
|
||||
var scalar Scalar
|
||||
for !scalar.setB32Seckey(seckey) {
|
||||
if _, err := rand.Read(seckey); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create public key
|
||||
var pubkey PublicKey
|
||||
err := ECPubkeyCreate(&pubkey, seckey)
|
||||
if err != nil {
|
||||
t.Errorf("ECPubkeyCreate failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify the public key is valid by parsing it
|
||||
var parsed PublicKey
|
||||
var serialized [65]byte
|
||||
length := ECPubkeySerialize(serialized[:], &pubkey, ECUncompressed)
|
||||
if length != 65 {
|
||||
t.Error("uncompressed serialization should be 65 bytes")
|
||||
}
|
||||
|
||||
err = ECPubkeyParse(&parsed, serialized[:length])
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse created public key: %v", err)
|
||||
}
|
||||
|
||||
// Compare original and parsed
|
||||
if ECPubkeyCmp(&pubkey, &parsed) != 0 {
|
||||
t.Error("parsed public key should equal original")
|
||||
}
|
||||
}
|
||||
|
||||
func TestECPubkeyParse(t *testing.T) {
|
||||
// Test with generator point (known valid point)
|
||||
// Generator X: 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
|
||||
// Generator Y: 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
|
||||
|
||||
// Uncompressed format
|
||||
uncompressed := []byte{
|
||||
0x04,
|
||||
0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
|
||||
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
|
||||
0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
|
||||
0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8,
|
||||
}
|
||||
|
||||
var pubkey PublicKey
|
||||
err := ECPubkeyParse(&pubkey, uncompressed)
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse uncompressed generator: %v", err)
|
||||
}
|
||||
|
||||
// Compressed format (even Y)
|
||||
compressed := []byte{
|
||||
0x02,
|
||||
0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
|
||||
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
|
||||
}
|
||||
|
||||
var pubkey2 PublicKey
|
||||
err = ECPubkeyParse(&pubkey2, compressed)
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse compressed generator: %v", err)
|
||||
}
|
||||
|
||||
// Both should be equal
|
||||
if ECPubkeyCmp(&pubkey, &pubkey2) != 0 {
|
||||
t.Error("compressed and uncompressed generator should be equal")
|
||||
}
|
||||
|
||||
// Test invalid inputs
|
||||
invalidInputs := [][]byte{
|
||||
{}, // empty
|
||||
{0x05}, // invalid prefix
|
||||
{0x04, 0x00}, // too short
|
||||
make([]byte, 66), // too long
|
||||
{0x02}, // compressed too short
|
||||
make([]byte, 34), // compressed too long
|
||||
}
|
||||
|
||||
for i, invalid := range invalidInputs {
|
||||
var dummy PublicKey
|
||||
err := ECPubkeyParse(&dummy, invalid)
|
||||
if err == nil {
|
||||
t.Errorf("invalid input %d should have failed", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestECPubkeySerialize(t *testing.T) {
|
||||
// Create a public key from a known private key
|
||||
seckey := []byte{
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
}
|
||||
|
||||
var pubkey PublicKey
|
||||
err := ECPubkeyCreate(&pubkey, seckey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create public key: %v", err)
|
||||
}
|
||||
|
||||
// Test compressed serialization
|
||||
var compressed [33]byte
|
||||
compressedLength := ECPubkeySerialize(compressed[:], &pubkey, ECCompressed)
|
||||
if compressedLength != 33 {
|
||||
t.Errorf("compressed serialization should return 33 bytes, got %d", compressedLength)
|
||||
}
|
||||
if compressed[0] != 0x02 && compressed[0] != 0x03 {
|
||||
t.Errorf("compressed format should start with 0x02 or 0x03, got 0x%02x", compressed[0])
|
||||
}
|
||||
|
||||
// Test uncompressed serialization
|
||||
var uncompressed [65]byte
|
||||
uncompressedLength := ECPubkeySerialize(uncompressed[:], &pubkey, ECUncompressed)
|
||||
if uncompressedLength != 65 {
|
||||
t.Errorf("uncompressed serialization should return 65 bytes, got %d", uncompressedLength)
|
||||
}
|
||||
if uncompressed[0] != 0x04 {
|
||||
t.Errorf("uncompressed format should start with 0x04, got 0x%02x", uncompressed[0])
|
||||
}
|
||||
|
||||
// Test round-trip
|
||||
var parsed1, parsed2 PublicKey
|
||||
err = ECPubkeyParse(&parsed1, compressed[:compressedLength])
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse compressed: %v", err)
|
||||
}
|
||||
|
||||
err = ECPubkeyParse(&parsed2, uncompressed[:uncompressedLength])
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse uncompressed: %v", err)
|
||||
}
|
||||
|
||||
if ECPubkeyCmp(&parsed1, &parsed2) != 0 {
|
||||
t.Error("round-trip should preserve public key")
|
||||
}
|
||||
|
||||
// Test buffer too small
|
||||
var small [32]byte
|
||||
smallLength := ECPubkeySerialize(small[:], &pubkey, ECCompressed)
|
||||
if smallLength != 0 {
|
||||
t.Error("serialization with small buffer should return 0")
|
||||
}
|
||||
|
||||
// Test invalid flags
|
||||
invalidLength := ECPubkeySerialize(compressed[:], &pubkey, 0xFF)
|
||||
if invalidLength != 0 {
|
||||
t.Error("serialization with invalid flags should return 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestECPubkeyCmp(t *testing.T) {
|
||||
// Create two different public keys
|
||||
seckey1 := []byte{
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
}
|
||||
seckey2 := []byte{
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
}
|
||||
|
||||
var pubkey1, pubkey2, pubkey3 PublicKey
|
||||
|
||||
err := ECPubkeyCreate(&pubkey1, seckey1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create pubkey1: %v", err)
|
||||
}
|
||||
|
||||
err = ECPubkeyCreate(&pubkey2, seckey2)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create pubkey2: %v", err)
|
||||
}
|
||||
|
||||
err = ECPubkeyCreate(&pubkey3, seckey1) // Same as pubkey1
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create pubkey3: %v", err)
|
||||
}
|
||||
|
||||
// Test equality
|
||||
if ECPubkeyCmp(&pubkey1, &pubkey3) != 0 {
|
||||
t.Error("identical public keys should compare equal")
|
||||
}
|
||||
|
||||
// Test inequality
|
||||
cmp := ECPubkeyCmp(&pubkey1, &pubkey2)
|
||||
if cmp == 0 {
|
||||
t.Error("different public keys should not compare equal")
|
||||
}
|
||||
|
||||
// Test symmetry
|
||||
cmp2 := ECPubkeyCmp(&pubkey2, &pubkey1)
|
||||
if (cmp > 0 && cmp2 >= 0) || (cmp < 0 && cmp2 <= 0) {
|
||||
t.Error("comparison should be antisymmetric")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECPubkeyCreate(b *testing.B) {
|
||||
seckey := []byte{
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var pubkey PublicKey
|
||||
ECPubkeyCreate(&pubkey, seckey)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECPubkeySerializeCompressed(b *testing.B) {
|
||||
seckey := []byte{
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
}
|
||||
|
||||
var pubkey PublicKey
|
||||
ECPubkeyCreate(&pubkey, seckey)
|
||||
var output [33]byte
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ECPubkeySerialize(output[:], &pubkey, ECCompressed)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECPubkeyParse(b *testing.B) {
|
||||
// Use generator point in compressed format
|
||||
compressed := []byte{
|
||||
0x02,
|
||||
0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
|
||||
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var pubkey PublicKey
|
||||
ECPubkeyParse(&pubkey, compressed)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user