This commit introduces direct function implementations for various scalar and field operations, including addition, multiplication, normalization, and serialization. These changes aim to optimize performance by avoiding interface dispatch and reducing allocations. Additionally, the existing methods are updated to utilize these new direct functions, enhancing overall efficiency in the secp256k1 library.
279 lines
6.1 KiB
Go
279 lines
6.1 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestSchnorrSignVerify(t *testing.T) {
|
|
// Generate keypair
|
|
kp, err := KeyPairGenerate()
|
|
if err != nil {
|
|
t.Fatalf("failed to generate keypair: %v", err)
|
|
}
|
|
defer kp.Clear()
|
|
|
|
// Get x-only pubkey
|
|
xonly, err := kp.XOnlyPubkey()
|
|
if err != nil {
|
|
t.Fatalf("failed to get x-only pubkey: %v", err)
|
|
}
|
|
|
|
// Create message
|
|
msg := make([]byte, 32)
|
|
for i := range msg {
|
|
msg[i] = byte(i)
|
|
}
|
|
|
|
// Sign
|
|
var sig [64]byte
|
|
if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
|
|
// Verify
|
|
if !SchnorrVerify(sig[:], msg, xonly) {
|
|
t.Error("signature verification failed")
|
|
}
|
|
|
|
// Test with wrong message
|
|
wrongMsg := make([]byte, 32)
|
|
copy(wrongMsg, msg)
|
|
wrongMsg[0] ^= 1
|
|
if SchnorrVerify(sig[:], wrongMsg, xonly) {
|
|
t.Error("signature verification should fail with wrong message")
|
|
}
|
|
}
|
|
|
|
func TestSchnorrSignWithAuxRand(t *testing.T) {
|
|
// Generate keypair
|
|
kp, err := KeyPairGenerate()
|
|
if err != nil {
|
|
t.Fatalf("failed to generate keypair: %v", err)
|
|
}
|
|
defer kp.Clear()
|
|
|
|
// Get x-only pubkey
|
|
xonly, err := kp.XOnlyPubkey()
|
|
if err != nil {
|
|
t.Fatalf("failed to get x-only pubkey: %v", err)
|
|
}
|
|
|
|
// Create message
|
|
msg := make([]byte, 32)
|
|
for i := range msg {
|
|
msg[i] = byte(i)
|
|
}
|
|
|
|
// Auxiliary randomness
|
|
auxRand := make([]byte, 32)
|
|
for i := range auxRand {
|
|
auxRand[i] = byte(i + 100)
|
|
}
|
|
|
|
// Sign
|
|
var sig [64]byte
|
|
if err := SchnorrSign(sig[:], msg, kp, auxRand); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
|
|
// Verify
|
|
if !SchnorrVerify(sig[:], msg, xonly) {
|
|
t.Error("signature verification failed")
|
|
}
|
|
}
|
|
|
|
func TestSchnorrVerifyInvalid(t *testing.T) {
|
|
// Generate keypair
|
|
kp, err := KeyPairGenerate()
|
|
if err != nil {
|
|
t.Fatalf("failed to generate keypair: %v", err)
|
|
}
|
|
defer kp.Clear()
|
|
|
|
// Get x-only pubkey
|
|
xonly, err := kp.XOnlyPubkey()
|
|
if err != nil {
|
|
t.Fatalf("failed to get x-only pubkey: %v", err)
|
|
}
|
|
|
|
msg := make([]byte, 32)
|
|
|
|
// Test with invalid signature length
|
|
if SchnorrVerify([]byte{1}, msg, xonly) {
|
|
t.Error("should fail with invalid signature length")
|
|
}
|
|
|
|
// Test with invalid message length
|
|
var sig [64]byte
|
|
if SchnorrVerify(sig[:], []byte{1}, xonly) {
|
|
t.Error("should fail with invalid message length")
|
|
}
|
|
|
|
// Test with nil pubkey
|
|
if SchnorrVerify(sig[:], msg, nil) {
|
|
t.Error("should fail with nil pubkey")
|
|
}
|
|
}
|
|
|
|
func TestNonceFunctionBIP340(t *testing.T) {
|
|
key32 := make([]byte, 32)
|
|
xonlyPk32 := make([]byte, 32)
|
|
msg := []byte("test message")
|
|
auxRand32 := make([]byte, 32)
|
|
|
|
// Initialize test data
|
|
for i := range key32 {
|
|
key32[i] = byte(i)
|
|
}
|
|
for i := range xonlyPk32 {
|
|
xonlyPk32[i] = byte(i + 10)
|
|
}
|
|
for i := range auxRand32 {
|
|
auxRand32[i] = byte(i + 20)
|
|
}
|
|
|
|
// Test with aux random
|
|
var nonce1 [32]byte
|
|
if err := NonceFunctionBIP340(nonce1[:], msg, key32, xonlyPk32, auxRand32); err != nil {
|
|
t.Fatalf("nonce generation failed: %v", err)
|
|
}
|
|
|
|
// Test without aux random
|
|
var nonce2 [32]byte
|
|
if err := NonceFunctionBIP340(nonce2[:], msg, key32, xonlyPk32, nil); err != nil {
|
|
t.Fatalf("nonce generation failed: %v", err)
|
|
}
|
|
|
|
// Nonces should be different
|
|
allSame := true
|
|
for i := 0; i < 32; i++ {
|
|
if nonce1[i] != nonce2[i] {
|
|
allSame = false
|
|
break
|
|
}
|
|
}
|
|
if allSame {
|
|
t.Error("nonces should differ with different aux random")
|
|
}
|
|
}
|
|
|
|
func TestSchnorrMultipleSignatures(t *testing.T) {
|
|
// Test that multiple signatures with same keypair are different when using different aux_rand
|
|
kp, err := KeyPairGenerate()
|
|
if err != nil {
|
|
t.Fatalf("failed to generate keypair: %v", err)
|
|
}
|
|
defer kp.Clear()
|
|
|
|
xonly, err := kp.XOnlyPubkey()
|
|
if err != nil {
|
|
t.Fatalf("failed to get x-only pubkey: %v", err)
|
|
}
|
|
|
|
msg := make([]byte, 32)
|
|
|
|
// Sign without aux_rand (deterministic - should be same)
|
|
var sig1, sig2 [64]byte
|
|
if err := SchnorrSign(sig1[:], msg, kp, nil); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
if err := SchnorrSign(sig2[:], msg, kp, nil); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
|
|
// Both should verify
|
|
if !SchnorrVerify(sig1[:], msg, xonly) {
|
|
t.Error("signature 1 verification failed")
|
|
}
|
|
if !SchnorrVerify(sig2[:], msg, xonly) {
|
|
t.Error("signature 2 verification failed")
|
|
}
|
|
|
|
// Without aux_rand, signatures should be deterministic (same)
|
|
allSame := true
|
|
for i := 0; i < 64; i++ {
|
|
if sig1[i] != sig2[i] {
|
|
allSame = false
|
|
break
|
|
}
|
|
}
|
|
if !allSame {
|
|
t.Error("without aux_rand, signatures should be deterministic (same)")
|
|
}
|
|
|
|
// Sign with different aux_rand (should be different)
|
|
auxRand1 := make([]byte, 32)
|
|
auxRand2 := make([]byte, 32)
|
|
for i := range auxRand1 {
|
|
auxRand1[i] = byte(i)
|
|
auxRand2[i] = byte(i + 1)
|
|
}
|
|
|
|
if err := SchnorrSign(sig1[:], msg, kp, auxRand1); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
if err := SchnorrSign(sig2[:], msg, kp, auxRand2); err != nil {
|
|
t.Fatalf("failed to sign: %v", err)
|
|
}
|
|
|
|
// Both should verify
|
|
if !SchnorrVerify(sig1[:], msg, xonly) {
|
|
t.Error("signature 1 verification failed")
|
|
}
|
|
if !SchnorrVerify(sig2[:], msg, xonly) {
|
|
t.Error("signature 2 verification failed")
|
|
}
|
|
|
|
// With different aux_rand, signatures should differ
|
|
allSame = true
|
|
for i := 0; i < 64; i++ {
|
|
if sig1[i] != sig2[i] {
|
|
allSame = false
|
|
break
|
|
}
|
|
}
|
|
if allSame {
|
|
t.Error("with different aux_rand, signatures should differ")
|
|
}
|
|
}
|
|
|
|
func BenchmarkSchnorrVerify(b *testing.B) {
|
|
// Generate test data once outside the benchmark loop
|
|
kp, err := KeyPairGenerate()
|
|
if err != nil {
|
|
b.Fatalf("failed to generate keypair: %v", err)
|
|
}
|
|
defer kp.Clear()
|
|
|
|
xonly, err := kp.XOnlyPubkey()
|
|
if err != nil {
|
|
b.Fatalf("failed to get x-only pubkey: %v", err)
|
|
}
|
|
|
|
msg := make([]byte, 32)
|
|
for i := range msg {
|
|
msg[i] = byte(i)
|
|
}
|
|
|
|
sig := make([]byte, 64)
|
|
if err := SchnorrSign(sig, msg, kp, nil); err != nil {
|
|
b.Fatalf("failed to sign: %v", err)
|
|
}
|
|
|
|
// Convert to internal types once
|
|
var secpXonly secp256k1_xonly_pubkey
|
|
copy(secpXonly.data[:], xonly.data[:])
|
|
|
|
// Benchmark verification with pre-computed values
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
ctx := getSchnorrVerifyContext()
|
|
for i := 0; i < b.N; i++ {
|
|
result := secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &secpXonly)
|
|
if result == 0 {
|
|
b.Fatal("verification failed")
|
|
}
|
|
}
|
|
}
|