[#103] owner: remove NEO3Wallet type

Allow to use public keys and N3 wallet accounts instead.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-01-13 16:16:35 +03:00 committed by Alex Vanin
parent f83ff628fb
commit 596774ce5b
13 changed files with 103 additions and 144 deletions

View file

@ -82,13 +82,7 @@ func (c *Client) PutContainer(ctx context.Context, cnr *container.Container, opt
// if container owner is not set, then use client key as owner // if container owner is not set, then use client key as owner
if cnr.OwnerID() == nil { if cnr.OwnerID() == nil {
w, err := owner.NEO3WalletFromPublicKey(&callOptions.key.PublicKey) ownerID := owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
if err != nil {
return nil, err
}
ownerID := new(owner.ID)
ownerID.SetNeo3Wallet(w)
cnr.SetOwnerID(ownerID) cnr.SetOwnerID(ownerID)
} }
@ -270,13 +264,7 @@ func (c *Client) ListContainers(ctx context.Context, ownerID *owner.ID, opts ...
} }
if ownerID == nil { if ownerID == nil {
w, err := owner.NEO3WalletFromPublicKey(&callOptions.key.PublicKey) ownerID = owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
if err != nil {
return nil, err
}
ownerID = new(owner.ID)
ownerID.SetNeo3Wallet(w)
} }
reqBody := new(v2container.ListRequestBody) reqBody := new(v2container.ListRequestBody)

View file

@ -50,13 +50,7 @@ func (c *Client) CreateSession(ctx context.Context, expiration uint64, opts ...C
opts[i](callOptions) opts[i](callOptions)
} }
w, err := owner.NEO3WalletFromPublicKey(&callOptions.key.PublicKey) ownerID := owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
if err != nil {
return nil, err
}
ownerID := new(owner.ID)
ownerID.SetNeo3Wallet(w)
reqBody := new(v2session.CreateRequestBody) reqBody := new(v2session.CreateRequestBody)
reqBody.SetOwnerID(ownerID.ToV2()) reqBody.SetOwnerID(ownerID.ToV2())
@ -66,7 +60,7 @@ func (c *Client) CreateSession(ctx context.Context, expiration uint64, opts ...C
req.SetBody(reqBody) req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions)) req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err = v2signature.SignServiceMessage(callOptions.key, req) err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,6 +1,8 @@
package container package container
import ( import (
"crypto/ecdsa"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/nspcc-dev/neofs-sdk-go/acl" "github.com/nspcc-dev/neofs-sdk-go/acl"
"github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/nspcc-dev/neofs-sdk-go/netmap"
@ -61,13 +63,13 @@ func WithOwnerID(id *owner.ID) Option {
} }
} }
func WithNEO3Wallet(w *owner.NEO3Wallet) Option { func WithOwnerPublicKey(pub *ecdsa.PublicKey) Option {
return func(option *containerOptions) { return func(option *containerOptions) {
if option.owner == nil { if option.owner == nil {
option.owner = new(owner.ID) option.owner = new(owner.ID)
} }
option.owner.SetNeo3Wallet(w) option.owner.SetPublicKey(pub)
} }
} }

34
owner/convert_test.go Normal file
View file

@ -0,0 +1,34 @@
package owner
import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/hex"
"testing"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
func TestNEO3WalletFromPublicKey(t *testing.T) {
rawPub, _ := hex.DecodeString("0369b7b6c49fb937f3de52af189b91069767679c2739798d85f2ed69c079940680")
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), rawPub)
require.True(t, x != nil && y != nil)
expected := "35ee628f21922d7308f1bd71f03a0d8ba89c4e7372fca1442c"
actual := PublicKeyToIDBytes(&ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y})
require.Equal(t, expected, hex.EncodeToString(actual))
}
func TestPublicKeyToBytes(t *testing.T) {
p, err := keys.NewPrivateKey()
require.NoError(t, err)
expected, err := base58.Decode(p.PublicKey().Address())
require.NoError(t, err)
actual := PublicKeyToIDBytes((*ecdsa.PublicKey)(p.PublicKey()))
require.Equal(t, expected, actual)
require.Equal(t, NEO3WalletSize, len(actual))
}

