github.com/m3shine/gochain@v2.2.26+incompatible/crypto/secp256k1/secp256_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package secp256k1
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"crypto/elliptic"
    23  	"crypto/rand"
    24  	"encoding/hex"
    25  	"io"
    26  	"testing"
    27  )
    28  
    29  const TestCount = 1000
    30  
    31  func generateKeyPair() (pubkey, privkey []byte) {
    32  	key, err := ecdsa.GenerateKey(S256(), rand.Reader)
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	pubkey = elliptic.Marshal(S256(), key.X, key.Y)
    37  
    38  	privkey = make([]byte, 32)
    39  	blob := key.D.Bytes()
    40  	copy(privkey[32-len(blob):], blob)
    41  
    42  	return pubkey, privkey
    43  }
    44  
    45  func csprngEntropy(n int) []byte {
    46  	buf := make([]byte, n)
    47  	if _, err := io.ReadFull(rand.Reader, buf); err != nil {
    48  		panic("reading from crypto/rand failed: " + err.Error())
    49  	}
    50  	return buf
    51  }
    52  
    53  func randSig() []byte {
    54  	sig := csprngEntropy(65)
    55  	sig[32] &= 0x70
    56  	sig[64] %= 4
    57  	return sig
    58  }
    59  
    60  // tests for malleability
    61  // highest bit of signature ECDSA s value must be 0, in the 33th byte
    62  func compactSigCheck(t *testing.T, sig []byte) {
    63  	var b int = int(sig[32])
    64  	if b < 0 {
    65  		t.Errorf("highest bit is negative: %d", b)
    66  	}
    67  	if ((b >> 7) == 1) != ((b & 0x80) == 0x80) {
    68  		t.Errorf("highest bit: %d bit >> 7: %d", b, b>>7)
    69  	}
    70  	if (b & 0x80) == 0x80 {
    71  		t.Errorf("highest bit: %d bit & 0x80: %d", b, b&0x80)
    72  	}
    73  }
    74  
    75  func TestSignatureValidity(t *testing.T) {
    76  	pubkey, seckey := generateKeyPair()
    77  	msg := csprngEntropy(32)
    78  	sig, err := Sign(msg, seckey)
    79  	if err != nil {
    80  		t.Errorf("signature error: %s", err)
    81  	}
    82  	compactSigCheck(t, sig)
    83  	if len(pubkey) != 65 {
    84  		t.Errorf("pubkey length mismatch: want: 65 have: %d", len(pubkey))
    85  	}
    86  	if len(seckey) != 32 {
    87  		t.Errorf("seckey length mismatch: want: 32 have: %d", len(seckey))
    88  	}
    89  	if len(sig) != 65 {
    90  		t.Errorf("sig length mismatch: want: 65 have: %d", len(sig))
    91  	}
    92  	recid := int(sig[64])
    93  	if recid > 4 || recid < 0 {
    94  		t.Errorf("sig recid mismatch: want: within 0 to 4 have: %d", int(sig[64]))
    95  	}
    96  }
    97  
    98  func TestInvalidRecoveryID(t *testing.T) {
    99  	_, seckey := generateKeyPair()
   100  	msg := csprngEntropy(32)
   101  	sig, _ := Sign(msg, seckey)
   102  	sig[64] = 99
   103  	_, err := RecoverPubkey(msg, sig)
   104  	if err != ErrInvalidRecoveryID {
   105  		t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID)
   106  	}
   107  }
   108  
   109  func TestSignAndRecover(t *testing.T) {
   110  	pubkey1, seckey := generateKeyPair()
   111  	msg := csprngEntropy(32)
   112  	sig, err := Sign(msg, seckey)
   113  	if err != nil {
   114  		t.Errorf("signature error: %s", err)
   115  	}
   116  	pubkey2, err := RecoverPubkey(msg, sig)
   117  	if err != nil {
   118  		t.Errorf("recover error: %s", err)
   119  	}
   120  	if !bytes.Equal(pubkey1, pubkey2) {
   121  		t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
   122  	}
   123  }
   124  
   125  func TestSignDeterministic(t *testing.T) {
   126  	_, seckey := generateKeyPair()
   127  	msg := make([]byte, 32)
   128  	copy(msg, "hi there")
   129  
   130  	sig1, err := Sign(msg, seckey)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	sig2, err := Sign(msg, seckey)
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  	if !bytes.Equal(sig1, sig2) {
   139  		t.Fatal("signatures not equal")
   140  	}
   141  }
   142  
   143  func TestRandomMessagesWithSameKey(t *testing.T) {
   144  	pubkey, seckey := generateKeyPair()
   145  	keys := func() ([]byte, []byte) {
   146  		return pubkey, seckey
   147  	}
   148  	signAndRecoverWithRandomMessages(t, keys)
   149  }
   150  
   151  func TestRandomMessagesWithRandomKeys(t *testing.T) {
   152  	keys := func() ([]byte, []byte) {
   153  		pubkey, seckey := generateKeyPair()
   154  		return pubkey, seckey
   155  	}
   156  	signAndRecoverWithRandomMessages(t, keys)
   157  }
   158  
   159  func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) {
   160  	for i := 0; i < TestCount; i++ {
   161  		pubkey1, seckey := keys()
   162  		msg := csprngEntropy(32)
   163  		sig, err := Sign(msg, seckey)
   164  		if err != nil {
   165  			t.Fatalf("signature error: %s", err)
   166  		}
   167  		if sig == nil {
   168  			t.Fatal("signature is nil")
   169  		}
   170  		compactSigCheck(t, sig)
   171  
   172  		// TODO: why do we flip around the recovery id?
   173  		sig[len(sig)-1] %= 4
   174  
   175  		pubkey2, err := RecoverPubkey(msg, sig)
   176  		if err != nil {
   177  			t.Fatalf("recover error: %s", err)
   178  		}
   179  		if pubkey2 == nil {
   180  			t.Error("pubkey is nil")
   181  		}
   182  		if !bytes.Equal(pubkey1, pubkey2) {
   183  			t.Fatalf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
   184  		}
   185  	}
   186  }
   187  
   188  func TestRecoveryOfRandomSignature(t *testing.T) {
   189  	pubkey1, _ := generateKeyPair()
   190  	msg := csprngEntropy(32)
   191  
   192  	for i := 0; i < TestCount; i++ {
   193  		// recovery can sometimes work, but if so should always give wrong pubkey
   194  		pubkey2, _ := RecoverPubkey(msg, randSig())
   195  		if bytes.Equal(pubkey1, pubkey2) {
   196  			t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2)
   197  		}
   198  	}
   199  }
   200  
   201  func TestRandomMessagesAgainstValidSig(t *testing.T) {
   202  	pubkey1, seckey := generateKeyPair()
   203  	msg := csprngEntropy(32)
   204  	sig, _ := Sign(msg, seckey)
   205  
   206  	for i := 0; i < TestCount; i++ {
   207  		msg = csprngEntropy(32)
   208  		pubkey2, _ := RecoverPubkey(msg, sig)
   209  		// recovery can sometimes work, but if so should always give wrong pubkey
   210  		if bytes.Equal(pubkey1, pubkey2) {
   211  			t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2)
   212  		}
   213  	}
   214  }
   215  
   216  // Useful when the underlying libsecp256k1 API changes to quickly
   217  // check only recover function without use of signature function
   218  func TestRecoverSanity(t *testing.T) {
   219  	msg, _ := hex.DecodeString("ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008")
   220  	sig, _ := hex.DecodeString("90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301")
   221  	pubkey1, _ := hex.DecodeString("04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652")
   222  	pubkey2, err := RecoverPubkey(msg, sig)
   223  	if err != nil {
   224  		t.Fatalf("recover error: %s", err)
   225  	}
   226  	if !bytes.Equal(pubkey1, pubkey2) {
   227  		t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
   228  	}
   229  }
   230  
   231  func BenchmarkSign(b *testing.B) {
   232  	_, seckey := generateKeyPair()
   233  	msg := csprngEntropy(32)
   234  	b.ResetTimer()
   235  
   236  	for i := 0; i < b.N; i++ {
   237  		Sign(msg, seckey)
   238  	}
   239  }
   240  
   241  func BenchmarkRecover(b *testing.B) {
   242  	msg := csprngEntropy(32)
   243  	_, seckey := generateKeyPair()
   244  	sig, _ := Sign(msg, seckey)
   245  	b.ResetTimer()
   246  
   247  	for i := 0; i < b.N; i++ {
   248  		RecoverPubkey(msg, sig)
   249  	}
   250  }