Refactoring for go1.15+
- use elliptic.MarshalCompressed - use elliptic.UnmarshalCompressed - for older go versions use old methods - update dependencies - github.com/mr-tron/base58 v1.2.0 - github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.7.0 Signed-off-by: Evgeniy Kulikov <kim@nspcc.ru>
This commit is contained in:
parent
357aa98aa2
commit
e9d1b1884c
7 changed files with 153 additions and 89 deletions
71
ecdsa.go
71
ecdsa.go
|
@ -70,75 +70,6 @@ func unmarshalXY(data []byte) (x *big.Int, y *big.Int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decompressPoints using formula y² = x³ - 3x + b
|
|
||||||
// crypto/elliptic/elliptic.go:55
|
|
||||||
func decompressPoints(x *big.Int, yBit uint) (*big.Int, *big.Int) {
|
|
||||||
params := curve.Params()
|
|
||||||
|
|
||||||
x3 := new(big.Int).Mul(x, x)
|
|
||||||
x3.Mul(x3, x)
|
|
||||||
|
|
||||||
threeX := new(big.Int).Lsh(x, 1)
|
|
||||||
threeX.Add(threeX, x)
|
|
||||||
|
|
||||||
x3.Sub(x3, threeX)
|
|
||||||
x3.Add(x3, params.B)
|
|
||||||
x3.Mod(x3, params.P)
|
|
||||||
|
|
||||||
// y = √(x³ - 3x + b) mod p
|
|
||||||
y := new(big.Int).ModSqrt(x3, params.P)
|
|
||||||
|
|
||||||
// big.Int.Jacobi(a, b) can return nil
|
|
||||||
if y == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if y.Bit(0) != (yBit & 0x1) {
|
|
||||||
y.Neg(y)
|
|
||||||
y.Mod(y, params.P)
|
|
||||||
}
|
|
||||||
|
|
||||||
return x, y
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodePoint(x, y *big.Int) []byte {
|
|
||||||
data := make([]byte, PublicKeyCompressedSize)
|
|
||||||
i := PublicKeyCompressedSize - len(x.Bytes())
|
|
||||||
copy(data[i:], x.Bytes())
|
|
||||||
|
|
||||||
if y.Bit(0) == 0x1 {
|
|
||||||
data[0] = 0x3
|
|
||||||
} else {
|
|
||||||
data[0] = 0x2
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodePoint(data []byte) (*big.Int, *big.Int) {
|
|
||||||
// empty data
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch prefix := data[0]; prefix {
|
|
||||||
case 0x02, 0x03: // compressed key
|
|
||||||
// Incorrect length for compressed encoding
|
|
||||||
if len(data) != PublicKeyCompressedSize {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return decompressPoints(new(big.Int).SetBytes(data[1:]), uint(prefix))
|
|
||||||
case 0x04: // uncompressed key
|
|
||||||
// To get the public key, besides getting it from the data and checking,
|
|
||||||
// we also must to check that the points are on an elliptic curve
|
|
||||||
return unmarshalXY(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unknown type
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalPublicKey to bytes.
|
// MarshalPublicKey to bytes.
|
||||||
func MarshalPublicKey(key *ecdsa.PublicKey) []byte {
|
func MarshalPublicKey(key *ecdsa.PublicKey) []byte {
|
||||||
if key == nil || key.X == nil || key.Y == nil {
|
if key == nil || key.X == nil || key.Y == nil {
|
||||||
|
@ -150,7 +81,7 @@ func MarshalPublicKey(key *ecdsa.PublicKey) []byte {
|
||||||
|
|
||||||
// UnmarshalPublicKey from bytes.
|
// UnmarshalPublicKey from bytes.
|
||||||
func UnmarshalPublicKey(data []byte) *ecdsa.PublicKey {
|
func UnmarshalPublicKey(data []byte) *ecdsa.PublicKey {
|
||||||
if x, y := decodePoint(data); x != nil && y != nil && curve.IsOnCurve(x, y) {
|
if x, y := decodePoint(data); x != nil && y != nil {
|
||||||
return &ecdsa.PublicKey{
|
return &ecdsa.PublicKey{
|
||||||
Curve: curve,
|
Curve: curve,
|
||||||
X: x,
|
X: x,
|
||||||
|
|
34
ecdsa_go1.15.go
Normal file
34
ecdsa_go1.15.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// +build go1.15
|
||||||
|
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/elliptic"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func encodePoint(x, y *big.Int) []byte {
|
||||||
|
return elliptic.MarshalCompressed(curve, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePoint(data []byte) (x *big.Int, y *big.Int) {
|
||||||
|
// empty data
|
||||||
|
if len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// tries to unmarshal compressed form
|
||||||
|
// returns (nil, nil) when:
|
||||||
|
// - wrong len(data)
|
||||||
|
// - data[0] != 2 && data[0] != 3
|
||||||
|
if x, y = elliptic.UnmarshalCompressed(curve, data); x != nil && y != nil {
|
||||||
|
return x, y
|
||||||
|
}
|
||||||
|
|
||||||
|
// tries to unmarshal uncompressed form and check that points on curve
|
||||||
|
if x, y = unmarshalXY(data); x == nil || y == nil || !curve.IsOnCurve(x, y) {
|
||||||
|
x, y = nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
}
|
79
ecdsa_older_go.go
Normal file
79
ecdsa_older_go.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// +build !go1.15
|
||||||
|
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import "math/big"
|
||||||
|
|
||||||
|
// decompressPoints using formula y² = x³ - 3x + b
|
||||||
|
// crypto/elliptic/elliptic.go:55
|
||||||
|
func decompressPoints(x *big.Int, yBit uint) (*big.Int, *big.Int) {
|
||||||
|
params := curve.Params()
|
||||||
|
|
||||||
|
x3 := new(big.Int).Mul(x, x)
|
||||||
|
x3.Mul(x3, x)
|
||||||
|
|
||||||
|
threeX := new(big.Int).Lsh(x, 1)
|
||||||
|
threeX.Add(threeX, x)
|
||||||
|
|
||||||
|
x3.Sub(x3, threeX)
|
||||||
|
x3.Add(x3, params.B)
|
||||||
|
x3.Mod(x3, params.P)
|
||||||
|
|
||||||
|
// y = √(x³ - 3x + b) mod p
|
||||||
|
y := new(big.Int).ModSqrt(x3, params.P)
|
||||||
|
|
||||||
|
// big.Int.Jacobi(a, b) can return nil
|
||||||
|
if y == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if y.Bit(0) != (yBit & 0x1) {
|
||||||
|
y.Neg(y)
|
||||||
|
y.Mod(y, params.P)
|
||||||
|
}
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodePoint(x, y *big.Int) []byte {
|
||||||
|
data := make([]byte, PublicKeyCompressedSize)
|
||||||
|
i := PublicKeyCompressedSize - len(x.Bytes())
|
||||||
|
copy(data[i:], x.Bytes())
|
||||||
|
|
||||||
|
if y.Bit(0) == 0x1 {
|
||||||
|
data[0] = 0x3
|
||||||
|
} else {
|
||||||
|
data[0] = 0x2
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePoint(data []byte) (x *big.Int, y *big.Int) {
|
||||||
|
// empty data
|
||||||
|
if len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch prefix := data[0]; prefix {
|
||||||
|
case 0x02, 0x03: // compressed key
|
||||||
|
// Incorrect length for compressed encoding
|
||||||
|
if len(data) != PublicKeyCompressedSize {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y = decompressPoints(new(big.Int).SetBytes(data[1:]), uint(prefix))
|
||||||
|
case 0x04: // uncompressed key
|
||||||
|
// To get the public key, besides getting it from the data and checking,
|
||||||
|
// we also must to check that the points are on an elliptic curve
|
||||||
|
x, y = unmarshalXY(data)
|
||||||
|
default: // unknown type
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if x == nil || y == nil || !curve.IsOnCurve(x, y) {
|
||||||
|
x, y = nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
28
ecdsa_older_go_test.go
Normal file
28
ecdsa_older_go_test.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// +build !go1.15
|
||||||
|
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_decompressPoints(t *testing.T) {
|
||||||
|
t.Run("prepared public keys: decompressPoints", func(t *testing.T) {
|
||||||
|
for i := range testKeys {
|
||||||
|
bytes, err := hex.DecodeString(testKeys[i])
|
||||||
|
require.NoErrorf(t, err, testKeys[i])
|
||||||
|
|
||||||
|
x, y := decompressPoints(new(big.Int).SetBytes(bytes[1:]), uint(bytes[0]))
|
||||||
|
require.NotNil(t, x)
|
||||||
|
require.NotNil(t, y)
|
||||||
|
|
||||||
|
res := MarshalPublicKey(&ecdsa.PublicKey{Curve: curve, X: x, Y: y})
|
||||||
|
require.Equal(t, testKeys[i], hex.EncodeToString(res))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -30,22 +30,6 @@ var testKeys = [...]string{
|
||||||
"02a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61",
|
"02a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61",
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decompressPoints(t *testing.T) {
|
|
||||||
t.Run("prepared public keys: decompressPoints", func(t *testing.T) {
|
|
||||||
for i := range testKeys {
|
|
||||||
bytes, err := hex.DecodeString(testKeys[i])
|
|
||||||
require.NoErrorf(t, err, testKeys[i])
|
|
||||||
|
|
||||||
x, y := decompressPoints(new(big.Int).SetBytes(bytes[1:]), uint(bytes[0]))
|
|
||||||
require.NotNil(t, x)
|
|
||||||
require.NotNil(t, y)
|
|
||||||
|
|
||||||
res := MarshalPublicKey(&ecdsa.PublicKey{Curve: curve, X: x, Y: y})
|
|
||||||
require.Equal(t, testKeys[i], hex.EncodeToString(res))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMarshalUnmarshal(t *testing.T) {
|
func TestMarshalUnmarshal(t *testing.T) {
|
||||||
t.Run("prepared public keys: unmarshal / marshal", func(t *testing.T) {
|
t.Run("prepared public keys: unmarshal / marshal", func(t *testing.T) {
|
||||||
for i := range testKeys {
|
for i := range testKeys {
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -3,8 +3,8 @@ module github.com/nspcc-dev/neofs-crypto
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/mr-tron/base58 v1.1.2
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0
|
github.com/nspcc-dev/rfc6979 v0.2.0
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.7.0
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -2,16 +2,24 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
|
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
|
||||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
|
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||||
|
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
Loading…
Reference in a new issue