From ae3515e81932da0d24803bd24078bf5e39e9efa1 Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Tue, 9 Apr 2024 12:13:43 +0300 Subject: [PATCH] crypto: add StringCompressed() for PublicKey Add StringCompressed to get a string representation of the key in compressed form. Close #3263 Signed-off-by: Ekaterina Pavlova --- cli/cmdargs/parser_test.go | 3 +- cli/query/query.go | 7 ++-- cli/smartcontract/permission.go | 4 +- cli/smartcontract/smart_contract_test.go | 5 +-- cli/wallet/candidate_test.go | 3 +- cli/wallet/multisig_test.go | 7 ++-- cli/wallet/wallet_test.go | 51 +++++++++++------------ internal/basicchain/basic.go | 2 +- pkg/config/protocol_config_test.go | 7 ++-- pkg/crypto/keys/publickey.go | 10 ++++- pkg/crypto/keys/publickey_test.go | 2 +- pkg/neotest/chain/chain.go | 12 +++--- pkg/services/oracle/response.go | 3 +- pkg/smartcontract/context/context_test.go | 3 +- pkg/smartcontract/context/item.go | 6 +-- pkg/smartcontract/context/item_test.go | 5 +-- pkg/smartcontract/manifest/group.go | 2 +- pkg/smartcontract/manifest/permission.go | 3 +- pkg/wallet/account_test.go | 3 +- 19 files changed, 64 insertions(+), 74 deletions(-) diff --git a/cli/cmdargs/parser_test.go b/cli/cmdargs/parser_test.go index c27df62f2..f3d8521fc 100644 --- a/cli/cmdargs/parser_test.go +++ b/cli/cmdargs/parser_test.go @@ -1,7 +1,6 @@ package cmdargs import ( - "encoding/hex" "strings" "testing" @@ -45,7 +44,7 @@ func TestParseCosigner(t *testing.T) { Scopes: transaction.CalledByEntry | transaction.CustomContracts, AllowedContracts: []util.Uint160{c1, c2}, }, - acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): { + acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): { Account: acc, Scopes: transaction.CustomGroups, AllowedGroups: keys.PublicKeys{priv.PublicKey()}, diff --git a/cli/query/query.go b/cli/query/query.go index 4b909b088..5a63ebf32 100644 --- a/cli/query/query.go +++ b/cli/query/query.go @@ -3,7 +3,6 @@ package query import ( "bytes" "encoding/base64" - "encoding/hex" "fmt" "sort" "strconv" @@ -204,7 +203,7 @@ func queryCandidates(ctx *cli.Context) error { var res []byte res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n") for _, val := range vals { - res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active) + res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", val.PublicKey.StringCompressed(), val.Votes, comm.Contains(&val.PublicKey), val.Active) } tw := tabwriter.NewWriter(ctx.App.Writer, 0, 2, 2, ' ', 0) _, err = tw.Write(res) @@ -235,7 +234,7 @@ func queryCommittee(ctx *cli.Context) error { } for _, k := range comm { - fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes())) + fmt.Fprintln(ctx.App.Writer, k.StringCompressed()) } return nil } @@ -306,7 +305,7 @@ func queryVoter(ctx *cli.Context) error { } voted := "null" if st.VoteTo != nil { - voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash())) + voted = fmt.Sprintf("%s (%s)", st.VoteTo.StringCompressed(), address.Uint160ToString(st.VoteTo.GetScriptHash())) } fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted) fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec))) diff --git a/cli/smartcontract/permission.go b/cli/smartcontract/permission.go index cfb28ad0b..51071509b 100644 --- a/cli/smartcontract/permission.go +++ b/cli/smartcontract/permission.go @@ -1,7 +1,6 @@ package smartcontract import ( - "encoding/hex" "errors" "fmt" @@ -28,10 +27,9 @@ func (p permission) MarshalYAML() (any, error) { &yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey}, &yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()}) case manifest.PermissionGroup: - bs := p.Contract.Value.(*keys.PublicKey).Bytes() m.Content = append(m.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey}, - &yaml.Node{Kind: yaml.ScalarNode, Value: hex.EncodeToString(bs)}) + &yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()}) default: return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type) } diff --git a/cli/smartcontract/smart_contract_test.go b/cli/smartcontract/smart_contract_test.go index cd89b16f6..69717b37c 100644 --- a/cli/smartcontract/smart_contract_test.go +++ b/cli/smartcontract/smart_contract_test.go @@ -1,7 +1,6 @@ package smartcontract import ( - "encoding/hex" "flag" "os" "testing" @@ -109,7 +108,7 @@ func TestPermissionMarshal(t *testing.T) { p.Methods.Add("abc") p.Methods.Add("lamao") testPermissionMarshal(t, p, - "group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+ + "group: "+priv.PublicKey().StringCompressed()+"\n"+ "methods:\n - abc\n - lamao\n") }) } @@ -118,7 +117,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) { priv, err := keys.NewPrivateKey() require.NoError(t, err) - pub := hex.EncodeToString(priv.PublicKey().Bytes()) + pub := priv.PublicKey().StringCompressed() u160 := random.Uint160().StringLE() testCases := []string{ "hash: []\nmethods: '*'\n", // invalid hash type diff --git a/cli/wallet/candidate_test.go b/cli/wallet/candidate_test.go index 6a23ab020..15f75ddee 100644 --- a/cli/wallet/candidate_test.go +++ b/cli/wallet/candidate_test.go @@ -1,7 +1,6 @@ package wallet_test import ( - "encoding/hex" "math/big" "strconv" "testing" @@ -18,7 +17,7 @@ func TestRegisterCandidate(t *testing.T) { validatorAddress := testcli.ValidatorPriv.Address() validatorPublic := testcli.ValidatorPriv.PublicKey() - validatorHex := hex.EncodeToString(validatorPublic.Bytes()) + validatorHex := validatorPublic.StringCompressed() e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", diff --git a/cli/wallet/multisig_test.go b/cli/wallet/multisig_test.go index 5972c3659..fad718c38 100644 --- a/cli/wallet/multisig_test.go +++ b/cli/wallet/multisig_test.go @@ -1,7 +1,6 @@ package wallet_test import ( - "encoding/hex" "encoding/json" "fmt" "math/big" @@ -45,9 +44,9 @@ func TestSignMultisigTx(t *testing.T) { "--wallet", w, "--wif", wif, "--min", "2", - hex.EncodeToString(pubs[0].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes())) + pubs[0].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed()) } addAccount(wallet1Path, privs[0].WIF()) addAccount(wallet2Path, privs[1].WIF()) diff --git a/cli/wallet/wallet_test.go b/cli/wallet/wallet_test.go index 6c312ea6f..a6c828dda 100644 --- a/cli/wallet/wallet_test.go +++ b/cli/wallet/wallet_test.go @@ -1,7 +1,6 @@ package wallet_test import ( - "encoding/hex" "encoding/json" "math/big" "os" @@ -437,16 +436,16 @@ func TestWalletInit(t *testing.T) { "--wallet", walletPath, "--min", "2"} t.Run("invalid pub encoding", func(t *testing.T) { - e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes()), + e.RunWithError(t, append(cmd, pubs[1].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed(), "not-a-pub")...) }) t.Run("missing WIF", func(t *testing.T) { - e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes()), - hex.EncodeToString(pubs[3].Bytes()))...) + e.RunWithError(t, append(cmd, pubs[0].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed(), + pubs[3].StringCompressed())...) }) cmd = append(cmd, "--wif", privs[0].WIF()) t.Run("InvalidPublicKeys", func(t *testing.T) { @@ -455,18 +454,18 @@ func TestWalletInit(t *testing.T) { e.In.WriteString("multipass\r") defer e.In.Reset() - e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes()), - hex.EncodeToString(pubs[3].Bytes()))...) + e.RunWithError(t, append(cmd, pubs[1].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed(), + pubs[3].StringCompressed())...) }) e.In.WriteString("multiacc\r") e.In.WriteString("multipass\r") e.In.WriteString("multipass\r") - e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes()), - hex.EncodeToString(pubs[3].Bytes()))...) + e.Run(t, append(cmd, pubs[0].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed(), + pubs[3].StringCompressed())...) script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs) require.NoError(t, err) @@ -482,10 +481,10 @@ func TestWalletInit(t *testing.T) { e.In.WriteString("multiacc\r") e.In.WriteString("multipass\r") e.In.WriteString("multipass\r") - e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes()), - hex.EncodeToString(pubs[3].Bytes()))...) + e.RunWithError(t, append(cmd, pubs[0].StringCompressed(), + pubs[1].StringCompressed(), + pubs[2].StringCompressed(), + pubs[3].StringCompressed())...) }) privs, pubs = testcli.GenerateKeys(t, 3) @@ -508,9 +507,9 @@ func TestWalletInit(t *testing.T) { e.Run(t, "neo-go", "wallet", "import-multisig", "--wallet", walletPath, "--min", "2", - hex.EncodeToString(pubs[0].Bytes()), // Public key of the already imported account - hex.EncodeToString(pubs[1].Bytes()), - hex.EncodeToString(pubs[2].Bytes())) + pubs[0].StringCompressed(), // Public key of the already imported account + pubs[1].StringCompressed(), + pubs[2].StringCompressed()) w, err := wallet.NewWalletFromFile(walletPath) require.NoError(t, err) @@ -530,9 +529,9 @@ func TestWalletInit(t *testing.T) { e.RunWithError(t, "neo-go", "wallet", "import-multisig", "--wallet", walletPath, "--min", "2", - hex.EncodeToString(pubsNew[0].Bytes()), - hex.EncodeToString(pubsNew[1].Bytes()), - hex.EncodeToString(pubsNew[2].Bytes())) + pubsNew[0].StringCompressed(), + pubsNew[1].StringCompressed(), + pubsNew[2].StringCompressed()) w, err := wallet.NewWalletFromFile(walletPath) require.NoError(t, err) diff --git a/internal/basicchain/basic.go b/internal/basicchain/basic.go index 370986563..812012aa0 100644 --- a/internal/basicchain/basic.go +++ b/internal/basicchain/basic.go @@ -196,7 +196,7 @@ func Init(t *testing.T, rootpath string, e *neotest.Executor) { require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt)) designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(noderoles.P2PNotary), []any{ntr.Accounts[0].PublicKey().Bytes()}) - t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PublicKey().Bytes())) + t.Logf("Designated Notary node: %s", ntr.Accounts[0].PublicKey().StringCompressed()) // Block #10: push verification contract with arguments into the chain. verifyPath = filepath.Join(testDataPrefix, "verify_args", "verification_with_args_contract.go") diff --git a/pkg/config/protocol_config_test.go b/pkg/config/protocol_config_test.go index 8553bf4de..60b850c33 100644 --- a/pkg/config/protocol_config_test.go +++ b/pkg/config/protocol_config_test.go @@ -2,7 +2,6 @@ package config import ( "encoding/base64" - "encoding/hex" "fmt" "path/filepath" "testing" @@ -320,7 +319,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) { t.Run("unmarshal config", func(t *testing.T) { t.Run("good", func(t *testing.T) { - pubStr := hex.EncodeToString(pub.Bytes()) + pubStr := pub.StringCompressed() script := []byte{1, 2, 3, 4} cfgYml := fmt.Sprintf(`ProtocolConfiguration: Genesis: @@ -354,7 +353,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) { }) t.Run("unknown role", func(t *testing.T) { - pubStr := hex.EncodeToString(pub.Bytes()) + pubStr := pub.StringCompressed() cfgYml := fmt.Sprintf(`ProtocolConfiguration: Genesis: Roles: @@ -367,7 +366,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) { }) t.Run("last role", func(t *testing.T) { - pubStr := hex.EncodeToString(pub.Bytes()) + pubStr := pub.StringCompressed() cfgYml := fmt.Sprintf(`ProtocolConfiguration: Genesis: Roles: diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index ba5e57e91..840b87e34 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -364,7 +364,7 @@ func (p *PublicKey) String() string { // MarshalJSON implements the json.Marshaler interface. func (p PublicKey) MarshalJSON() ([]byte, error) { - return json.Marshal(hex.EncodeToString(p.Bytes())) + return json.Marshal(p.StringCompressed()) } // UnmarshalJSON implements the json.Unmarshaler interface. @@ -389,7 +389,7 @@ func (p *PublicKey) UnmarshalJSON(data []byte) error { // MarshalYAML implements the YAML marshaler interface. func (p *PublicKey) MarshalYAML() (any, error) { - return hex.EncodeToString(p.Bytes()), nil + return p.StringCompressed(), nil } // UnmarshalYAML implements the YAML unmarshaler interface. @@ -406,3 +406,9 @@ func (p *PublicKey) UnmarshalYAML(unmarshal func(any) error) error { } return p.DecodeBytes(b) } + +// StringCompressed returns the hex string representation of the public key +// in its compressed form. +func (p *PublicKey) StringCompressed() string { + return hex.EncodeToString(p.Bytes()) +} diff --git a/pkg/crypto/keys/publickey_test.go b/pkg/crypto/keys/publickey_test.go index 3fc8bbeb3..d22c0d090 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -77,7 +77,7 @@ func TestDecodeFromString(t *testing.T) { str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c" pubKey, err := NewPublicKeyFromString(str) require.NoError(t, err) - require.Equal(t, str, hex.EncodeToString(pubKey.Bytes())) + require.Equal(t, str, pubKey.StringCompressed()) _, err = NewPublicKeyFromString(str[2:]) require.Error(t, err) diff --git a/pkg/neotest/chain/chain.go b/pkg/neotest/chain/chain.go index d54f9ee5b..5d0fce09c 100644 --- a/pkg/neotest/chain/chain.go +++ b/pkg/neotest/chain/chain.go @@ -95,12 +95,12 @@ func init() { // Config entry must contain validators first in a specific order. standByCommittee = make([]string, len(pubs)) - standByCommittee[0] = hex.EncodeToString(pubs[2].Bytes()) - standByCommittee[1] = hex.EncodeToString(pubs[0].Bytes()) - standByCommittee[2] = hex.EncodeToString(pubs[3].Bytes()) - standByCommittee[3] = hex.EncodeToString(pubs[1].Bytes()) - standByCommittee[4] = hex.EncodeToString(pubs[4].Bytes()) - standByCommittee[5] = hex.EncodeToString(pubs[5].Bytes()) + standByCommittee[0] = pubs[2].StringCompressed() + standByCommittee[1] = pubs[0].StringCompressed() + standByCommittee[2] = pubs[3].StringCompressed() + standByCommittee[3] = pubs[1].StringCompressed() + standByCommittee[4] = pubs[4].StringCompressed() + standByCommittee[5] = pubs[5].StringCompressed() multiValidatorAcc = make([]*wallet.Account, 4) sort.Sort(pubs[:4]) diff --git a/pkg/services/oracle/response.go b/pkg/services/oracle/response.go index 06062941e..8cbd70d77 100644 --- a/pkg/services/oracle/response.go +++ b/pkg/services/oracle/response.go @@ -1,7 +1,6 @@ package oracle import ( - "encoding/hex" "errors" "fmt" gio "io" @@ -45,7 +44,7 @@ func (o *Oracle) AddResponse(pub *keys.PublicKey, reqID uint64, txSig []byte) { ok = pub.VerifyHashable(txSig, uint32(o.Network), incTx.backupTx) if !ok { o.Log.Debug("invalid response signature", - zap.String("pub", hex.EncodeToString(pub.Bytes()))) + zap.String("pub", pub.StringCompressed())) incTx.Unlock() return } diff --git a/pkg/smartcontract/context/context_test.go b/pkg/smartcontract/context/context_test.go index 9d3468bef..a0aa35ad8 100644 --- a/pkg/smartcontract/context/context_test.go +++ b/pkg/smartcontract/context/context_test.go @@ -1,7 +1,6 @@ package context import ( - "encoding/hex" "encoding/json" "testing" @@ -185,7 +184,7 @@ func TestParameterContext_MarshalJSON(t *testing.T) { Value: sign, }}, Signatures: map[string][]byte{ - hex.EncodeToString(priv.PublicKey().Bytes()): sign, + priv.PublicKey().StringCompressed(): sign, }, }, }, diff --git a/pkg/smartcontract/context/item.go b/pkg/smartcontract/context/item.go index ffa5b7da9..436417632 100644 --- a/pkg/smartcontract/context/item.go +++ b/pkg/smartcontract/context/item.go @@ -1,8 +1,6 @@ package context import ( - "encoding/hex" - "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/smartcontract" ) @@ -16,11 +14,11 @@ type Item struct { // GetSignature returns a signature for the pub if present. func (it *Item) GetSignature(pub *keys.PublicKey) []byte { - return it.Signatures[hex.EncodeToString(pub.Bytes())] + return it.Signatures[pub.StringCompressed()] } // AddSignature adds a signature for the pub. func (it *Item) AddSignature(pub *keys.PublicKey, sig []byte) { - pubHex := hex.EncodeToString(pub.Bytes()) + pubHex := pub.StringCompressed() it.Signatures[pubHex] = sig } diff --git a/pkg/smartcontract/context/item_test.go b/pkg/smartcontract/context/item_test.go index 767e510d4..84ee8e540 100644 --- a/pkg/smartcontract/context/item_test.go +++ b/pkg/smartcontract/context/item_test.go @@ -1,7 +1,6 @@ package context import ( - "encoding/hex" "testing" "github.com/nspcc-dev/neo-go/internal/random" @@ -46,8 +45,8 @@ func TestContextItem_MarshalJSON(t *testing.T) { Value: random.Bytes(keys.SignatureLen), }}, Signatures: map[string][]byte{ - hex.EncodeToString(priv1.PublicKey().Bytes()): random.Bytes(keys.SignatureLen), - hex.EncodeToString(priv2.PublicKey().Bytes()): random.Bytes(keys.SignatureLen), + priv1.PublicKey().StringCompressed(): random.Bytes(keys.SignatureLen), + priv2.PublicKey().StringCompressed(): random.Bytes(keys.SignatureLen), }, } diff --git a/pkg/smartcontract/manifest/group.go b/pkg/smartcontract/manifest/group.go index c66126e80..96834ddb0 100644 --- a/pkg/smartcontract/manifest/group.go +++ b/pkg/smartcontract/manifest/group.go @@ -79,7 +79,7 @@ func (g Groups) Contains(k *keys.PublicKey) bool { // MarshalJSON implements the json.Marshaler interface. func (g *Group) MarshalJSON() ([]byte, error) { aux := &groupAux{ - PublicKey: hex.EncodeToString(g.PublicKey.Bytes()), + PublicKey: g.PublicKey.StringCompressed(), Signature: g.Signature, } return json.Marshal(aux) diff --git a/pkg/smartcontract/manifest/permission.go b/pkg/smartcontract/manifest/permission.go index 260c73b14..18b67dd7e 100644 --- a/pkg/smartcontract/manifest/permission.go +++ b/pkg/smartcontract/manifest/permission.go @@ -2,7 +2,6 @@ package manifest import ( "crypto/elliptic" - "encoding/hex" "encoding/json" "errors" "fmt" @@ -204,7 +203,7 @@ func (d *PermissionDesc) MarshalJSON() ([]byte, error) { case PermissionHash: return json.Marshal("0x" + d.Hash().StringLE()) case PermissionGroup: - return json.Marshal(hex.EncodeToString(d.Group().Bytes())) + return json.Marshal(d.Group().StringCompressed()) default: return []byte(`"*"`), nil } diff --git a/pkg/wallet/account_test.go b/pkg/wallet/account_test.go index a96340967..765ebb7da 100644 --- a/pkg/wallet/account_test.go +++ b/pkg/wallet/account_test.go @@ -1,7 +1,6 @@ package wallet import ( - "encoding/hex" "encoding/json" "testing" @@ -237,7 +236,7 @@ func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) { require.Equalf(t, want, have, "expected address %s got %s", want, have) want, have = tk.Wif, acc.privateKey.WIF() require.Equalf(t, want, have, "expected wif %s got %s", want, have) - want, have = tk.PublicKey, hex.EncodeToString(acc.PublicKey().Bytes()) + want, have = tk.PublicKey, acc.PublicKey().StringCompressed() require.Equalf(t, want, have, "expected pub key %s got %s", want, have) want, have = tk.PrivateKey, acc.privateKey.String() require.Equalf(t, want, have, "expected priv key %s got %s", want, have)