github.com/Finschia/finschia-sdk@v0.48.1/crypto/keys/secp256k1/secp256k1_test.go (about)

     1  package secp256k1_test
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/base64"
     6  	"encoding/hex"
     7  	"math/big"
     8  	"testing"
     9  
    10  	btcSecp256k1 "github.com/btcsuite/btcd/btcec"
    11  	"github.com/cosmos/btcutil/base58"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/Finschia/ostracon/crypto"
    16  	ostsecp256k1 "github.com/Finschia/ostracon/crypto/secp256k1"
    17  
    18  	"github.com/Finschia/finschia-sdk/codec"
    19  	"github.com/Finschia/finschia-sdk/crypto/keys/ed25519"
    20  	"github.com/Finschia/finschia-sdk/crypto/keys/secp256k1"
    21  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    22  )
    23  
    24  type keyData struct {
    25  	priv string
    26  	pub  string
    27  	addr string
    28  }
    29  
    30  var secpDataTable = []keyData{
    31  	{
    32  		priv: "a96e62ed3955e65be32703f12d87b6b5cf26039ecfa948dc5107a495418e5330",
    33  		pub:  "02950e1cdfcb133d6024109fd489f734eeb4502418e538c28481f22bce276f248c",
    34  		addr: "1CKZ9Nx4zgds8tU7nJHotKSDr4a9bYJCa3",
    35  	},
    36  }
    37  
    38  func TestPubKeySecp256k1Address(t *testing.T) {
    39  	for _, d := range secpDataTable {
    40  		privB, _ := hex.DecodeString(d.priv)
    41  		pubB, _ := hex.DecodeString(d.pub)
    42  		addrBbz, _, _ := base58.CheckDecode(d.addr)
    43  		addrB := crypto.Address(addrBbz)
    44  
    45  		priv := secp256k1.PrivKey{Key: privB}
    46  
    47  		pubKey := priv.PubKey()
    48  		pubT, _ := pubKey.(*secp256k1.PubKey)
    49  
    50  		addr := pubKey.Address()
    51  		assert.Equal(t, pubT, &secp256k1.PubKey{Key: pubB}, "Expected pub keys to match")
    52  		assert.Equal(t, addr, addrB, "Expected addresses to match")
    53  	}
    54  }
    55  
    56  func TestSignAndValidateSecp256k1(t *testing.T) {
    57  	privKey := secp256k1.GenPrivKey()
    58  	pubKey := privKey.PubKey()
    59  
    60  	msg := crypto.CRandBytes(1000)
    61  	sig, err := privKey.Sign(msg)
    62  	require.Nil(t, err)
    63  	assert.True(t, pubKey.VerifySignature(msg, sig))
    64  
    65  	// ----
    66  	// Test cross packages verification
    67  	msgHash := crypto.Sha256(msg)
    68  	btcPrivKey, btcPubKey := btcSecp256k1.PrivKeyFromBytes(btcSecp256k1.S256(), privKey.Key)
    69  	// This fails: malformed signature: no header magic
    70  	//   btcSig, err := secp256k1.ParseSignature(sig, secp256k1.S256())
    71  	//   require.NoError(t, err)
    72  	//   assert.True(t, btcSig.Verify(msgHash, btcPubKey))
    73  	// So we do a hacky way:
    74  	r := new(big.Int)
    75  	s := new(big.Int)
    76  	r.SetBytes(sig[:32])
    77  	s.SetBytes(sig[32:])
    78  	ok := ecdsa.Verify(btcPubKey.ToECDSA(), msgHash, r, s)
    79  	require.True(t, ok)
    80  
    81  	sig2, err := btcPrivKey.Sign(msgHash)
    82  	require.NoError(t, err)
    83  	pubKey.VerifySignature(msg, sig2.Serialize())
    84  
    85  	// ----
    86  	// Mutate the signature, just one bit.
    87  	sig[3] ^= byte(0x01)
    88  	assert.False(t, pubKey.VerifySignature(msg, sig))
    89  }
    90  
    91  // This test is intended to justify the removal of calls to the underlying library
    92  // in creating the privkey.
    93  func TestSecp256k1LoadPrivkeyAndSerializeIsIdentity(t *testing.T) {
    94  	numberOfTests := 256
    95  	for i := 0; i < numberOfTests; i++ {
    96  		// Seed the test case with some random bytes
    97  		privKeyBytes := [32]byte{}
    98  		copy(privKeyBytes[:], crypto.CRandBytes(32))
    99  
   100  		// This function creates a private and public key in the underlying libraries format.
   101  		// The private key is basically calling new(big.Int).SetBytes(pk), which removes leading zero bytes
   102  		priv, _ := btcSecp256k1.PrivKeyFromBytes(btcSecp256k1.S256(), privKeyBytes[:])
   103  		// this takes the bytes returned by `(big int).Bytes()`, and if the length is less than 32 bytes,
   104  		// pads the bytes from the left with zero bytes. Therefore these two functions composed
   105  		// result in the identity function on privKeyBytes, hence the following equality check
   106  		// always returning true.
   107  		serializedBytes := priv.Serialize()
   108  		require.Equal(t, privKeyBytes[:], serializedBytes)
   109  	}
   110  }
   111  
   112  func TestGenPrivKeyFromSecret(t *testing.T) {
   113  	// curve oder N
   114  	N := btcSecp256k1.S256().N
   115  	tests := []struct {
   116  		name   string
   117  		secret []byte
   118  	}{
   119  		{"empty secret", []byte{}},
   120  		{
   121  			"some long secret",
   122  			[]byte("We live in a society exquisitely dependent on science and technology, " +
   123  				"in which hardly anyone knows anything about science and technology."),
   124  		},
   125  		{"another seed used in cosmos tests #1", []byte{0}},
   126  		{"another seed used in cosmos tests #2", []byte("mySecret")},
   127  		{"another seed used in cosmos tests #3", []byte("")},
   128  	}
   129  	for _, tt := range tests {
   130  		tt := tt
   131  		t.Run(tt.name, func(t *testing.T) {
   132  			gotPrivKey := secp256k1.GenPrivKeyFromSecret(tt.secret)
   133  			require.NotNil(t, gotPrivKey)
   134  			// interpret as a big.Int and make sure it is a valid field element:
   135  			fe := new(big.Int).SetBytes(gotPrivKey.Key[:])
   136  			require.True(t, fe.Cmp(N) < 0)
   137  			require.True(t, fe.Sign() > 0)
   138  		})
   139  	}
   140  }
   141  
   142  func TestPubKeyEquals(t *testing.T) {
   143  	secp256K1PubKey := secp256k1.GenPrivKey().PubKey().(*secp256k1.PubKey)
   144  
   145  	testCases := []struct {
   146  		msg      string
   147  		pubKey   cryptotypes.PubKey
   148  		other    cryptotypes.PubKey
   149  		expectEq bool
   150  	}{
   151  		{
   152  			"different bytes",
   153  			secp256K1PubKey,
   154  			secp256k1.GenPrivKey().PubKey(),
   155  			false,
   156  		},
   157  		{
   158  			"equals",
   159  			secp256K1PubKey,
   160  			&secp256k1.PubKey{
   161  				Key: secp256K1PubKey.Key,
   162  			},
   163  			true,
   164  		},
   165  		{
   166  			"different types",
   167  			secp256K1PubKey,
   168  			ed25519.GenPrivKey().PubKey(),
   169  			false,
   170  		},
   171  	}
   172  
   173  	for _, tc := range testCases {
   174  		t.Run(tc.msg, func(t *testing.T) {
   175  			eq := tc.pubKey.Equals(tc.other)
   176  			require.Equal(t, eq, tc.expectEq)
   177  		})
   178  	}
   179  }
   180  
   181  func TestPrivKeyEquals(t *testing.T) {
   182  	secp256K1PrivKey := secp256k1.GenPrivKey()
   183  
   184  	testCases := []struct {
   185  		msg      string
   186  		privKey  cryptotypes.PrivKey
   187  		other    cryptotypes.PrivKey
   188  		expectEq bool
   189  	}{
   190  		{
   191  			"different bytes",
   192  			secp256K1PrivKey,
   193  			secp256k1.GenPrivKey(),
   194  			false,
   195  		},
   196  		{
   197  			"equals",
   198  			secp256K1PrivKey,
   199  			&secp256k1.PrivKey{
   200  				Key: secp256K1PrivKey.Key,
   201  			},
   202  			true,
   203  		},
   204  		{
   205  			"different types",
   206  			secp256K1PrivKey,
   207  			ed25519.GenPrivKey(),
   208  			false,
   209  		},
   210  	}
   211  
   212  	for _, tc := range testCases {
   213  		t.Run(tc.msg, func(t *testing.T) {
   214  			eq := tc.privKey.Equals(tc.other)
   215  			require.Equal(t, eq, tc.expectEq)
   216  		})
   217  	}
   218  }
   219  
   220  func TestMarshalAmino(t *testing.T) {
   221  	aminoCdc := codec.NewLegacyAmino()
   222  	privKey := secp256k1.GenPrivKey()
   223  	pubKey := privKey.PubKey().(*secp256k1.PubKey)
   224  
   225  	testCases := []struct {
   226  		desc      string
   227  		msg       codec.AminoMarshaler
   228  		typ       interface{}
   229  		expBinary []byte
   230  		expJSON   string
   231  	}{
   232  		{
   233  			"secp256k1 private key",
   234  			privKey,
   235  			&secp256k1.PrivKey{},
   236  			append([]byte{32}, privKey.Bytes()...), // Length-prefixed.
   237  			"\"" + base64.StdEncoding.EncodeToString(privKey.Bytes()) + "\"",
   238  		},
   239  		{
   240  			"secp256k1 public key",
   241  			pubKey,
   242  			&secp256k1.PubKey{},
   243  			append([]byte{33}, pubKey.Bytes()...), // Length-prefixed.
   244  			"\"" + base64.StdEncoding.EncodeToString(pubKey.Bytes()) + "\"",
   245  		},
   246  	}
   247  
   248  	for _, tc := range testCases {
   249  		t.Run(tc.desc, func(t *testing.T) {
   250  			// Do a round trip of encoding/decoding binary.
   251  			bz, err := aminoCdc.Marshal(tc.msg)
   252  			require.NoError(t, err)
   253  			require.Equal(t, tc.expBinary, bz)
   254  
   255  			err = aminoCdc.Unmarshal(bz, tc.typ)
   256  			require.NoError(t, err)
   257  
   258  			require.Equal(t, tc.msg, tc.typ)
   259  
   260  			// Do a round trip of encoding/decoding JSON.
   261  			bz, err = aminoCdc.MarshalJSON(tc.msg)
   262  			require.NoError(t, err)
   263  			require.Equal(t, tc.expJSON, string(bz))
   264  
   265  			err = aminoCdc.UnmarshalJSON(bz, tc.typ)
   266  			require.NoError(t, err)
   267  
   268  			require.Equal(t, tc.msg, tc.typ)
   269  		})
   270  	}
   271  }
   272  
   273  func TestMarshalAmino_BackwardsCompatibility(t *testing.T) {
   274  	aminoCdc := codec.NewLegacyAmino()
   275  	// Create Tendermint keys.
   276  	ostPrivKey := ostsecp256k1.GenPrivKey()
   277  	ostPubKey := ostPrivKey.PubKey()
   278  	// Create our own keys, with the same private key as Tendermint's.
   279  	privKey := &secp256k1.PrivKey{Key: []byte(ostPrivKey)}
   280  	pubKey := privKey.PubKey().(*secp256k1.PubKey)
   281  
   282  	testCases := []struct {
   283  		desc      string
   284  		ostKey    interface{}
   285  		ourKey    interface{}
   286  		marshalFn func(o interface{}) ([]byte, error)
   287  	}{
   288  		{
   289  			"secp256k1 private key, binary",
   290  			ostPrivKey,
   291  			privKey,
   292  			aminoCdc.Marshal,
   293  		},
   294  		{
   295  			"secp256k1 private key, JSON",
   296  			ostPrivKey,
   297  			privKey,
   298  			aminoCdc.MarshalJSON,
   299  		},
   300  		{
   301  			"secp256k1 public key, binary",
   302  			ostPubKey,
   303  			pubKey,
   304  			aminoCdc.Marshal,
   305  		},
   306  		{
   307  			"secp256k1 public key, JSON",
   308  			ostPubKey,
   309  			pubKey,
   310  			aminoCdc.MarshalJSON,
   311  		},
   312  	}
   313  
   314  	for _, tc := range testCases {
   315  		t.Run(tc.desc, func(t *testing.T) {
   316  			// Make sure Amino encoding override is not breaking backwards compatibility.
   317  			bz1, err := tc.marshalFn(tc.ostKey)
   318  			require.NoError(t, err)
   319  			bz2, err := tc.marshalFn(tc.ourKey)
   320  			require.NoError(t, err)
   321  			require.Equal(t, bz1, bz2)
   322  		})
   323  	}
   324  }