From a87892e5ab9a9c38c80811dbca0a024526eb9aa7 Mon Sep 17 00:00:00 2001 From: Konstantin Shafransky Date: Fri, 10 Dec 2021 15:52:02 +0300 Subject: [PATCH 1/2] verify implemented --- sign/signed_transaction.go | 40 +++++++++++++++++++++++++++++++++ sign/signed_transaction_test.go | 38 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/sign/signed_transaction.go b/sign/signed_transaction.go index a267f68..4f61b74 100644 --- a/sign/signed_transaction.go +++ b/sign/signed_transaction.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/sha256" "encoding/hex" + "fmt" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcutil" @@ -82,3 +83,42 @@ func (tx *SignedTransaction) Sign(wifs []string, chain *Chain) error { tx.Transaction.Signatures = sigsHex return nil } + +func (tx *SignedTransaction) Verify(chain *Chain, keys [][]byte) (bool, error) { + dig, err := tx.Digest(chain) + if err != nil { + return false, fmt.Errorf("failed to get digest: %w", err) + } + + pubKeysFound := make([]*btcec.PublicKey, 0, len(tx.Signatures)) + for _, signature := range tx.Signatures { + sig, err := hex.DecodeString(signature) + if err != nil { + return false, fmt.Errorf("failed to decode signature: %w", err) + } + + p, _, err := btcec.RecoverCompact(btcec.S256(), sig, dig) + if err != nil { + return false, fmt.Errorf("failed to RecoverCompact: %w", err) + } + + pubKeysFound = append(pubKeysFound, p) + } + +find: + for _, pub := range pubKeysFound { + for _, v := range keys { + pb, err := btcec.ParsePubKey(v, btcec.S256()) + if err != nil { + return false, fmt.Errorf("failed to parse pub key: %w", err) + } + + if pub.IsEqual(pb) { + continue find + } + } + return false, nil + } + + return true, nil +} diff --git a/sign/signed_transaction_test.go b/sign/signed_transaction_test.go index 84d48a7..db71660 100644 --- a/sign/signed_transaction_test.go +++ b/sign/signed_transaction_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/btcsuite/btcutil" "github.com/scorum/scorum-go/types" "github.com/stretchr/testify/require" ) @@ -35,3 +36,40 @@ func TestTransaction_Digest(t *testing.T) { require.NoError(t, err) require.Equal(t, expected, hex.EncodeToString(digest)) } + +func TestTransaction_Verify(t *testing.T) { + var tx *types.Transaction + // Prepare the transaction. + expiration := time.Date(2016, 8, 8, 12, 24, 17, 0, time.UTC) + tx = &types.Transaction{ + RefBlockNum: 36029, + RefBlockPrefix: 1164960351, + Expiration: &types.Time{&expiration}, + } + tx.PushOperation(&types.VoteOperation{ + Voter: "xeroc", + Author: "xeroc", + Permlink: "piston", + Weight: 10000, + }) + + var initChain = &Chain{ + ID: "0000000000000000000000000000000000000000000000000000000000000000", + } + + expectedDigest := "582176b1daf89984bc8b4fdcb24ff1433d1eb114a8c4bf20fb22ad580d035889" + stx := NewSignedTransaction(tx) + digest, err := stx.Digest(initChain) + require.NoError(t, err) + require.Equal(t, expectedDigest, hex.EncodeToString(digest)) + + wif := "5HzA7Eju6BQcunCHNy5ywGG2YriZMQaEcoPEbQFpSRk9NZEo6Fv" + require.NoError(t, stx.Sign([]string{wif}, initChain)) + + btcecWif, err := btcutil.DecodeWIF(wif) + require.NoError(t, err) + + res, err := stx.Verify(initChain, [][]byte{btcecWif.PrivKey.PubKey().SerializeUncompressed()}) + require.NoError(t, err) + require.True(t, res) +} From a3fa21cc4ae97a6650cdf4d96f0a919a504dc593 Mon Sep 17 00:00:00 2001 From: Konstantin Shafransky Date: Fri, 10 Dec 2021 17:25:35 +0300 Subject: [PATCH 2/2] proper test on real rx from testnet --- sign/signed_transaction_test.go | 61 +++++++++++++++++---------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/sign/signed_transaction_test.go b/sign/signed_transaction_test.go index db71660..c894eb6 100644 --- a/sign/signed_transaction_test.go +++ b/sign/signed_transaction_test.go @@ -2,10 +2,11 @@ package sign import ( "encoding/hex" + "encoding/json" "testing" "time" - "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/base58" "github.com/scorum/scorum-go/types" "github.com/stretchr/testify/require" ) @@ -38,38 +39,38 @@ func TestTransaction_Digest(t *testing.T) { } func TestTransaction_Verify(t *testing.T) { - var tx *types.Transaction - // Prepare the transaction. - expiration := time.Date(2016, 8, 8, 12, 24, 17, 0, time.UTC) - tx = &types.Transaction{ - RefBlockNum: 36029, - RefBlockPrefix: 1164960351, - Expiration: &types.Time{&expiration}, - } - tx.PushOperation(&types.VoteOperation{ - Voter: "xeroc", - Author: "xeroc", - Permlink: "piston", - Weight: 10000, - }) + txStr := ` + { + "ref_block_num": 57753, + "ref_block_prefix": 1882698764, + "expiration": "2021-12-01T17:26:00", + "operations": [ + [ + "transfer", + { + "from": "azucena", + "to": "leonarda", + "amount": "0.000009000 SCR", + "memo": "{\"bet_id\":\"8b022219-3825-413e-a6ae-1cc3154bdb7f\",\"game_id\":\"17ff54ad-8472-4e4f-9e96-2b6ccbfaef33\"}" + } + ] + ], + "extensions": [], + "signatures": [ + "204da1d0e0c5cb39978d1ad4fe4cd4446718ad0e10a19d662ac7bc9e0bba708f2c2116279fdc512d03fe2c97cdfc00804a4b958a8078f9b3b28e4f4b22f798f032" + ], + "transaction_id": "825d2733272648f95c21ae97be9f8c3d8edaf8f9", + "block_num": 31449514, + "transaction_num": 0 + }` - var initChain = &Chain{ - ID: "0000000000000000000000000000000000000000000000000000000000000000", - } + var tx types.Transaction + err := json.Unmarshal([]byte(txStr), &tx) + stx := NewSignedTransaction(&tx) - expectedDigest := "582176b1daf89984bc8b4fdcb24ff1433d1eb114a8c4bf20fb22ad580d035889" - stx := NewSignedTransaction(tx) - digest, err := stx.Digest(initChain) - require.NoError(t, err) - require.Equal(t, expectedDigest, hex.EncodeToString(digest)) - - wif := "5HzA7Eju6BQcunCHNy5ywGG2YriZMQaEcoPEbQFpSRk9NZEo6Fv" - require.NoError(t, stx.Sign([]string{wif}, initChain)) - - btcecWif, err := btcutil.DecodeWIF(wif) - require.NoError(t, err) + keyWithChecksum := base58.Decode("7cTf2Dx9rxffs6E2z2pdn5cLMneo3AAFSsF9g4SaVviCYdfQ63") - res, err := stx.Verify(initChain, [][]byte{btcecWif.PrivKey.PubKey().SerializeUncompressed()}) + res, err := stx.Verify(TestChain, [][]byte{keyWithChecksum[:len(keyWithChecksum)-4]}) require.NoError(t, err) require.True(t, res) }