schnorr_test.go raw

   1  //go:build !js && !wasm && !tinygo && !wasm32
   2  
   3  package p256k1
   4  
   5  import (
   6  	"testing"
   7  )
   8  
   9  func TestSchnorrSignVerify(t *testing.T) {
  10  	// Generate keypair
  11  	kp, err := KeyPairGenerate()
  12  	if err != nil {
  13  		t.Fatalf("failed to generate keypair: %v", err)
  14  	}
  15  	defer kp.Clear()
  16  
  17  	// Get x-only pubkey
  18  	xonly, err := kp.XOnlyPubkey()
  19  	if err != nil {
  20  		t.Fatalf("failed to get x-only pubkey: %v", err)
  21  	}
  22  
  23  	// Create message
  24  	msg := make([]byte, 32)
  25  	for i := range msg {
  26  		msg[i] = byte(i)
  27  	}
  28  
  29  	// Sign
  30  	var sig [64]byte
  31  	if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
  32  		t.Fatalf("failed to sign: %v", err)
  33  	}
  34  
  35  	// Verify
  36  	if !SchnorrVerify(sig[:], msg, xonly) {
  37  		t.Error("signature verification failed")
  38  	}
  39  
  40  	// Test with wrong message
  41  	wrongMsg := make([]byte, 32)
  42  	copy(wrongMsg, msg)
  43  	wrongMsg[0] ^= 1
  44  	if SchnorrVerify(sig[:], wrongMsg, xonly) {
  45  		t.Error("signature verification should fail with wrong message")
  46  	}
  47  }
  48  
  49  func TestSchnorrSignWithAuxRand(t *testing.T) {
  50  	// Generate keypair
  51  	kp, err := KeyPairGenerate()
  52  	if err != nil {
  53  		t.Fatalf("failed to generate keypair: %v", err)
  54  	}
  55  	defer kp.Clear()
  56  
  57  	// Get x-only pubkey
  58  	xonly, err := kp.XOnlyPubkey()
  59  	if err != nil {
  60  		t.Fatalf("failed to get x-only pubkey: %v", err)
  61  	}
  62  
  63  	// Create message
  64  	msg := make([]byte, 32)
  65  	for i := range msg {
  66  		msg[i] = byte(i)
  67  	}
  68  
  69  	// Auxiliary randomness
  70  	auxRand := make([]byte, 32)
  71  	for i := range auxRand {
  72  		auxRand[i] = byte(i + 100)
  73  	}
  74  
  75  	// Sign
  76  	var sig [64]byte
  77  	if err := SchnorrSign(sig[:], msg, kp, auxRand); err != nil {
  78  		t.Fatalf("failed to sign: %v", err)
  79  	}
  80  
  81  	// Verify
  82  	if !SchnorrVerify(sig[:], msg, xonly) {
  83  		t.Error("signature verification failed")
  84  	}
  85  }
  86  
  87  func TestSchnorrVerifyInvalid(t *testing.T) {
  88  	// Generate keypair
  89  	kp, err := KeyPairGenerate()
  90  	if err != nil {
  91  		t.Fatalf("failed to generate keypair: %v", err)
  92  	}
  93  	defer kp.Clear()
  94  
  95  	// Get x-only pubkey
  96  	xonly, err := kp.XOnlyPubkey()
  97  	if err != nil {
  98  		t.Fatalf("failed to get x-only pubkey: %v", err)
  99  	}
 100  
 101  	msg := make([]byte, 32)
 102  
 103  	// Test with invalid signature length
 104  	if SchnorrVerify([]byte{1}, msg, xonly) {
 105  		t.Error("should fail with invalid signature length")
 106  	}
 107  
 108  	// Test with invalid message length
 109  	var sig [64]byte
 110  	if SchnorrVerify(sig[:], []byte{1}, xonly) {
 111  		t.Error("should fail with invalid message length")
 112  	}
 113  
 114  	// Test with nil pubkey
 115  	if SchnorrVerify(sig[:], msg, nil) {
 116  		t.Error("should fail with nil pubkey")
 117  	}
 118  }
 119  
 120  func TestNonceFunctionBIP340(t *testing.T) {
 121  	key32 := make([]byte, 32)
 122  	xonlyPk32 := make([]byte, 32)
 123  	msg := make([]byte, 32) // BIP-340 requires 32-byte message hash
 124  	auxRand32 := make([]byte, 32)
 125  
 126  	// Initialize test data
 127  	for i := range key32 {
 128  		key32[i] = byte(i)
 129  	}
 130  	for i := range xonlyPk32 {
 131  		xonlyPk32[i] = byte(i + 10)
 132  	}
 133  	for i := range auxRand32 {
 134  		auxRand32[i] = byte(i + 20)
 135  	}
 136  
 137  	// Test with aux random
 138  	var nonce1 [32]byte
 139  	if err := NonceFunctionBIP340(nonce1[:], msg, key32, xonlyPk32, auxRand32); err != nil {
 140  		t.Fatalf("nonce generation failed: %v", err)
 141  	}
 142  
 143  	// Test without aux random
 144  	var nonce2 [32]byte
 145  	if err := NonceFunctionBIP340(nonce2[:], msg, key32, xonlyPk32, nil); err != nil {
 146  		t.Fatalf("nonce generation failed: %v", err)
 147  	}
 148  
 149  	// Nonces should be different
 150  	allSame := true
 151  	for i := 0; i < 32; i++ {
 152  		if nonce1[i] != nonce2[i] {
 153  			allSame = false
 154  			break
 155  		}
 156  	}
 157  	if allSame {
 158  		t.Error("nonces should differ with different aux random")
 159  	}
 160  }
 161  
 162  func TestSchnorrMultipleSignatures(t *testing.T) {
 163  	// Test that multiple signatures with same keypair are different when using different aux_rand
 164  	kp, err := KeyPairGenerate()
 165  	if err != nil {
 166  		t.Fatalf("failed to generate keypair: %v", err)
 167  	}
 168  	defer kp.Clear()
 169  
 170  	xonly, err := kp.XOnlyPubkey()
 171  	if err != nil {
 172  		t.Fatalf("failed to get x-only pubkey: %v", err)
 173  	}
 174  
 175  	msg := make([]byte, 32)
 176  
 177  	// Sign without aux_rand (deterministic - should be same)
 178  	var sig1, sig2 [64]byte
 179  	if err := SchnorrSign(sig1[:], msg, kp, nil); err != nil {
 180  		t.Fatalf("failed to sign: %v", err)
 181  	}
 182  	if err := SchnorrSign(sig2[:], msg, kp, nil); err != nil {
 183  		t.Fatalf("failed to sign: %v", err)
 184  	}
 185  
 186  	// Both should verify
 187  	if !SchnorrVerify(sig1[:], msg, xonly) {
 188  		t.Error("signature 1 verification failed")
 189  	}
 190  	if !SchnorrVerify(sig2[:], msg, xonly) {
 191  		t.Error("signature 2 verification failed")
 192  	}
 193  
 194  	// Without aux_rand, signatures should be deterministic (same)
 195  	allSame := true
 196  	for i := 0; i < 64; i++ {
 197  		if sig1[i] != sig2[i] {
 198  			allSame = false
 199  			break
 200  		}
 201  	}
 202  	if !allSame {
 203  		t.Error("without aux_rand, signatures should be deterministic (same)")
 204  	}
 205  
 206  	// Sign with different aux_rand (should be different)
 207  	auxRand1 := make([]byte, 32)
 208  	auxRand2 := make([]byte, 32)
 209  	for i := range auxRand1 {
 210  		auxRand1[i] = byte(i)
 211  		auxRand2[i] = byte(i + 1)
 212  	}
 213  
 214  	if err := SchnorrSign(sig1[:], msg, kp, auxRand1); err != nil {
 215  		t.Fatalf("failed to sign: %v", err)
 216  	}
 217  	if err := SchnorrSign(sig2[:], msg, kp, auxRand2); err != nil {
 218  		t.Fatalf("failed to sign: %v", err)
 219  	}
 220  
 221  	// Both should verify
 222  	if !SchnorrVerify(sig1[:], msg, xonly) {
 223  		t.Error("signature 1 verification failed")
 224  	}
 225  	if !SchnorrVerify(sig2[:], msg, xonly) {
 226  		t.Error("signature 2 verification failed")
 227  	}
 228  
 229  	// With different aux_rand, signatures should differ
 230  	allSame = true
 231  	for i := 0; i < 64; i++ {
 232  		if sig1[i] != sig2[i] {
 233  			allSame = false
 234  			break
 235  		}
 236  	}
 237  	if allSame {
 238  		t.Error("with different aux_rand, signatures should differ")
 239  	}
 240  }
 241  
 242  func BenchmarkSchnorrVerify(b *testing.B) {
 243  	// Generate test data once outside the benchmark loop
 244  	kp, err := KeyPairGenerate()
 245  	if err != nil {
 246  		b.Fatalf("failed to generate keypair: %v", err)
 247  	}
 248  	defer kp.Clear()
 249  
 250  	xonly, err := kp.XOnlyPubkey()
 251  	if err != nil {
 252  		b.Fatalf("failed to get x-only pubkey: %v", err)
 253  	}
 254  
 255  	msg := make([]byte, 32)
 256  	for i := range msg {
 257  		msg[i] = byte(i)
 258  	}
 259  
 260  	sig := make([]byte, 64)
 261  	if err := SchnorrSign(sig, msg, kp, nil); err != nil {
 262  		b.Fatalf("failed to sign: %v", err)
 263  	}
 264  
 265  	// Convert to internal types once
 266  	var secpXonly secp256k1_xonly_pubkey
 267  	copy(secpXonly.data[:], xonly.data[:])
 268  
 269  	// Benchmark verification with pre-computed values
 270  	b.ResetTimer()
 271  	b.ReportAllocs()
 272  
 273  	ctx := getSchnorrVerifyContext()
 274  	for i := 0; i < b.N; i++ {
 275  		result := secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &secpXonly)
 276  		if result == 0 {
 277  			b.Fatal("verification failed")
 278  		}
 279  	}
 280  }
 281