Files
p256k1/integration_test.go

620 lines
16 KiB
Go

package p256k1
import (
"crypto/rand"
"testing"
)
// Test complete ECDSA signing and verification workflow
func TestECDSASignVerifyWorkflow(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Generate a random secret key
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
// Create public key
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
t.Fatal("Failed to create public key")
}
// Create message hash
var msghash [32]byte
_, err = rand.Read(msghash[:])
if err != nil {
t.Fatalf("Failed to generate message hash: %v", err)
}
// Sign the message
var sig Signature
if !ECDSASign(ctx, &sig, msghash[:], seckey[:], nil, nil) {
t.Fatal("Failed to sign message")
}
// Verify the signature
if !ECDSAVerify(ctx, &sig, msghash[:], &pubkey) {
t.Fatal("Failed to verify signature")
}
// Test that signature fails with wrong message
msghash[0] ^= 1 // Flip one bit
if ECDSAVerify(ctx, &sig, msghash[:], &pubkey) {
t.Error("Signature should not verify with modified message")
}
// Restore message and test with wrong public key
msghash[0] ^= 1 // Restore original message
var wrongSeckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(wrongSeckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, wrongSeckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid wrong secret key after 10 attempts")
}
}
var wrongPubkey PublicKey
if !ECPubkeyCreate(ctx, &wrongPubkey, wrongSeckey[:]) {
t.Fatal("Failed to create wrong public key")
}
if ECDSAVerify(ctx, &sig, msghash[:], &wrongPubkey) {
t.Error("Signature should not verify with wrong public key")
}
}
// Test signature serialization and parsing
func TestSignatureSerialization(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Create a signature
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var msghash [32]byte
_, err = rand.Read(msghash[:])
if err != nil {
t.Fatalf("Failed to generate message hash: %v", err)
}
var sig Signature
if !ECDSASign(ctx, &sig, msghash[:], seckey[:], nil, nil) {
t.Fatal("Failed to sign message")
}
// Test compact serialization
var compact [64]byte
if !ECDSASignatureSerializeCompact(ctx, compact[:], &sig) {
t.Fatal("Failed to serialize signature in compact format")
}
// Parse back from compact format
var parsedSig Signature
if !ECDSASignatureParseCompact(ctx, &parsedSig, compact[:]) {
t.Fatal("Failed to parse signature from compact format")
}
// Serialize again and compare
var compact2 [64]byte
if !ECDSASignatureSerializeCompact(ctx, compact2[:], &parsedSig) {
t.Fatal("Failed to serialize parsed signature")
}
for i := 0; i < 64; i++ {
if compact[i] != compact2[i] {
t.Error("Compact serialization round-trip failed")
break
}
}
// Test DER serialization
var der [72]byte // Max DER size
derLen := 72
if !ECDSASignatureSerializeDER(ctx, der[:], &derLen, &sig) {
t.Fatal("Failed to serialize signature in DER format")
}
// Parse back from DER format
var parsedSigDER Signature
if !ECDSASignatureParseDER(ctx, &parsedSigDER, der[:derLen]) {
t.Fatal("Failed to parse signature from DER format")
}
// Verify both parsed signatures work
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
t.Fatal("Failed to create public key")
}
if !ECDSAVerify(ctx, &parsedSig, msghash[:], &pubkey) {
t.Error("Parsed compact signature should verify")
}
if !ECDSAVerify(ctx, &parsedSigDER, msghash[:], &pubkey) {
t.Error("Parsed DER signature should verify")
}
}
// Test public key serialization and parsing
func TestPublicKeySerialization(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Create a public key
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
t.Fatal("Failed to create public key")
}
// Test compressed serialization
var compressed [33]byte
compressedLen := 33
if !ECPubkeySerialize(ctx, compressed[:], &compressedLen, &pubkey, ECCompressed) {
t.Fatal("Failed to serialize public key in compressed format")
}
if compressedLen != 33 {
t.Errorf("Expected compressed length 33, got %d", compressedLen)
}
// Test uncompressed serialization
var uncompressed [65]byte
uncompressedLen := 65
if !ECPubkeySerialize(ctx, uncompressed[:], &uncompressedLen, &pubkey, ECUncompressed) {
t.Fatal("Failed to serialize public key in uncompressed format")
}
if uncompressedLen != 65 {
t.Errorf("Expected uncompressed length 65, got %d", uncompressedLen)
}
// Parse compressed format
var parsedCompressed PublicKey
if !ECPubkeyParse(ctx, &parsedCompressed, compressed[:compressedLen]) {
t.Fatal("Failed to parse compressed public key")
}
// Parse uncompressed format
var parsedUncompressed PublicKey
if !ECPubkeyParse(ctx, &parsedUncompressed, uncompressed[:uncompressedLen]) {
t.Fatal("Failed to parse uncompressed public key")
}
// Both should represent the same key
var compressedAgain [33]byte
compressedAgainLen := 33
if !ECPubkeySerialize(ctx, compressedAgain[:], &compressedAgainLen, &parsedCompressed, ECCompressed) {
t.Fatal("Failed to serialize parsed compressed key")
}
var uncompressedAgain [33]byte
uncompressedAgainLen := 33
if !ECPubkeySerialize(ctx, uncompressedAgain[:], &uncompressedAgainLen, &parsedUncompressed, ECCompressed) {
t.Fatal("Failed to serialize parsed uncompressed key")
}
for i := 0; i < 33; i++ {
if compressedAgain[i] != uncompressedAgain[i] {
t.Error("Compressed and uncompressed should represent same key")
break
}
}
}
// Test public key comparison
func TestPublicKeyComparison(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Create two different keys
var seckey1, seckey2 [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey1[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey1[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key 1 after 10 attempts")
}
}
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey2[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey2[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key 2 after 10 attempts")
}
}
var pubkey1, pubkey2, pubkey1Copy PublicKey
if !ECPubkeyCreate(ctx, &pubkey1, seckey1[:]) {
t.Fatal("Failed to create public key 1")
}
if !ECPubkeyCreate(ctx, &pubkey2, seckey2[:]) {
t.Fatal("Failed to create public key 2")
}
if !ECPubkeyCreate(ctx, &pubkey1Copy, seckey1[:]) {
t.Fatal("Failed to create public key 1 copy")
}
// Test comparison
cmp1vs2 := ECPubkeyCmp(ctx, &pubkey1, &pubkey2)
cmp2vs1 := ECPubkeyCmp(ctx, &pubkey2, &pubkey1)
cmp1vs1 := ECPubkeyCmp(ctx, &pubkey1, &pubkey1Copy)
if cmp1vs2 == 0 {
t.Error("Different keys should not compare equal")
}
if cmp2vs1 == 0 {
t.Error("Different keys should not compare equal (reversed)")
}
if cmp1vs1 != 0 {
t.Error("Same keys should compare equal")
}
if (cmp1vs2 > 0) == (cmp2vs1 > 0) {
t.Error("Comparison should be antisymmetric")
}
}
// Test context randomization
func TestContextRandomization(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Test randomization with random seed
var seed [32]byte
_, err = rand.Read(seed[:])
if err != nil {
t.Fatalf("Failed to generate random seed: %v", err)
}
err = ContextRandomize(ctx, seed[:])
if err != nil {
t.Errorf("Context randomization failed: %v", err)
}
// Test that randomized context still works
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
t.Error("Key generation should work with randomized context")
}
// Test signing with randomized context
var msghash [32]byte
_, err = rand.Read(msghash[:])
if err != nil {
t.Fatalf("Failed to generate message hash: %v", err)
}
var sig Signature
if !ECDSASign(ctx, &sig, msghash[:], seckey[:], nil, nil) {
t.Error("Signing should work with randomized context")
}
if !ECDSAVerify(ctx, &sig, msghash[:], &pubkey) {
t.Error("Verification should work with randomized context")
}
// Test randomization with nil seed (should work)
err = ContextRandomize(ctx, nil)
if err != nil {
t.Errorf("Context randomization with nil seed failed: %v", err)
}
}
// Test multiple signatures with same key
func TestMultipleSignatures(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Generate key pair
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
t.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
t.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
t.Fatal("Failed to create public key")
}
// Sign multiple different messages
numMessages := 10
messages := make([][32]byte, numMessages)
signatures := make([]Signature, numMessages)
for i := 0; i < numMessages; i++ {
_, err = rand.Read(messages[i][:])
if err != nil {
t.Fatalf("Failed to generate message %d: %v", i, err)
}
if !ECDSASign(ctx, &signatures[i], messages[i][:], seckey[:], nil, nil) {
t.Fatalf("Failed to sign message %d", i)
}
}
// Verify all signatures
for i := 0; i < numMessages; i++ {
if !ECDSAVerify(ctx, &signatures[i], messages[i][:], &pubkey) {
t.Errorf("Failed to verify signature %d", i)
}
// Test cross-verification (should fail)
for j := 0; j < numMessages; j++ {
if i != j {
if ECDSAVerify(ctx, &signatures[i], messages[j][:], &pubkey) {
t.Errorf("Signature %d should not verify message %d", i, j)
}
}
}
}
}
// Test edge cases and error conditions
func TestEdgeCases(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Test invalid secret keys
var zeroKey [32]byte // All zeros
if ECSecKeyVerify(ctx, zeroKey[:]) {
t.Error("Zero secret key should be invalid")
}
var overflowKey [32]byte
// Set to group order (invalid)
overflowBytes := []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,
}
copy(overflowKey[:], overflowBytes)
if ECSecKeyVerify(ctx, overflowKey[:]) {
t.Error("Overflowing secret key should be invalid")
}
// Test invalid public key parsing
var invalidPubkey PublicKey
invalidBytes := []byte{0xFF, 0xFF, 0xFF} // Too short
if ECPubkeyParse(ctx, &invalidPubkey, invalidBytes) {
t.Error("Invalid public key bytes should not parse")
}
// Test invalid signature parsing
var invalidSig Signature
invalidSigBytes := make([]byte, 64)
for i := range invalidSigBytes {
invalidSigBytes[i] = 0xFF // All 0xFF (likely invalid)
}
if ECDSASignatureParseCompact(ctx, &invalidSig, invalidSigBytes) {
// This might succeed depending on implementation, so we just test it doesn't crash
}
}
// Test selftest functionality
func TestSelftest(t *testing.T) {
if err := Selftest(); err != nil {
t.Errorf("Selftest failed: %v", err)
}
}
// Integration test with known test vectors
func TestKnownTestVectors(t *testing.T) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
t.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Test vector from Bitcoin Core tests
seckey := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
}
if !ECSecKeyVerify(ctx, seckey) {
t.Fatal("Test vector secret key should be valid")
}
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey) {
t.Fatal("Failed to create public key from test vector")
}
// Serialize and check against expected value
var serialized [33]byte
serializedLen := 33
if !ECPubkeySerialize(ctx, serialized[:], &serializedLen, &pubkey, ECCompressed) {
t.Fatal("Failed to serialize test vector public key")
}
// The expected compressed public key for secret key 1
expected := []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,
}
for i := 0; i < 33; i++ {
if serialized[i] != expected[i] {
t.Errorf("Public key mismatch at byte %d: expected %02x, got %02x", i, expected[i], serialized[i])
}
}
}
// Benchmark integration tests
func BenchmarkFullECDSAWorkflow(b *testing.B) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
b.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Pre-generate key and message
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
b.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
b.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var pubkey PublicKey
if !ECPubkeyCreate(ctx, &pubkey, seckey[:]) {
b.Fatal("Failed to create public key")
}
var msghash [32]byte
rand.Read(msghash[:])
b.ResetTimer()
for i := 0; i < b.N; i++ {
var sig Signature
if !ECDSASign(ctx, &sig, msghash[:], seckey[:], nil, nil) {
b.Fatal("Failed to sign")
}
if !ECDSAVerify(ctx, &sig, msghash[:], &pubkey) {
b.Fatal("Failed to verify")
}
}
}
func BenchmarkKeyGeneration(b *testing.B) {
ctx, err := ContextCreate(ContextNone)
if err != nil {
b.Fatalf("Failed to create context: %v", err)
}
defer ContextDestroy(ctx)
// Pre-generate valid secret key
var seckey [32]byte
for i := 0; i < 10; i++ {
_, err = rand.Read(seckey[:])
if err != nil {
b.Fatalf("Failed to generate random bytes: %v", err)
}
if ECSecKeyVerify(ctx, seckey[:]) {
break
}
if i == 9 {
b.Fatal("Failed to generate valid secret key after 10 attempts")
}
}
var pubkey PublicKey
b.ResetTimer()
for i := 0; i < b.N; i++ {
ECPubkeyCreate(ctx, &pubkey, seckey[:])
}
}