View file

@ -2,12 +2,15 @@ package owner
import ( import (
"bytes" "bytes"
"crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
) )
@ -16,6 +19,12 @@ type ID refs.OwnerID
var errInvalidIDString = errors.New("incorrect format of the string owner ID") var errInvalidIDString = errors.New("incorrect format of the string owner ID")
// ErrEmptyPublicKey when public key passed to Verify method is nil.
var ErrEmptyPublicKey = errors.New("empty public key")
// NEO3WalletSize contains size of neo3 wallet.
const NEO3WalletSize = 25
// NewIDFromV2 wraps v2 OwnerID message to ID. // NewIDFromV2 wraps v2 OwnerID message to ID.
// //
// Nil refs.OwnerID converts to nil. // Nil refs.OwnerID converts to nil.
@ -33,9 +42,9 @@ func NewID() *ID {
return NewIDFromV2(new(refs.OwnerID)) return NewIDFromV2(new(refs.OwnerID))
} }
// SetNeo3Wallet sets owner identifier value to NEO3 wallet address. // SetPublicKey sets owner identifier value to the provided NEO3 public key.
func (id *ID) SetNeo3Wallet(v *NEO3Wallet) { func (id *ID) SetPublicKey(pub *ecdsa.PublicKey) {
(*refs.OwnerID)(id).SetValue(v.Bytes()) (*refs.OwnerID)(id).SetValue(PublicKeyToIDBytes(pub))
} }
// ToV2 returns the v2 owner ID message. // ToV2 returns the v2 owner ID message.
@ -60,14 +69,20 @@ func (id *ID) Equal(id2 *ID) bool {
) )
} }
// NewIDFromNeo3Wallet creates new owner identity from 25-byte neo wallet. // NewIDFromPublicKey creates new owner identity from ECDSA public key.
func NewIDFromNeo3Wallet(v *NEO3Wallet) *ID { func NewIDFromPublicKey(pub *ecdsa.PublicKey) *ID {
id := NewID() id := NewID()
id.SetNeo3Wallet(v) id.SetPublicKey(pub)
return id return id
} }
// NewIDFromPublicKey creates new owner identity from N3 wallet account.
func NewIDFromN3Account(acc *wallet.Account) *ID {
return NewIDFromPublicKey(
(*ecdsa.PublicKey)(acc.PrivateKey().PublicKey()))
}
// Parse converts base58 string representation into ID. // Parse converts base58 string representation into ID.
func (id *ID) Parse(s string) error { func (id *ID) Parse(s string) error {
data, err := base58.Decode(s) data, err := base58.Decode(s)
@ -123,3 +138,15 @@ func (id *ID) MarshalJSON() ([]byte, error) {
func (id *ID) UnmarshalJSON(data []byte) error { func (id *ID) UnmarshalJSON(data []byte) error {
return (*refs.OwnerID)(id).UnmarshalJSON(data) return (*refs.OwnerID)(id).UnmarshalJSON(data)
} }
// PublicKeyToIDBytes converts public key to a byte slice of NEO3WalletSize length.
// It is similar to decoding a NEO3 address but is inlined to skip base58 encoding-decoding step
// make it clear that no errors can occur.
func PublicKeyToIDBytes(pub *ecdsa.PublicKey) []byte {
sh := (*keys.PublicKey)(pub).GetScriptHash()
b := make([]byte, NEO3WalletSize)
b[0] = address.Prefix
copy(b[1:], sh.BytesBE())
copy(b[21:], hash.Checksum(b[:21]))
return b
}

View file

@ -7,6 +7,7 @@ import (
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
. "github.com/nspcc-dev/neofs-sdk-go/owner" . "github.com/nspcc-dev/neofs-sdk-go/owner"
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test" ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
@ -49,26 +50,28 @@ func TestID_Valid(t *testing.T) {
}) })
} }
func TestNewIDFromNeo3Wallet(t *testing.T) { func TestNewIDFromN3Account(t *testing.T) {
acc, err := wallet.NewAccount()
require.NoError(t, err)
id := NewIDFromN3Account(acc)
require.Equal(t, id.String(), acc.Address)
}
func TestNewIDFromPublicKey(t *testing.T) {
p, err := keys.NewPrivateKey() p, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) id := NewIDFromPublicKey((*ecdsa.PublicKey)(p.PublicKey()))
require.NoError(t, err) require.Equal(t, id.String(), p.Address())
id := NewIDFromNeo3Wallet(wallet)
require.Equal(t, id.ToV2().GetValue(), wallet.Bytes())
} }
func TestID_Parse(t *testing.T) { func TestID_Parse(t *testing.T) {
t.Run("should parse successful", func(t *testing.T) { t.Run("should parse successful", func(t *testing.T) {
p, err := keys.NewPrivateKey() acc, err := wallet.NewAccount()
require.NoError(t, err) require.NoError(t, err)
wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) eid := NewIDFromN3Account(acc)
require.NoError(t, err)
eid := NewIDFromNeo3Wallet(wallet)
aid := NewID() aid := NewID()
require.NoError(t, aid.Parse(eid.String())) require.NoError(t, aid.Parse(eid.String()))

View file

@ -1,56 +0,0 @@
package owner
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)
// NEO3Wallet represents NEO3 wallet address.
type NEO3Wallet [NEO3WalletSize]byte
// NEO3WalletSize contains size of neo3 wallet.
const NEO3WalletSize = 25
// ErrEmptyPublicKey when PK passed to Verify method is nil.
var ErrEmptyPublicKey = errors.New("empty public key")
// NEO3WalletFromPublicKey converts public key to NEO3 wallet address.
func NEO3WalletFromPublicKey(key *ecdsa.PublicKey) (*NEO3Wallet, error) {
if key == nil {
return nil, ErrEmptyPublicKey
}
neoPublicKey := (*keys.PublicKey)(key)
d, err := base58.Decode(neoPublicKey.Address())
if err != nil {
return nil, fmt.Errorf("can't decode neo3 address from key: %w", err)
}
w := new(NEO3Wallet)
copy(w.Bytes(), d)
return w, nil
}
// String implements fmt.Stringer.
func (w *NEO3Wallet) String() string {
if w != nil {
return base58.Encode(w[:])
}
return ""
}
// Bytes returns slice of NEO3 wallet address bytes.
func (w *NEO3Wallet) Bytes() []byte {
if w != nil {
return w[:]
}
return nil
}

View file

@ -1,21 +0,0 @@
package owner
import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
)
func TestNEO3WalletFromPublicKey(t *testing.T) {
rawPub, _ := hex.DecodeString("0369b7b6c49fb937f3de52af189b91069767679c2739798d85f2ed69c079940680")
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), rawPub)
require.True(t, x != nil && y != nil)
expected := "35ee628f21922d7308f1bd71f03a0d8ba89c4e7372fca1442c"
w, err := NEO3WalletFromPublicKey(&ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y})
require.NoError(t, err)
require.Equal(t, expected, hex.EncodeToString(w[:]))
}

