github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/crypto/secp256k1/secp256_test.go (about)

     1  package secp256k1
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	"crypto/rand"
     8  	"encoding/hex"
     9  	"testing"
    10  
    11  	"github.com/quickchainproject/quickchain/common/math"
    12  	"github.com/quickchainproject/quickchain/crypto/randentropy"
    13  )
    14  
    15  const TestCount = 1000
    16  
    17  func generateKeyPair() (pubkey, privkey []byte) {
    18  	key, err := ecdsa.GenerateKey(S256(), rand.Reader)
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  	pubkey = elliptic.Marshal(S256(), key.X, key.Y)
    23  	return pubkey, math.PaddedBigBytes(key.D, 32)
    24  }
    25  
    26  func randSig() []byte {
    27  	sig := randentropy.GetEntropyCSPRNG(65)
    28  	sig[32] &= 0x70
    29  	sig[64] %= 4
    30  	return sig
    31  }
    32  
    33  // tests for malleability
    34  // highest bit of signature ECDSA s value must be 0, in the 33th byte
    35  func compactSigCheck(t *testing.T, sig []byte) {
    36  	var b int = int(sig[32])
    37  	if b < 0 {
    38  		t.Errorf("highest bit is negative: %d", b)
    39  	}
    40  	if ((b >> 7) == 1) != ((b & 0x80) == 0x80) {
    41  		t.Errorf("highest bit: %d bit >> 7: %d", b, b>>7)
    42  	}
    43  	if (b & 0x80) == 0x80 {
    44  		t.Errorf("highest bit: %d bit & 0x80: %d", b, b&0x80)
    45  	}
    46  }
    47  
    48  func TestSignatureValidity(t *testing.T) {
    49  	pubkey, seckey := generateKeyPair()
    50  	msg := randentropy.GetEntropyCSPRNG(32)
    51  	sig, err := Sign(msg, seckey)
    52  	if err != nil {
    53  		t.Errorf("signature error: %s", err)
    54  	}
    55  	compactSigCheck(t, sig)
    56  	if len(pubkey) != 65 {
    57  		t.Errorf("pubkey length mismatch: want: 65 have: %d", len(pubkey))
    58  	}
    59  	if len(seckey) != 32 {
    60  		t.Errorf("seckey length mismatch: want: 32 have: %d", len(seckey))
    61  	}
    62  	if len(sig) != 65 {
    63  		t.Errorf("sig length mismatch: want: 65 have: %d", len(sig))
    64  	}
    65  	recid := int(sig[64])
    66  	if recid > 4 || recid < 0 {
    67  		t.Errorf("sig recid mismatch: want: within 0 to 4 have: %d", int(sig[64]))
    68  	}
    69  }
    70  
    71  func TestInvalidRecoveryID(t *testing.T) {
    72  	_, seckey := generateKeyPair()
    73  	msg := randentropy.GetEntropyCSPRNG(32)
    74  	sig, _ := Sign(msg, seckey)
    75  	sig[64] = 99
    76  	_, err := RecoverPubkey(msg, sig)
    77  	if err != ErrInvalidRecoveryID {
    78  		t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID)
    79  	}
    80  }
    81  
    82  func TestSignAndRecover(t *testing.T) {
    83  	pubkey1, seckey := generateKeyPair()
    84  	msg := randentropy.GetEntropyCSPRNG(32)
    85  	sig, err := Sign(msg, seckey)
    86  	if err != nil {
    87  		t.Errorf("signature error: %s", err)
    88  	}
    89  	pubkey2, err := RecoverPubkey(msg, sig)
    90  	if err != nil {
    91  		t.Errorf("recover error: %s", err)
    92  	}
    93  	if !bytes.Equal(pubkey1, pubkey2) {
    94  		t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
    95  	}
    96  }
    97  
    98  func TestSignDeterministic(t *testing.T) {
    99  	_, seckey := generateKeyPair()
   100  	msg := make([]byte, 32)
   101  	copy(msg, "hi there")
   102  
   103  	sig1, err := Sign(msg, seckey)
   104  	if err != nil {
   105  		t.Fatal(err)
   106  	}
   107  	sig2, err := Sign(msg, seckey)
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	if !bytes.Equal(sig1, sig2) {
   112  		t.Fatal("signatures not equal")
   113  	}
   114  }
   115  
   116  func TestRandomMessagesWithSameKey(t *testing.T) {
   117  	pubkey, seckey := generateKeyPair()
   118  	keys := func() ([]byte, []byte) {
   119  		return pubkey, seckey
   120  	}
   121  	signAndRecoverWithRandomMessages(t, keys)
   122  }
   123  
   124  func TestRandomMessagesWithRandomKeys(t *testing.T) {
   125  	keys := func() ([]byte, []byte) {
   126  		pubkey, seckey := generateKeyPair()
   127  		return pubkey, seckey
   128  	}
   129  	signAndRecoverWithRandomMessages(t, keys)
   130  }
   131  
   132  func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) {
   133  	for i := 0; i < TestCount; i++ {
   134  		pubkey1, seckey := keys()
   135  		msg := randentropy.GetEntropyCSPRNG(32)
   136  		sig, err := Sign(msg, seckey)
   137  		if err != nil {
   138  			t.Fatalf("signature error: %s", err)
   139  		}
   140  		if sig == nil {
   141  			t.Fatal("signature is nil")
   142  		}
   143  		compactSigCheck(t, sig)
   144  
   145  		// TODO: why do we flip around the recovery id?
   146  		sig[len(sig)-1] %= 4
   147  
   148  		pubkey2, err := RecoverPubkey(msg, sig)
   149  		if err != nil {
   150  			t.Fatalf("recover error: %s", err)
   151  		}
   152  		if pubkey2 == nil {
   153  			t.Error("pubkey is nil")
   154  		}
   155  		if !bytes.Equal(pubkey1, pubkey2) {
   156  			t.Fatalf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
   157  		}
   158  	}
   159  }
   160  
   161  func TestRecoveryOfRandomSignature(t *testing.T) {
   162  	pubkey1, _ := generateKeyPair()
   163  	msg := randentropy.GetEntropyCSPRNG(32)
   164  
   165  	for i := 0; i < TestCount; i++ {
   166  		// recovery can sometimes work, but if so should always give wrong pubkey
   167  		pubkey2, _ := RecoverPubkey(msg, randSig())
   168  		if bytes.Equal(pubkey1, pubkey2) {
   169  			t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2)
   170  		}
   171  	}
   172  }
   173  
   174  func TestRandomMessagesAgainstValidSig(t *testing.T) {
   175  	pubkey1, seckey := generateKeyPair()
   176  	msg := randentropy.GetEntropyCSPRNG(32)
   177  	sig, _ := Sign(msg, seckey)
   178  
   179  	for i := 0; i < TestCount; i++ {
   180  		msg = randentropy.GetEntropyCSPRNG(32)
   181  		pubkey2, _ := RecoverPubkey(msg, sig)
   182  		// recovery can sometimes work, but if so should always give wrong pubkey
   183  		if bytes.Equal(pubkey1, pubkey2) {
   184  			t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2)
   185  		}
   186  	}
   187  }
   188  
   189  // Useful when the underlying libsecp256k1 API changes to quickly
   190  // check only recover function without use of signature function
   191  func TestRecoverSanity(t *testing.T) {
   192  	msg, _ := hex.DecodeString("ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008")
   193  	sig, _ := hex.DecodeString("90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301")
   194  	pubkey1, _ := hex.DecodeString("04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652")
   195  	pubkey2, err := RecoverPubkey(msg, sig)
   196  	if err != nil {
   197  		t.Fatalf("recover error: %s", err)
   198  	}
   199  	if !bytes.Equal(pubkey1, pubkey2) {
   200  		t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
   201  	}
   202  }
   203  
   204  func BenchmarkSign(b *testing.B) {
   205  	_, seckey := generateKeyPair()
   206  	msg := randentropy.GetEntropyCSPRNG(32)
   207  	b.ResetTimer()
   208  
   209  	for i := 0; i < b.N; i++ {
   210  		Sign(msg, seckey)
   211  	}
   212  }
   213  
   214  func BenchmarkRecover(b *testing.B) {
   215  	msg := randentropy.GetEntropyCSPRNG(32)
   216  	_, seckey := generateKeyPair()
   217  	sig, _ := Sign(msg, seckey)
   218  	b.ResetTimer()
   219  
   220  	for i := 0; i < b.N; i++ {
   221  		RecoverPubkey(msg, sig)
   222  	}
   223  }