github.com/codingfuture/orig-energi3@v0.8.4/crypto/secp256k1/secp256_test.go (about)

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