diff --git a/eacl/record_test.go b/eacl/record_test.go index 904d33b..1a14107 100644 --- a/eacl/record_test.go +++ b/eacl/record_test.go @@ -2,11 +2,10 @@ package eacl import ( "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "fmt" "testing" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" v2acl "github.com/nspcc-dev/neofs-api-go/v2/acl" checksumtest "github.com/nspcc-dev/neofs-sdk-go/checksum/test" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" @@ -252,7 +251,7 @@ func TestReservedRecords(t *testing.T) { } func randomPublicKey(t *testing.T) *ecdsa.PublicKey { - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - return &p.PublicKey + return &p.PrivateKey.PublicKey } diff --git a/eacl/target.go b/eacl/target.go index 3a2b7a8..249628b 100644 --- a/eacl/target.go +++ b/eacl/target.go @@ -2,8 +2,8 @@ package eacl import ( "crypto/ecdsa" - "crypto/elliptic" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" v2acl "github.com/nspcc-dev/neofs-api-go/v2/acl" ) @@ -51,8 +51,7 @@ func SetTargetECDSAKeys(t *Target, pubs ...*ecdsa.PublicKey) { } for i := 0; i < ln; i++ { - b := elliptic.MarshalCompressed(pubs[i].Curve, pubs[i].X, pubs[i].Y) - binKeys = append(binKeys, b) + binKeys = append(binKeys, (*keys.PublicKey)(pubs[i]).Bytes()) } t.SetBinaryKeys(binKeys) @@ -68,13 +67,9 @@ func TargetECDSAKeys(t *Target) []*ecdsa.PublicKey { pubs := make([]*ecdsa.PublicKey, ln) for i := 0; i < ln; i++ { - x, y := elliptic.UnmarshalCompressed(elliptic.P256(), binKeys[i]) - if x != nil && y != nil { - pubs[i] = &ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: x, - Y: y, - } + p := new(keys.PublicKey) + if p.DecodeBytes(binKeys[i]) == nil { + pubs[i] = (*ecdsa.PublicKey)(p) } } diff --git a/eacl/target_test.go b/eacl/target_test.go index d89c05d..2afd6f9 100644 --- a/eacl/target_test.go +++ b/eacl/target_test.go @@ -2,9 +2,9 @@ package eacl import ( "crypto/ecdsa" - "crypto/elliptic" "testing" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-api-go/v2/acl" v2acl "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/stretchr/testify/require" @@ -25,8 +25,7 @@ func TestTarget(t *testing.T) { require.Equal(t, v2acl.RoleSystem, v2.GetRole()) require.Len(t, v2.GetKeys(), len(pubs)) for i, key := range v2.GetKeys() { - b := elliptic.MarshalCompressed(pubs[i].Curve, pubs[i].X, pubs[i].Y) - require.Equal(t, key, b) + require.Equal(t, key, (*keys.PublicKey)(pubs[i]).Bytes()) } newTarget := NewTargetFromV2(v2) diff --git a/go.mod b/go.mod index aed77da..7217239 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,7 @@ require ( github.com/nspcc-dev/neo-go v0.98.0 github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1 github.com/nspcc-dev/neofs-crypto v0.3.0 - github.com/nspcc-dev/rfc6979 v0.2.0 github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.18.1 - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 google.golang.org/grpc v1.41.0 ) diff --git a/object/fmt_test.go b/object/fmt_test.go index d2fc57c..6e4bab7 100644 --- a/object/fmt_test.go +++ b/object/fmt_test.go @@ -1,11 +1,10 @@ package object import ( - "crypto/ecdsa" - "crypto/elliptic" "crypto/rand" "testing" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/stretchr/testify/require" ) @@ -18,9 +17,9 @@ func TestVerificationFields(t *testing.T) { obj.SetPayload(payload) obj.SetPayloadSize(uint64(len(payload))) - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - require.NoError(t, SetVerificationFields(p, obj)) + require.NoError(t, SetVerificationFields(&p.PrivateKey, obj)) require.NoError(t, CheckVerificationFields(obj.Object())) diff --git a/owner/id.go b/owner/id.go index ba3113b..6aed52e 100644 --- a/owner/id.go +++ b/owner/id.go @@ -6,6 +6,8 @@ import ( "fmt" "github.com/mr-tron/base58" + "github.com/nspcc-dev/neo-go/pkg/crypto/hash" + "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neofs-api-go/v2/refs" ) @@ -94,12 +96,12 @@ func valid(rawID []byte) bool { if len(rawID) != NEO3WalletSize { return false } - if rawID[0] != addressPrefixN3 { + if rawID[0] != address.NEO3Prefix { return false } const boundIndex = NEO3WalletSize - 4 - return bytes.Equal(rawID[boundIndex:], addressChecksum(rawID[:boundIndex])) + return bytes.Equal(rawID[boundIndex:], hash.Checksum(rawID[:boundIndex])) } // Marshal marshals ID into a protobuf binary form. diff --git a/owner/id_test.go b/owner/id_test.go index 820fa2e..ade70e5 100644 --- a/owner/id_test.go +++ b/owner/id_test.go @@ -2,11 +2,11 @@ package owner_test import ( "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "testing" "github.com/mr-tron/base58" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/util/slice" "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" @@ -28,11 +28,10 @@ func TestID_Valid(t *testing.T) { val := id.ToV2().GetValue() t.Run("invalid prefix", func(t *testing.T) { - v := make([]byte, len(val)) - copy(v, val) - v[0] ^= 0xFF + val := slice.Copy(val) + val[0] ^= 0xFF - id := ownertest.IDFromBytes(v) + id := ownertest.IDFromBytes(val) require.False(t, id.Valid()) }) t.Run("invalid size", func(t *testing.T) { @@ -42,20 +41,19 @@ func TestID_Valid(t *testing.T) { require.False(t, id.Valid()) }) t.Run("invalid checksum", func(t *testing.T) { - v := make([]byte, len(val)) - copy(v, val) - v[NEO3WalletSize-1] ^= 0xFF + val := slice.Copy(val) + val[NEO3WalletSize-1] ^= 0xFF - id := ownertest.IDFromBytes(v) + id := ownertest.IDFromBytes(val) require.False(t, id.Valid()) }) } func TestNewIDFromNeo3Wallet(t *testing.T) { - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - wallet, err := NEO3WalletFromPublicKey(&p.PublicKey) + wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) require.NoError(t, err) id := NewIDFromNeo3Wallet(wallet) @@ -64,10 +62,10 @@ func TestNewIDFromNeo3Wallet(t *testing.T) { func TestID_Parse(t *testing.T) { t.Run("should parse successful", func(t *testing.T) { - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - wallet, err := NEO3WalletFromPublicKey(&p.PublicKey) + wallet, err := NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) require.NoError(t, err) eid := NewIDFromNeo3Wallet(wallet) diff --git a/owner/test/id.go b/owner/test/id.go index 3a62023..f79ca91 100644 --- a/owner/test/id.go +++ b/owner/test/id.go @@ -1,9 +1,11 @@ package ownertest import ( - "crypto/sha256" "math/rand" + "github.com/mr-tron/base58" + "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-sdk-go/owner" ) @@ -11,13 +13,15 @@ import ( // ID returns owner.ID calculated // from a random owner.NEO3Wallet. func ID() *owner.ID { - u := make([]byte, owner.NEO3WalletSize) - u[0] = 0x35 - rand.Read(u[1:21]) - h1 := sha256.Sum256(u[:21]) - h2 := sha256.Sum256(h1[:]) - copy(u[21:], h2[:4]) - return IDFromBytes(u) + u := util.Uint160{} + rand.Read(u[:]) + + addr := address.Uint160ToString(u) + data, err := base58.Decode(addr) + if err != nil { + panic(err) + } + return IDFromBytes(data) } // IDFromBytes returns owner.ID generated diff --git a/owner/wallet.go b/owner/wallet.go index 0a96578..830bf7a 100644 --- a/owner/wallet.go +++ b/owner/wallet.go @@ -2,12 +2,11 @@ package owner import ( "crypto/ecdsa" - "crypto/elliptic" - "crypto/sha256" "errors" + "fmt" "github.com/mr-tron/base58" - "golang.org/x/crypto/ripemd160" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) // NEO3Wallet represents NEO3 wallet address. @@ -16,8 +15,6 @@ type NEO3Wallet [NEO3WalletSize]byte // NEO3WalletSize contains size of neo3 wallet. const NEO3WalletSize = 25 -const addressPrefixN3 = 0x35 - // ErrEmptyPublicKey when PK passed to Verify method is nil. var ErrEmptyPublicKey = errors.New("empty public key") @@ -27,30 +24,17 @@ func NEO3WalletFromPublicKey(key *ecdsa.PublicKey) (*NEO3Wallet, error) { return nil, ErrEmptyPublicKey } - b := elliptic.MarshalCompressed(key.Curve, key.X, key.Y) - script := []byte{0x0C /* PUSHDATA1 */, byte(len(b)) /* 33 */} - script = append(script, b...) - script = append(script, 0x41 /* SYSCALL */) - h := sha256.Sum256([]byte("System.Crypto.CheckSig")) - script = append(script, h[:4]...) + neoPublicKey := (*keys.PublicKey)(key) - h1 := sha256.Sum256(script) - rw := ripemd160.New() - rw.Write(h1[:]) - h160 := rw.Sum(nil) + d, err := base58.Decode(neoPublicKey.Address()) + if err != nil { + return nil, fmt.Errorf("can't decode neo3 address from key: %w", err) + } - var w NEO3Wallet - w[0] = addressPrefixN3 - copy(w[1:21], h160) - copy(w[21:], addressChecksum(w[:21])) + w := new(NEO3Wallet) + copy(w.Bytes(), d) - return &w, nil -} - -func addressChecksum(data []byte) []byte { - h1 := sha256.Sum256(data) - h2 := sha256.Sum256(h1[:]) - return h2[:4] + return w, nil } // String implements fmt.Stringer. diff --git a/pool/pool.go b/pool/pool.go index d2dab67..7089137 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -4,7 +4,6 @@ import ( "context" "crypto/ecdsa" "crypto/sha256" - "encoding/hex" "errors" "fmt" "math" @@ -14,6 +13,7 @@ import ( "sync" "time" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-sdk-go/client" apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" "github.com/nspcc-dev/neofs-sdk-go/container" @@ -430,9 +430,8 @@ func (p *pool) OwnerID() *owner.ID { } func formCacheKey(address string, key *ecdsa.PrivateKey) string { - buf := make([]byte, 32) - key.D.FillBytes(buf) - return address + hex.EncodeToString(buf) + k := keys.PrivateKey{PrivateKey: *key} + return address + k.String() } func (p *pool) conn(ctx context.Context, cfg *callConfig) (*clientPack, []client.CallOption, error) { diff --git a/pool/pool_test.go b/pool/pool_test.go index b46a94a..d084691 100644 --- a/pool/pool_test.go +++ b/pool/pool_test.go @@ -5,8 +5,6 @@ package pool import ( "context" "crypto/ecdsa" - "crypto/elliptic" - crand "crypto/rand" "fmt" "math/rand" "testing" @@ -14,6 +12,7 @@ import ( "github.com/golang/mock/gomock" "github.com/google/uuid" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/nspcc-dev/neofs-sdk-go/session" @@ -64,9 +63,9 @@ func TestBuildPoolCreateSessionFailed(t *testing.T) { } func newPrivateKey(t *testing.T) *ecdsa.PrivateKey { - p, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - return p + return &p.PrivateKey } func TestBuildPoolOneNodeFailed(t *testing.T) { diff --git a/reputation/test/generate.go b/reputation/test/generate.go index be216aa..0177643 100644 --- a/reputation/test/generate.go +++ b/reputation/test/generate.go @@ -1,11 +1,9 @@ package reputationtest import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "testing" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-sdk-go/reputation" "github.com/nspcc-dev/neofs-sdk-go/util/signature" "github.com/stretchr/testify/require" @@ -14,13 +12,13 @@ import ( func PeerID() *reputation.PeerID { v := reputation.NewPeerID() - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() if err != nil { panic(err) } key := [signature.PublicKeyCompressedSize]byte{} - copy(key[:], elliptic.MarshalCompressed(p.Curve, p.X, p.Y)) + copy(key[:], p.Bytes()) v.SetPublicKey(key) return v @@ -53,9 +51,9 @@ func GlobalTrust() *reputation.GlobalTrust { func SignedGlobalTrust(t testing.TB) *reputation.GlobalTrust { gt := GlobalTrust() - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - require.NoError(t, gt.Sign(p)) + require.NoError(t, gt.Sign(&p.PrivateKey)) return gt } diff --git a/session/test/token.go b/session/test/token.go index 84bf3e1..bf11059 100644 --- a/session/test/token.go +++ b/session/test/token.go @@ -1,22 +1,20 @@ package sessiontest import ( - "crypto/ecdsa" - "crypto/elliptic" - crand "crypto/rand" "math/rand" "github.com/google/uuid" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/session" ) -var p *ecdsa.PrivateKey +var p *keys.PrivateKey func init() { var err error - p, err = ecdsa.GenerateKey(elliptic.P256(), crand.Reader) + p, err = keys.NewPrivateKey() if err != nil { panic(err) } @@ -39,7 +37,7 @@ func Token() *session.Token { ownerID := owner.NewID() ownerID.SetNeo3Wallet(w) - keyBin := elliptic.MarshalCompressed(p.PublicKey.Curve, p.PublicKey.X, p.PublicKey.Y) + keyBin := p.PublicKey().Bytes() tok.SetID(uid) tok.SetOwnerID(ownerID) @@ -57,7 +55,7 @@ func Token() *session.Token { func SignedToken() *session.Token { tok := Token() - err := tok.Sign(p) + err := tok.Sign(&p.PrivateKey) if err != nil { panic(err) } diff --git a/token/bearer.go b/token/bearer.go index bd85e56..3cec8b4 100644 --- a/token/bearer.go +++ b/token/bearer.go @@ -5,6 +5,7 @@ import ( "crypto/elliptic" "errors" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/refs" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" @@ -89,14 +90,8 @@ func (b *BearerToken) SignToken(key *ecdsa.PrivateKey) error { // To pass node validation it should be owner of requested container. Returns // nil if token is not signed. func (b *BearerToken) Issuer() *owner.ID { - var pub *ecdsa.PublicKey - - x, y := elliptic.UnmarshalCompressed(elliptic.P256(), b.token.GetSignature().GetKey()) - if x != nil && y != nil { - pub = &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y} - } - - wallet, err := owner.NEO3WalletFromPublicKey(pub) + pub, _ := keys.NewPublicKeyFromBytes(b.token.GetSignature().GetKey(), elliptic.P256()) + wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(pub)) if err != nil { return nil } diff --git a/token/bearer_test.go b/token/bearer_test.go index 13985b0..cad01bd 100644 --- a/token/bearer_test.go +++ b/token/bearer_test.go @@ -2,10 +2,9 @@ package token_test import ( "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "testing" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/token" @@ -21,16 +20,16 @@ func TestBearerToken_Issuer(t *testing.T) { }) t.Run("signed token", func(t *testing.T) { - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() require.NoError(t, err) - wallet, err := owner.NEO3WalletFromPublicKey(&p.PublicKey) + wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(p.PublicKey())) require.NoError(t, err) ownerID := owner.NewIDFromNeo3Wallet(wallet) bearerToken.SetEACLTable(eacl.NewTable()) - require.NoError(t, bearerToken.SignToken(p)) + require.NoError(t, bearerToken.SignToken(&p.PrivateKey)) require.True(t, ownerID.Equal(bearerToken.Issuer())) }) } diff --git a/token/test/generate.go b/token/test/generate.go index 4e5926c..465f20b 100644 --- a/token/test/generate.go +++ b/token/test/generate.go @@ -1,10 +1,7 @@ package tokentest import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" eacltest "github.com/nspcc-dev/neofs-sdk-go/eacl/test" ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test" "github.com/nspcc-dev/neofs-sdk-go/token" @@ -29,12 +26,12 @@ func BearerToken() *token.BearerToken { func SignedBearerToken() *token.BearerToken { tok := BearerToken() - p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + p, err := keys.NewPrivateKey() if err != nil { panic(err) } - err = tok.SignToken(p) + err = tok.SignToken(&p.PrivateKey) if err != nil { panic(err) } diff --git a/util/signature/data.go b/util/signature/data.go index 7c14cdd..783c66e 100644 --- a/util/signature/data.go +++ b/util/signature/data.go @@ -4,6 +4,9 @@ import ( "crypto/ecdsa" "crypto/elliptic" "errors" + "fmt" + + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) type DataSource interface { @@ -72,8 +75,8 @@ func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySigna return err } - b := elliptic.MarshalCompressed(key.Curve, key.X, key.Y) - handler(b, sig) + pub := (*keys.PublicKey)(&key.PublicKey) + handler(pub.Bytes(), sig) return nil } @@ -93,16 +96,19 @@ func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts .. key, sig := sigSrc() - var pub *ecdsa.PublicKey + var pub *keys.PublicKey if len(key) != 0 { - x, y := elliptic.UnmarshalCompressed(elliptic.P256(), key) - if x == nil || y == nil { - return ErrInvalidPublicKey + pub, err = keys.NewPublicKeyFromBytes(key, elliptic.P256()) + if err != nil { + return fmt.Errorf("%w: %v", ErrInvalidPublicKey, err) } - pub = &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y} } - return cfg.verifyFunc(pub, data, sig) + return cfg.verifyFunc( + (*ecdsa.PublicKey)(pub), + data, + sig, + ) } func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) error { diff --git a/util/signature/options.go b/util/signature/options.go index 2878c77..c1cefee 100644 --- a/util/signature/options.go +++ b/util/signature/options.go @@ -8,7 +8,7 @@ import ( "crypto/sha512" "math/big" - "github.com/nspcc-dev/rfc6979" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) var curve = elliptic.P256() @@ -77,31 +77,15 @@ func SignWithRFC6979() SignOption { } func signRFC6979(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) { - digest := sha256.Sum256(msg) - r, s := rfc6979.SignECDSA(key, digest[:], sha256.New) - return getSignatureSlice(key.Curve, r, s), nil + p := &keys.PrivateKey{PrivateKey: *key} + return p.Sign(msg), nil } -func verifyRFC6979(pub *ecdsa.PublicKey, msg []byte, sig []byte) error { +func verifyRFC6979(key *ecdsa.PublicKey, msg []byte, sig []byte) error { + p := (*keys.PublicKey)(key) h := sha256.Sum256(msg) - if pub.X == nil || pub.Y == nil || len(sig) != 64 { - return ErrInvalidSignature - } - - rBytes := new(big.Int).SetBytes(sig[0:32]) - sBytes := new(big.Int).SetBytes(sig[32:64]) - if ecdsa.Verify(pub, h[:], rBytes, sBytes) { + if p.Verify(sig, h[:]) { return nil } return ErrInvalidSignature } - -func getSignatureSlice(curve elliptic.Curve, r, s *big.Int) []byte { - params := curve.Params() - curveOrderByteSize := params.P.BitLen() / 8 - signature := make([]byte, curveOrderByteSize*2) - _ = r.FillBytes(signature[:curveOrderByteSize]) - _ = s.FillBytes(signature[curveOrderByteSize:]) - - return signature -}