Skip to content

Commit

Permalink
Merge pull request #62 from make-software/release/v1.4.2
Browse files Browse the repository at this point in the history
Release/v1.4.2
  • Loading branch information
koltsov-iv authored Oct 19, 2023
2 parents a0132fc + 8d36571 commit 8041afc
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 133 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/quality-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Setup GO environment
run: |
go mod vendor
go install -v github.com/incu6us/goimports-reviser/v3.5.6
go install -v github.com/incu6us/goimports-reviser/v3@v3.5.6
go install github.com/golangci/golangci-lint/cmd/[email protected]
- name: Format
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/make-software/casper-go-sdk
go 1.19

require (
github.com/btcsuite/btcd v0.22.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
github.com/shopspring/decimal v1.3.1
github.com/stretchr/testify v1.8.2
golang.org/x/crypto v0.9.0
Expand Down
7 changes: 4 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand Down
20 changes: 20 additions & 0 deletions tests/types/keypair/private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,23 @@ func Test_SECPKey_CreateAndValidateRawSignature(t *testing.T) {
err = privateKeyData.PublicKey().VerifyRawSignature(secretMessage, signature)
assert.NoError(t, err)
}

func Test_ED25PKey_CreateAndValidateSignature(t *testing.T) {
secretMessage := []byte("Enigmatic Shadows Concealing Ancient Whispers")
privateKeyData, err := keypair.GeneratePrivateKey(keypair.ED25519)
require.NoError(t, err)
signature, err := privateKeyData.Sign(secretMessage)
require.NoError(t, err)
err = privateKeyData.PublicKey().VerifySignature(secretMessage, signature)
assert.NoError(t, err)
}

func Test_ED25Key_CreateAndValidateRawSignature(t *testing.T) {
secretMessage := []byte("Enigmatic Shadows Concealing Ancient Whispers")
privateKeyData, err := keypair.GeneratePrivateKey(keypair.ED25519)
require.NoError(t, err)
signature, err := privateKeyData.RawSign(secretMessage)
require.NoError(t, err)
err = privateKeyData.PublicKey().VerifyRawSignature(secretMessage, signature)
assert.NoError(t, err)
}
9 changes: 3 additions & 6 deletions types/keypair/private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func (v PrivateKey) PublicKey() PublicKey {
}

// Sign creates a Casper compatible cryptographic signature, including the algorithm tag prefix
func (v PrivateKey) Sign(mes []byte) ([]byte, error) {
sign, err := v.priv.Sign(mes)
func (v PrivateKey) Sign(msg []byte) ([]byte, error) {
sign, err := v.priv.Sign(msg)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -83,13 +83,10 @@ func GeneratePrivateKey(algorithm keyAlgorithm) (PrivateKey, error) {
return PrivateKey{}, err
}
case SECP256K1:
data, _, err := secp256k1.NewPemPair()
priv, err = secp256k1.GeneratePrivateKey()
if err != nil {
return PrivateKey{}, err
}
if priv, err = secp256k1.NewPrivateKeyFromPem(data); err != nil {
return PrivateKey{}, err
}
}
publicKey, err := NewPublicKeyFromBytes(append([]byte{byte(algorithm)}, priv.PublicKeyBytes()...))
if err != nil {
Expand Down
76 changes: 15 additions & 61 deletions types/keypair/secp256k1/pem_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ package secp256k1

import (
"crypto/elliptic"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"fmt"
"math/big"

"github.com/btcsuite/btcd/btcec"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
)

var oid = asn1.ObjectIdentifier{1, 3, 132, 0, 10}
Expand All @@ -20,13 +18,8 @@ type ecPrivateKey struct {
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
}

type pkixPublicKey struct {
Algo pkix.AlgorithmIdentifier
BitString asn1.BitString
}

func NewPemPair() ([]byte, []byte, error) {
priv, err := btcec.NewPrivateKey(btcec.S256())
priv, err := secp256k1.GeneratePrivateKey()
if err != nil {
return nil, nil, fmt.Errorf("creating new S256 private key")
}
Expand All @@ -44,7 +37,15 @@ func NewPemPair() ([]byte, []byte, error) {
return privKeyPem, pubKeyPem, nil
}

func PrivateKeyToPem(priv *btcec.PrivateKey) ([]byte, error) {
func GeneratePrivateKey() (PrivateKey, error) {
priv, err := secp256k1.GeneratePrivateKey()
if err != nil {
return PrivateKey{}, fmt.Errorf("creating new S256 private key")
}
return PrivateKey{key: priv}, nil
}

func PrivateKeyToPem(priv *secp256k1.PrivateKey) ([]byte, error) {
key := priv.ToECDSA()

privateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
Expand All @@ -66,7 +67,7 @@ func PrivateKeyToPem(priv *btcec.PrivateKey) ([]byte, error) {
), nil
}

func PemToPrivateKey(priv []byte) (*btcec.PrivateKey, error) {
func PemToPrivateKey(priv []byte) (*secp256k1.PrivateKey, error) {
block, _ := pem.Decode(priv)
if block == nil {
return nil, fmt.Errorf("key not found")
Expand All @@ -80,61 +81,14 @@ func PemToPrivateKey(priv []byte) (*btcec.PrivateKey, error) {
return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version)
}

curve := btcec.S256()

k := new(big.Int).SetBytes(privKey.PrivateKey)
curveOrder := curve.Params().N
if k.Cmp(curveOrder) >= 0 {
return nil, fmt.Errorf("x509: invalid elliptic curve private key value")
}

key := new(btcec.PrivateKey)
key.Curve = curve
key.D = k

privateKey := make([]byte, (curveOrder.BitLen()+7)/8)

for len(privKey.PrivateKey) > len(privateKey) {
if privKey.PrivateKey[0] != 0 {
return nil, fmt.Errorf("x509: invalid private key length")
}
privKey.PrivateKey = privKey.PrivateKey[1:]
}

copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
key.X, key.Y = curve.ScalarBaseMult(privateKey)

return key, nil
return secp256k1.PrivKeyFromBytes(privKey.PrivateKey), nil
}

func PublicKeyToPem(pub *btcec.PublicKey) ([]byte, error) {
pubEDSA := pub.ToECDSA()

var publicKeyAlgorithm pkix.AlgorithmIdentifier

publicKeyBytes := elliptic.Marshal(pubEDSA.Curve, pubEDSA.X, pubEDSA.Y)

publicKeyAlgorithm.Algorithm = oid
var paramBytes []byte
paramBytes, err := asn1.Marshal(oid)
if err != nil {
return nil, err
}

publicKeyAlgorithm.Parameters.FullBytes = paramBytes

pubBytes, _ := asn1.Marshal(pkixPublicKey{
Algo: publicKeyAlgorithm,
BitString: asn1.BitString{
Bytes: publicKeyBytes,
BitLength: 8 * len(publicKeyBytes),
},
})

func PublicKeyToPem(pub *secp256k1.PublicKey) ([]byte, error) {
return pem.EncodeToMemory(
&pem.Block{
Type: "EC PUBLIC KEY",
Bytes: pubBytes,
Bytes: pub.SerializeUncompressed(),
},
), nil
}
25 changes: 5 additions & 20 deletions types/keypair/secp256k1/private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (
"errors"
"os"

"github.com/btcsuite/btcd/btcec"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
)

type PrivateKey struct {
key *btcec.PrivateKey
key *secp256k1.PrivateKey
}

func (v PrivateKey) PublicKeyBytes() []byte {
Expand All @@ -18,12 +19,8 @@ func (v PrivateKey) PublicKeyBytes() []byte {

func (v PrivateKey) Sign(mes []byte) ([]byte, error) {
hash := sha256.Sum256(mes)
sig, err := v.key.Sign(hash[:])
if err != nil {
return nil, err
}

return serializeSig(sig), nil
// Return the signature as a concatenation of the R and S values in big-endian to match the old signature format.
return ecdsa.SignCompact(v.key, hash[:], false)[1:], nil
}

func NewPrivateKeyFromPemFile(path string) (PrivateKey, error) {
Expand All @@ -44,15 +41,3 @@ func NewPrivateKeyFromPem(content []byte) (PrivateKey, error) {
key: private,
}, nil
}

// Serialize signature to R || S.
// R, S are padded to 32 bytes respectively.
func serializeSig(sig *btcec.Signature) []byte {
rBytes := sig.R.Bytes()
sBytes := sig.S.Bytes()
sigBytes := make([]byte, 64)
// 0 pad the byte arrays from the left if they aren't big enough.
copy(sigBytes[32-len(rBytes):32], rBytes)
copy(sigBytes[64-len(sBytes):64], sBytes)
return sigBytes
}
71 changes: 31 additions & 40 deletions types/keypair/secp256k1/public_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,66 +3,57 @@ package secp256k1
import (
"crypto/sha256"
"fmt"
"math/big"
"log"

"github.com/btcsuite/btcd/btcec"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
)

const PublicKeySize = 33

// used to reject malleable signatures
// see:
// - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
// - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/crypto.go#L39
var secp256k1halfN = new(big.Int).Rsh(btcec.S256().N, 1)

type PublicKey btcec.PublicKey
type PublicKey struct {
key *secp256k1.PublicKey
}

func (v PublicKey) Bytes() []byte {
key := btcec.PublicKey(v)
return key.SerializeCompressed()
return v.key.SerializeCompressed()
}

// VerifySignature verifies a signature of the form R || S.
// It rejects signatures which are not in lower-S form.
func (v PublicKey) VerifySignature(msg []byte, sigStr []byte) bool {
if len(sigStr) != 64 {
return false
}

pub, err := btcec.ParsePubKey(v.Bytes(), btcec.S256())
if err != nil {
return false
}

// parse the signature:
signature := signatureFromBytes(sigStr)
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
// see: https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
if signature.S.Cmp(secp256k1halfN) > 0 {
return false
}

sum256 := sha256.Sum256(msg)
return signature.Verify(sum256[:], pub)
}

// Read Signature struct from R || S. Caller needs to ensure
// that len(sigStr) == 64.
func signatureFromBytes(sigStr []byte) *btcec.Signature {
return &btcec.Signature{
R: new(big.Int).SetBytes(sigStr[:32]),
S: new(big.Int).SetBytes(sigStr[32:64]),
var signature *ecdsa.Signature
var err error
// if old signature len = 64, parse it as raw signature
if len(sigStr) == 64 {
// Split the signature bytes into r and s values and parse them into ModNScalar
var r, s secp256k1.ModNScalar
var bytesR [32]byte
var bytesS [32]byte
copy(bytesR[:], sigStr[:32])
copy(bytesS[:], sigStr[32:])
r.SetBytes(&bytesR)
s.SetBytes(&bytesS)

signature = ecdsa.NewSignature(&r, &s)
} else {
signature, err = ecdsa.ParseDERSignature(sigStr)
if err != nil {
log.Println(err)
return false
}
}
hash := sha256.Sum256(msg)
return signature.Verify(hash[:], v.key)
}

func NewPublicKey(data []byte) (PublicKey, error) {
if len(data) != PublicKeySize {
return PublicKey{}, fmt.Errorf("can't parse wrong size of public key: %d", len(data))
}
key, err := btcec.ParsePubKey(data, btcec.S256())
key, err := secp256k1.ParsePubKey(data)
if err != nil {
return PublicKey{}, err
}
return PublicKey(*key), err
return PublicKey{key: key}, err
}
2 changes: 1 addition & 1 deletion types/unbonding_purse.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ type UnbondingPurse struct {
// The original validator's public key.
ValidatorPublicKey keypair.PublicKey `json:"validator_public_key"`
// The re-delegated validator's public key.
NewValidator keypair.PublicKey `json:"new_validator"`
NewValidator *keypair.PublicKey `json:"new_validator"`
}

0 comments on commit 8041afc

Please sign in to comment.