forked from TrueCloudLab/frostfs-crypto
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func MarshalPublicKey(key *ecdsa.PublicKey) []byte {
|
||||
if key == nil || key.X == nil || key.Y == nil {
|
||||
|
@ -150,7 +81,7 @@ func MarshalPublicKey(key *ecdsa.PublicKey) []byte {
|
|||
|
||||
// UnmarshalPublicKey from bytes.
|
||||
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{
|
||||
Curve: curve,
|
||||
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",
|
||||
}
|
||||
|
||||
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) {
|
||||
t.Run("prepared public keys: unmarshal / marshal", func(t *testing.T) {
|
||||
for i := range testKeys {
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,8 +3,8 @@ module github.com/nspcc-dev/neofs-crypto
|
|||
go 1.13
|
||||
|
||||
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/pkg/errors v0.8.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
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/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.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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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.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