bench_test.go raw

   1  // Copyright 2013-2016 The btcsuite developers
   2  // Use of this source code is governed by an ISC
   3  // license that can be found in the LICENSE file.
   4  
   5  package btcec
   6  
   7  import (
   8  	"math/big"
   9  	"testing"
  10  
  11  	"next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
  12  	"next.orly.dev/pkg/nostr/encoders/hex"
  13  )
  14  
  15  // setHex decodes the passed big-endian hex string into the internal field value
  16  // representation.  Only the first 32-bytes are used.
  17  //
  18  // This is NOT constant time.
  19  //
  20  // The field value is returned to support chaining.  This enables syntax like:
  21  // f := new(FieldVal).SetHex("0abc").Add(1) so that f = 0x0abc + 1
  22  func setHex(hexString string) *FieldVal {
  23  	if len(hexString)%2 != 0 {
  24  		hexString = "0" + hexString
  25  	}
  26  	bytes, _ := hex.Dec(hexString)
  27  	var f FieldVal
  28  	f.SetByteSlice(bytes)
  29  	return &f
  30  }
  31  
  32  // hexToFieldVal converts the passed hex string into a FieldVal and will panic
  33  // if there is an error.  This is only provided for the hard-coded constants so
  34  // errors in the source code can be detected. It will only (and must only) be
  35  // called with hard-coded values.
  36  func hexToFieldVal(s string) *FieldVal {
  37  	b, err := hex.Dec(s)
  38  	if err != nil {
  39  		panic("invalid hex in source file: " + s)
  40  	}
  41  	var f FieldVal
  42  	if overflow := f.SetByteSlice(b); overflow {
  43  		panic("hex in source file overflows mod P: " + s)
  44  	}
  45  	return &f
  46  }
  47  
  48  // fromHex converts the passed hex string into a big integer pointer and will
  49  // panic is there is an error.  This is only provided for the hard-coded
  50  // constants so errors in the source code can bet detected. It will only (and
  51  // must only) be called for initialization purposes.
  52  func fromHex(s string) *big.Int {
  53  	if s == "" {
  54  		return big.NewInt(0)
  55  	}
  56  	r, ok := new(big.Int).SetString(s, 16)
  57  	if !ok {
  58  		panic("invalid hex in source file: " + s)
  59  	}
  60  	return r
  61  }
  62  
  63  // jacobianPointFromHex decodes the passed big-endian hex strings into a
  64  // Jacobian point with its internal fields set to the resulting values.  Only
  65  // the first 32-bytes are used.
  66  func jacobianPointFromHex(x, y, z string) JacobianPoint {
  67  	var p JacobianPoint
  68  	p.X = *setHex(x)
  69  	p.Y = *setHex(y)
  70  	p.Z = *setHex(z)
  71  	return p
  72  }
  73  
  74  // BenchmarkAddNonConst benchmarks the secp256k1 curve AddNonConst function with
  75  // Z values of 1 so that the associated optimizations are used.
  76  func BenchmarkAddJacobian(b *testing.B) {
  77  	p1 := jacobianPointFromHex(
  78  		"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
  79  		"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
  80  		"1",
  81  	)
  82  	p2 := jacobianPointFromHex(
  83  		"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
  84  		"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
  85  		"1",
  86  	)
  87  	b.ReportAllocs()
  88  	b.ResetTimer()
  89  	var result JacobianPoint
  90  	for i := 0; i < b.N; i++ {
  91  		secp256k1.AddNonConst(&p1, &p2, &result)
  92  	}
  93  }
  94  
  95  // BenchmarkAddNonConstNotZOne benchmarks the secp256k1 curve AddNonConst
  96  // function with Z values other than one so the optimizations associated with
  97  // Z=1 aren't used.
  98  func BenchmarkAddJacobianNotZOne(b *testing.B) {
  99  	x1 := setHex("d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718")
 100  	y1 := setHex("5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190")
 101  	z1 := setHex("2")
 102  	x2 := setHex("91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4")
 103  	y2 := setHex("03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1")
 104  	z2 := setHex("3")
 105  	p1 := MakeJacobianPoint(x1, y1, z1)
 106  	p2 := MakeJacobianPoint(x2, y2, z2)
 107  	b.ReportAllocs()
 108  	b.ResetTimer()
 109  	var result JacobianPoint
 110  	for i := 0; i < b.N; i++ {
 111  		AddNonConst(&p1, &p2, &result)
 112  	}
 113  }
 114  
 115  // BenchmarkScalarBaseMult benchmarks the secp256k1 curve ScalarBaseMult
 116  // function.
 117  func BenchmarkScalarBaseMult(b *testing.B) {
 118  	k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
 119  	curve := S256()
 120  	for i := 0; i < b.N; i++ {
 121  		curve.ScalarBaseMult(k.Bytes())
 122  	}
 123  }
 124  
 125  // BenchmarkScalarBaseMultLarge benchmarks the secp256k1 curve ScalarBaseMult
 126  // function with abnormally large k values.
 127  func BenchmarkScalarBaseMultLarge(b *testing.B) {
 128  	k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c005751111111011111110")
 129  	curve := S256()
 130  	for i := 0; i < b.N; i++ {
 131  		curve.ScalarBaseMult(k.Bytes())
 132  	}
 133  }
 134  
 135  // BenchmarkScalarMult benchmarks the secp256k1 curve ScalarMult function.
 136  func BenchmarkScalarMult(b *testing.B) {
 137  	x := fromHex("34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6")
 138  	y := fromHex("0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232")
 139  	k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
 140  	curve := S256()
 141  	for i := 0; i < b.N; i++ {
 142  		curve.ScalarMult(x, y, k.Bytes())
 143  	}
 144  }
 145  
 146  // hexToModNScalar converts the passed hex string into a ModNScalar and will
 147  // panic if there is an error.  This is only provided for the hard-coded
 148  // constants so errors in the source code can be detected. It will only (and
 149  // must only) be called with hard-coded values.
 150  func hexToModNScalar(s string) *ModNScalar {
 151  	b, err := hex.Dec(s)
 152  	if err != nil {
 153  		panic("invalid hex in source file: " + s)
 154  	}
 155  	var scalar ModNScalar
 156  	if overflow := scalar.SetByteSlice(b); overflow {
 157  		panic("hex in source file overflows mod N scalar: " + s)
 158  	}
 159  	return &scalar
 160  }
 161  
 162  // BenchmarkFieldNormalize benchmarks how long it takes the internal field
 163  // to perform normalization (which includes modular reduction).
 164  func BenchmarkFieldNormalize(b *testing.B) {
 165  	// The normalize function is constant time so default value is fine.
 166  	var f FieldVal
 167  	for i := 0; i < b.N; i++ {
 168  		f.Normalize()
 169  	}
 170  }
 171  
 172  // BenchmarkParseCompressedPubKey benchmarks how long it takes to decompress and
 173  // validate a compressed public key from a byte array.
 174  func BenchmarkParseCompressedPubKey(b *testing.B) {
 175  	rawPk, _ := hex.Dec("0234f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6")
 176  
 177  	var (
 178  		pk  *PublicKey
 179  		err error
 180  	)
 181  	b.ReportAllocs()
 182  	b.ResetTimer()
 183  	for i := 0; i < b.N; i++ {
 184  		pk, err = ParsePubKey(rawPk)
 185  	}
 186  	_ = pk
 187  	_ = err
 188  }
 189