View file

@ -254,17 +254,12 @@ type innerPool struct {
} }
func newPool(ctx context.Context, options *BuilderOptions) (Pool, error) { func newPool(ctx context.Context, options *BuilderOptions) (Pool, error) {
wallet, err := owner.NEO3WalletFromPublicKey(&options.Key.PublicKey)
if err != nil {
return nil, err
}
cache, err := NewCache() cache, err := NewCache()
if err != nil { if err != nil {
return nil, fmt.Errorf("couldn't create cache: %w", err) return nil, fmt.Errorf("couldn't create cache: %w", err)
} }
ownerID := owner.NewIDFromNeo3Wallet(wallet) ownerID := owner.NewIDFromPublicKey(&options.Key.PublicKey)
inner := make([]*innerPool, len(options.nodesParams)) inner := make([]*innerPool, len(options.nodesParams))
var atLeastOneHealthy bool var atLeastOneHealthy bool
@ -498,11 +493,7 @@ func (p *pool) conn(ctx context.Context, cfg *callConfig) (*clientPack, []client
return nil, nil, err return nil, nil, err
} }
wallet, err := owner.NEO3WalletFromPublicKey(&key.PublicKey) ownerID := owner.NewIDFromPublicKey(&key.PublicKey)
if err != nil {
return nil, nil, err
}
ownerID := owner.NewIDFromNeo3Wallet(wallet)
sessionToken = sessionTokenForOwner(ownerID, cliRes) sessionToken = sessionTokenForOwner(ownerID, cliRes)
_ = p.cache.Put(cacheKey, sessionToken) _ = p.cache.Put(cacheKey, sessionToken)

View file

@ -511,9 +511,7 @@ func TestSessionTokenOwner(t *testing.T) {
require.True(t, ok) require.True(t, ok)
anonKey := newPrivateKey(t) anonKey := newPrivateKey(t)
wallet, err := owner.NEO3WalletFromPublicKey(&anonKey.PublicKey) anonOwner := owner.NewIDFromPublicKey(&anonKey.PublicKey)
require.NoError(t, err)
anonOwner := owner.NewIDFromNeo3Wallet(wallet)
cfg := cfgFromOpts(WithKey(anonKey), useDefaultSession()) cfg := cfgFromOpts(WithKey(anonKey), useDefaultSession())
cp, _, err := p.conn(ctx, cfg) cp, _, err := p.conn(ctx, cfg)

View file

@ -1,7 +1,9 @@
package sessiontest package sessiontest
import ( import (
"math/rand" "crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -31,11 +33,13 @@ func Token() *session.Token {
panic(err) panic(err)
} }
w := new(owner.NEO3Wallet) priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
rand.Read(w.Bytes()) if err != nil {
panic(err)
}
ownerID := owner.NewID() ownerID := owner.NewID()
ownerID.SetNeo3Wallet(w) ownerID.SetPublicKey(&priv.PublicKey)
keyBin := p.PublicKey().Bytes() keyBin := p.PublicKey().Bytes()

View file

@ -91,12 +91,10 @@ func (b *BearerToken) SignToken(key *ecdsa.PrivateKey) error {
// nil if token is not signed. // nil if token is not signed.
func (b *BearerToken) Issuer() *owner.ID { func (b *BearerToken) Issuer() *owner.ID {
pub, _ := keys.NewPublicKeyFromBytes(b.token.GetSignature().GetKey(), elliptic.P256()) pub, _ := keys.NewPublicKeyFromBytes(b.token.GetSignature().GetKey(), elliptic.P256())
wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(pub)) if pub == nil {
if err != nil {
return nil return nil
} }
return owner.NewIDFromPublicKey((*ecdsa.PublicKey)(pub))
return owner.NewIDFromNeo3Wallet(wallet)
} }
// NewBearerToken creates and initializes blank BearerToken. // NewBearerToken creates and initializes blank BearerToken.

View file

@ -23,10 +23,7 @@ func TestBearerToken_Issuer(t *testing.T) {
p, err := keys.NewPrivateKey() p, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) ownerID := owner.NewIDFromPublicKey((*ecdsa.PublicKey)(p.PublicKey()))
require.NoError(t, err)
ownerID := owner.NewIDFromNeo3Wallet(wallet)
bearerToken.SetEACLTable(eacl.NewTable()) bearerToken.SetEACLTable(eacl.NewTable())
require.NoError(t, bearerToken.SignToken(&p.PrivateKey)) require.NoError(t, bearerToken.SignToken(&p.PrivateKey))