forked from TrueCloudLab/frostfs-sdk-go
[#43] owner: move package from neofs-api-go
Also remove neofs-crypto dependency. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
46353456f1
commit
ee42623a3e
5 changed files with 319 additions and 0 deletions
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1
|
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/google/uuid v1.2.0
|
github.com/google/uuid v1.2.0
|
||||||
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/hrw v1.0.9
|
github.com/nspcc-dev/hrw v1.0.9
|
||||||
github.com/nspcc-dev/neo-go v0.96.1
|
github.com/nspcc-dev/neo-go v0.96.1
|
||||||
github.com/nspcc-dev/neofs-api-go v1.30.0
|
github.com/nspcc-dev/neofs-api-go v1.30.0
|
||||||
|
|
101
owner/id.go
Normal file
101
owner/id.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package owner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/mr-tron/base58"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ID represents v2-compatible owner identifier.
|
||||||
|
type ID refs.OwnerID
|
||||||
|
|
||||||
|
var errInvalidIDString = errors.New("incorrect format of the string owner ID")
|
||||||
|
|
||||||
|
// NewIDFromV2 wraps v2 OwnerID message to ID.
|
||||||
|
//
|
||||||
|
// Nil refs.OwnerID converts to nil.
|
||||||
|
func NewIDFromV2(idV2 *refs.OwnerID) *ID {
|
||||||
|
return (*ID)(idV2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewID creates and initializes blank ID.
|
||||||
|
//
|
||||||
|
// Works similar as NewIDFromV2(new(OwnerID)).
|
||||||
|
//
|
||||||
|
// Defaults:
|
||||||
|
// - value: nil.
|
||||||
|
func NewID() *ID {
|
||||||
|
return NewIDFromV2(new(refs.OwnerID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNeo3Wallet sets owner identifier value to NEO3 wallet address.
|
||||||
|
func (id *ID) SetNeo3Wallet(v *NEO3Wallet) {
|
||||||
|
(*refs.OwnerID)(id).SetValue(v.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 returns the v2 owner ID message.
|
||||||
|
//
|
||||||
|
// Nil ID converts to nil.
|
||||||
|
func (id *ID) ToV2() *refs.OwnerID {
|
||||||
|
return (*refs.OwnerID)(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer.
|
||||||
|
func (id *ID) String() string {
|
||||||
|
return base58.Encode((*refs.OwnerID)(id).GetValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal defines a comparison relation on ID's.
|
||||||
|
//
|
||||||
|
// ID's are equal if they have the same binary representation.
|
||||||
|
func (id *ID) Equal(id2 *ID) bool {
|
||||||
|
return bytes.Equal(
|
||||||
|
(*refs.ObjectID)(id).GetValue(),
|
||||||
|
(*refs.ObjectID)(id2).GetValue(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIDFromNeo3Wallet creates new owner identity from 25-byte neo wallet.
|
||||||
|
func NewIDFromNeo3Wallet(v *NEO3Wallet) *ID {
|
||||||
|
id := NewID()
|
||||||
|
id.SetNeo3Wallet(v)
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse converts base58 string representation into ID.
|
||||||
|
func (id *ID) Parse(s string) error {
|
||||||
|
data, err := base58.Decode(s)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse owner.ID from string: %w", err)
|
||||||
|
} else if len(data) != NEO3WalletSize {
|
||||||
|
return errInvalidIDString
|
||||||
|
}
|
||||||
|
|
||||||
|
(*refs.OwnerID)(id).SetValue(data)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals ID into a protobuf binary form.
|
||||||
|
func (id *ID) Marshal() ([]byte, error) {
|
||||||
|
return (*refs.OwnerID)(id).StableMarshal(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals protobuf binary representation of ID.
|
||||||
|
func (id *ID) Unmarshal(data []byte) error {
|
||||||
|
return (*refs.OwnerID)(id).Unmarshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes ID to protobuf JSON format.
|
||||||
|
func (id *ID) MarshalJSON() ([]byte, error) {
|
||||||
|
return (*refs.OwnerID)(id).MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes ID from protobuf JSON format.
|
||||||
|
func (id *ID) UnmarshalJSON(data []byte) error {
|
||||||
|
return (*refs.OwnerID)(id).UnmarshalJSON(data)
|
||||||
|
}
|
133
owner/id_test.go
Normal file
133
owner/id_test.go
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package owner_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mr-tron/base58"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
. "github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||||
|
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIDV2(t *testing.T) {
|
||||||
|
id := ownertest.GenerateID()
|
||||||
|
|
||||||
|
idV2 := id.ToV2()
|
||||||
|
|
||||||
|
require.Equal(t, id, NewIDFromV2(idV2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewIDFromNeo3Wallet(t *testing.T) {
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey()))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
id := NewIDFromNeo3Wallet(wallet)
|
||||||
|
require.Equal(t, id.ToV2().GetValue(), wallet.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestID_Parse(t *testing.T) {
|
||||||
|
t.Run("should parse successful", func(t *testing.T) {
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey()))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
eid := NewIDFromNeo3Wallet(wallet)
|
||||||
|
aid := NewID()
|
||||||
|
|
||||||
|
require.NoError(t, aid.Parse(eid.String()))
|
||||||
|
require.Equal(t, eid, aid)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should failure on parse", func(t *testing.T) {
|
||||||
|
cs := []byte{1, 2, 3, 4, 5, 6}
|
||||||
|
str := base58.Encode(cs)
|
||||||
|
cid := NewID()
|
||||||
|
|
||||||
|
require.Error(t, cid.Parse(str))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIDEncoding(t *testing.T) {
|
||||||
|
id := ownertest.GenerateID()
|
||||||
|
|
||||||
|
t.Run("binary", func(t *testing.T) {
|
||||||
|
data, err := id.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
id2 := NewID()
|
||||||
|
require.NoError(t, id2.Unmarshal(data))
|
||||||
|
|
||||||
|
require.Equal(t, id, id2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("json", func(t *testing.T) {
|
||||||
|
data, err := id.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
a2 := NewID()
|
||||||
|
require.NoError(t, a2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, id, a2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestID_Equal(t *testing.T) {
|
||||||
|
var (
|
||||||
|
data1 = []byte{1, 2, 3}
|
||||||
|
data2 = data1
|
||||||
|
data3 = append(data1, 255)
|
||||||
|
)
|
||||||
|
|
||||||
|
id1 := ownertest.GenerateIDFromBytes(data1)
|
||||||
|
|
||||||
|
require.True(t, id1.Equal(
|
||||||
|
ownertest.GenerateIDFromBytes(data2),
|
||||||
|
))
|
||||||
|
|
||||||
|
require.False(t, id1.Equal(
|
||||||
|
ownertest.GenerateIDFromBytes(data3),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewIDFromV2(t *testing.T) {
|
||||||
|
t.Run("from nil", func(t *testing.T) {
|
||||||
|
var x *refs.OwnerID
|
||||||
|
|
||||||
|
require.Nil(t, NewIDFromV2(x))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestID_ToV2(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x *ID
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestID_String(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
id := NewID()
|
||||||
|
|
||||||
|
require.Empty(t, id.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewID(t *testing.T) {
|
||||||
|
t.Run("default values", func(t *testing.T) {
|
||||||
|
id := NewID()
|
||||||
|
|
||||||
|
// convert to v2 message
|
||||||
|
idV2 := id.ToV2()
|
||||||
|
|
||||||
|
require.Nil(t, idV2.GetValue())
|
||||||
|
})
|
||||||
|
}
|
27
owner/test/id.go
Normal file
27
owner/test/id.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package ownertest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateID returns owner.ID calculated
|
||||||
|
// from a random owner.NEO3Wallet.
|
||||||
|
func GenerateID() *owner.ID {
|
||||||
|
data := make([]byte, owner.NEO3WalletSize)
|
||||||
|
|
||||||
|
rand.Read(data)
|
||||||
|
|
||||||
|
return GenerateIDFromBytes(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIDFromBytes returns owner.ID generated
|
||||||
|
// from a passed byte slice.
|
||||||
|
func GenerateIDFromBytes(val []byte) *owner.ID {
|
||||||
|
idV2 := new(refs.OwnerID)
|
||||||
|
idV2.SetValue(val)
|
||||||
|
|
||||||
|
return owner.NewIDFromV2(idV2)
|
||||||
|
}
|
57
owner/wallet.go
Normal file
57
owner/wallet.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
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
|
||||||
|
}
|
Loading…
Reference in a new issue