bench_test.go raw

   1  // Copyright 2013-2016 The btcsuite developers
   2  // Copyright (c) 2015-2022 The Decred developers
   3  // Use of this source code is governed by an ISC
   4  // license that can be found in the LICENSE file.
   5  
   6  package ecdsa
   7  
   8  import (
   9  	"testing"
  10  
  11  	"next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
  12  	"next.orly.dev/pkg/nostr/encoders/hex"
  13  )
  14  
  15  // hexToModNScalar converts the passed hex string into a ModNScalar and will
  16  // panic if there is an error.  This is only provided for the hard-coded
  17  // constants so errors in the source code can be detected. It will only (and
  18  // must only) be called with hard-coded values.
  19  func hexToModNScalar(s string) *secp256k1.ModNScalar {
  20  	b, err := hex.Dec(s)
  21  	if err != nil {
  22  		panic("invalid hex in source file: " + s)
  23  	}
  24  	var scalar secp256k1.ModNScalar
  25  	if overflow := scalar.SetByteSlice(b); overflow {
  26  		panic("hex in source file overflows mod N scalar: " + s)
  27  	}
  28  	return &scalar
  29  }
  30  
  31  // hexToFieldVal converts the passed hex string into a FieldVal and will panic
  32  // if there is an error.  This is only provided for the hard-coded constants so
  33  // errors in the source code can be detected. It will only (and must only) be
  34  // called with hard-coded values.
  35  func hexToFieldVal(s string) *secp256k1.FieldVal {
  36  	b, err := hex.Dec(s)
  37  	if err != nil {
  38  		panic("invalid hex in source file: " + s)
  39  	}
  40  	var f secp256k1.FieldVal
  41  	if overflow := f.SetByteSlice(b); overflow {
  42  		panic("hex in source file overflows mod P: " + s)
  43  	}
  44  	return &f
  45  }
  46  
  47  // BenchmarkSigVerify benchmarks how long it takes the secp256k1 curve to
  48  // verify signatures.
  49  func BenchmarkSigVerify(b *testing.B) {
  50  	// Randomly generated keypair.
  51  	// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
  52  	pubKey := secp256k1.NewPublicKey(
  53  		hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"),
  54  		hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"),
  55  	)
  56  	// Double sha256 of by{0x01, 0x02, 0x03, 0x04}
  57  	msgHash := hexToBytes("8de472e2399610baaa7f84840547cd409434e31f5d3bd71e4d947f283874f9c0")
  58  	sig := NewSignature(
  59  		hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"),
  60  		hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"),
  61  	)
  62  	if !sig.Verify(msgHash, pubKey) {
  63  		b.Errorf("Signature failed to verify")
  64  		return
  65  	}
  66  	b.ReportAllocs()
  67  	b.ResetTimer()
  68  	for i := 0; i < b.N; i++ {
  69  		sig.Verify(msgHash, pubKey)
  70  	}
  71  }
  72  
  73  // BenchmarkSign benchmarks how long it takes to sign a message.
  74  func BenchmarkSign(b *testing.B) {
  75  	// Randomly generated keypair.
  76  	d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
  77  	secKey := secp256k1.NewSecretKey(d)
  78  	// blake256 of by{0x01, 0x02, 0x03, 0x04}.
  79  	msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
  80  	b.ReportAllocs()
  81  	b.ResetTimer()
  82  	for i := 0; i < b.N; i++ {
  83  		signRFC6979(secKey, msgHash)
  84  	}
  85  }
  86  
  87  // BenchmarkSigSerialize benchmarks how long it takes to serialize a typical
  88  // signature with the strict DER encoding.
  89  func BenchmarkSigSerialize(b *testing.B) {
  90  	// Randomly generated keypair.
  91  	// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
  92  	// Signature for double sha256 of by{0x01, 0x02, 0x03, 0x04}.
  93  	sig := NewSignature(
  94  		hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"),
  95  		hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"),
  96  	)
  97  	b.ReportAllocs()
  98  	b.ResetTimer()
  99  	for i := 0; i < b.N; i++ {
 100  		sig.Serialize()
 101  	}
 102  }
 103  
 104  // BenchmarkNonceRFC6979 benchmarks how long it takes to generate a
 105  // deterministic nonce according to RFC6979.
 106  func BenchmarkNonceRFC6979(b *testing.B) {
 107  	// Randomly generated keypair.
 108  	// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
 109  	// X: d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab
 110  	// Y: ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52
 111  	secKeyStr := "9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d"
 112  	secKey := hexToBytes(secKeyStr)
 113  	// BLAKE-256 of by{0x01, 0x02, 0x03, 0x04}.
 114  	msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
 115  	b.ReportAllocs()
 116  	b.ResetTimer()
 117  	var noElideNonce *secp256k1.ModNScalar
 118  	for i := 0; i < b.N; i++ {
 119  		noElideNonce = secp256k1.NonceRFC6979(secKey, msgHash, nil, nil, 0)
 120  	}
 121  	_ = noElideNonce
 122  }
 123  
 124  // BenchmarkSignCompact benchmarks how long it takes to produce a compact
 125  // signature for a message.
 126  func BenchmarkSignCompact(b *testing.B) {
 127  	d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
 128  	secKey := secp256k1.NewSecretKey(d)
 129  	// blake256 of by{0x01, 0x02, 0x03, 0x04}.
 130  	msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
 131  	b.ReportAllocs()
 132  	b.ResetTimer()
 133  	for i := 0; i < b.N; i++ {
 134  		_ = SignCompact(secKey, msgHash, true)
 135  	}
 136  }
 137  
 138  // BenchmarkRecoverCompact benchmarks how long it takes to recover a public key
 139  // given a compact signature and message.
 140  func BenchmarkRecoverCompact(b *testing.B) {
 141  	// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
 142  	wantPubKey := secp256k1.NewPublicKey(
 143  		hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"),
 144  		hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"),
 145  	)
 146  	compactSig := hexToBytes(
 147  		"205978b7896bc71676ba2e459882a8f52e1299449596c4f" +
 148  			"93c59bf1fbfa2f9d3b76ecd0c99406f61a6de2bb5a8937c061c176ecf381d0231e0d" +
 149  			"af73b922c8952c7",
 150  	)
 151  	// blake256 of by{0x01, 0x02, 0x03, 0x04}.
 152  	msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
 153  	// Ensure a valid compact signature is being benchmarked.
 154  	pubKey, wasCompressed, err := RecoverCompact(compactSig, msgHash)
 155  	if err != nil {
 156  		b.Fatalf("unexpected err: %v", err)
 157  	}
 158  	if !wasCompressed {
 159  		b.Fatal("recover claims uncompressed pubkey")
 160  	}
 161  	if !pubKey.IsEqual(wantPubKey) {
 162  		b.Fatal("recover returned unexpected pubkey")
 163  	}
 164  	b.ReportAllocs()
 165  	b.ResetTimer()
 166  	for i := 0; i < b.N; i++ {
 167  		_, _, _ = RecoverCompact(compactSig, msgHash)
 168  	}
 169  }
 170