2019-08-27 13:29:42 +00:00
|
|
|
package keys
|
2018-03-02 15:24:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/sha256"
|
2018-12-05 19:04:31 +00:00
|
|
|
"crypto/x509"
|
2018-03-02 15:24:09 +00:00
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
|
2020-12-02 12:52:31 +00:00
|
|
|
"github.com/btcsuite/btcd/btcec"
|
2021-03-25 12:22:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2019-08-27 10:00:03 +00:00
|
|
|
"github.com/nspcc-dev/rfc6979"
|
2018-03-02 15:24:09 +00:00
|
|
|
)
|
|
|
|
|
2020-07-14 05:40:39 +00:00
|
|
|
// PrivateKey represents a NEO private key and provides a high level API around
|
|
|
|
// ecdsa.PrivateKey.
|
2018-03-02 15:24:09 +00:00
|
|
|
type PrivateKey struct {
|
2020-07-14 05:40:39 +00:00
|
|
|
ecdsa.PrivateKey
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 12:52:31 +00:00
|
|
|
// NewPrivateKey creates a new random Secp256r1 private key.
|
2018-03-02 15:24:09 +00:00
|
|
|
func NewPrivateKey() (*PrivateKey, error) {
|
2020-12-02 12:52:31 +00:00
|
|
|
return newPrivateKeyOnCurve(elliptic.P256())
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSecp256k1PrivateKey creates a new random Secp256k1 private key.
|
|
|
|
func NewSecp256k1PrivateKey() (*PrivateKey, error) {
|
|
|
|
return newPrivateKeyOnCurve(btcec.S256())
|
|
|
|
}
|
|
|
|
|
|
|
|
// newPrivateKeyOnCurve creates a new random private key using curve c.
|
|
|
|
func newPrivateKeyOnCurve(c elliptic.Curve) (*PrivateKey, error) {
|
2021-06-17 18:54:46 +00:00
|
|
|
pk, err := ecdsa.GenerateKey(c, rand.Reader)
|
2019-09-04 21:12:39 +00:00
|
|
|
if err != nil {
|
2018-03-02 15:24:09 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-06-17 18:54:46 +00:00
|
|
|
return &PrivateKey{*pk}, nil
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 05:40:39 +00:00
|
|
|
// NewPrivateKeyFromHex returns a Secp256k1 PrivateKey created from the
|
2018-03-02 15:24:09 +00:00
|
|
|
// given hex string.
|
|
|
|
func NewPrivateKeyFromHex(str string) (*PrivateKey, error) {
|
|
|
|
b, err := hex.DecodeString(str)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return NewPrivateKeyFromBytes(b)
|
|
|
|
}
|
|
|
|
|
2020-07-14 05:40:39 +00:00
|
|
|
// NewPrivateKeyFromBytes returns a NEO Secp256r1 PrivateKey from the given
|
|
|
|
// byte slice.
|
2018-03-02 15:24:09 +00:00
|
|
|
func NewPrivateKeyFromBytes(b []byte) (*PrivateKey, error) {
|
|
|
|
if len(b) != 32 {
|
|
|
|
return nil, fmt.Errorf(
|
|
|
|
"invalid byte length: expected %d bytes got %d", 32, len(b),
|
|
|
|
)
|
|
|
|
}
|
2020-07-14 05:40:39 +00:00
|
|
|
var (
|
|
|
|
c = elliptic.P256()
|
|
|
|
d = new(big.Int).SetBytes(b)
|
|
|
|
)
|
|
|
|
|
2021-08-25 16:58:01 +00:00
|
|
|
x, y := c.ScalarBaseMult(b)
|
2020-07-14 05:40:39 +00:00
|
|
|
|
|
|
|
return &PrivateKey{
|
|
|
|
ecdsa.PrivateKey{
|
|
|
|
PublicKey: ecdsa.PublicKey{
|
|
|
|
Curve: c,
|
|
|
|
X: x,
|
|
|
|
Y: y,
|
|
|
|
},
|
|
|
|
D: d,
|
|
|
|
},
|
|
|
|
}, nil
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 05:40:39 +00:00
|
|
|
// NewPrivateKeyFromASN1 returns a NEO Secp256k1 PrivateKey from the ASN.1
|
|
|
|
// serialized key.
|
2019-10-10 13:45:30 +00:00
|
|
|
func NewPrivateKeyFromASN1(b []byte) (*PrivateKey, error) {
|
2018-12-05 19:04:31 +00:00
|
|
|
privkey, err := x509.ParseECPrivateKey(b)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-08-25 16:58:01 +00:00
|
|
|
return &PrivateKey{*privkey}, nil
|
2018-12-05 19:04:31 +00:00
|
|
|
}
|
|
|
|
|
2018-03-02 15:24:09 +00:00
|
|
|
// PublicKey derives the public key from the private key.
|
2019-09-05 06:35:02 +00:00
|
|
|
func (p *PrivateKey) PublicKey() *PublicKey {
|
2020-07-14 05:40:39 +00:00
|
|
|
result := PublicKey(p.PrivateKey.PublicKey)
|
|
|
|
return &result
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPrivateKeyFromWIF returns a NEO PrivateKey from the given
|
|
|
|
// WIF (wallet import format).
|
|
|
|
func NewPrivateKeyFromWIF(wif string) (*PrivateKey, error) {
|
|
|
|
w, err := WIFDecode(wif, WIFVersion)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return w.PrivateKey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WIF returns the (wallet import format) of the PrivateKey.
|
|
|
|
// Good documentation about this process can be found here:
|
|
|
|
// https://en.bitcoin.it/wiki/Wallet_import_format
|
2019-09-05 06:35:02 +00:00
|
|
|
func (p *PrivateKey) WIF() string {
|
2020-07-14 05:40:39 +00:00
|
|
|
w, err := WIFEncode(p.Bytes(), WIFVersion, true)
|
2019-09-05 06:35:02 +00:00
|
|
|
// The only way WIFEncode() can fail is if we're to give it a key of
|
|
|
|
// wrong size, but we have a proper key here, aren't we?
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return w
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Address derives the public NEO address that is coupled with the private key, and
|
|
|
|
// returns it as a string.
|
2019-09-05 06:35:02 +00:00
|
|
|
func (p *PrivateKey) Address() string {
|
|
|
|
pk := p.PublicKey()
|
|
|
|
return pk.Address()
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
2020-02-19 09:10:36 +00:00
|
|
|
// GetScriptHash returns verification script hash for public key associated with
|
|
|
|
// the private key.
|
|
|
|
func (p *PrivateKey) GetScriptHash() util.Uint160 {
|
2019-09-05 06:35:02 +00:00
|
|
|
pk := p.PublicKey()
|
2020-02-19 09:10:36 +00:00
|
|
|
return pk.GetScriptHash()
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
2020-08-29 15:44:45 +00:00
|
|
|
// Sign signs arbitrary length data using the private key. It uses SHA256 to
|
|
|
|
// calculate hash and then SignHash to create a signature (so you can save on
|
|
|
|
// hash calculation if you already have it).
|
2020-01-16 15:30:16 +00:00
|
|
|
func (p *PrivateKey) Sign(data []byte) []byte {
|
2020-08-29 15:44:45 +00:00
|
|
|
var digest = sha256.Sum256(data)
|
|
|
|
|
|
|
|
return p.SignHash(digest)
|
|
|
|
}
|
2018-03-02 15:24:09 +00:00
|
|
|
|
2020-08-29 15:44:45 +00:00
|
|
|
// SignHash signs particular hash the private key.
|
|
|
|
func (p *PrivateKey) SignHash(digest util.Uint256) []byte {
|
|
|
|
r, s := rfc6979.SignECDSA(&p.PrivateKey, digest[:], sha256.New)
|
|
|
|
return getSignatureSlice(p.PrivateKey.Curve, r, s)
|
2020-07-25 07:56:58 +00:00
|
|
|
}
|
2018-03-02 15:24:09 +00:00
|
|
|
|
2021-03-25 12:22:16 +00:00
|
|
|
// SignHashable signs some Hashable item for the network specified using
|
|
|
|
// hash.NetSha256() with the private key.
|
|
|
|
func (p *PrivateKey) SignHashable(net uint32, hh hash.Hashable) []byte {
|
|
|
|
return p.SignHash(hash.NetSha256(net, hh))
|
|
|
|
}
|
|
|
|
|
2020-07-25 07:56:58 +00:00
|
|
|
func getSignatureSlice(curve elliptic.Curve, r, s *big.Int) []byte {
|
|
|
|
params := curve.Params()
|
2018-03-02 15:24:09 +00:00
|
|
|
curveOrderByteSize := params.P.BitLen() / 8
|
|
|
|
rBytes, sBytes := r.Bytes(), s.Bytes()
|
|
|
|
signature := make([]byte, curveOrderByteSize*2)
|
|
|
|
copy(signature[curveOrderByteSize-len(rBytes):], rBytes)
|
|
|
|
copy(signature[curveOrderByteSize*2-len(sBytes):], sBytes)
|
|
|
|
|
2020-01-16 15:30:16 +00:00
|
|
|
return signature
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// String implements the stringer interface.
|
|
|
|
func (p *PrivateKey) String() string {
|
2020-07-14 05:40:39 +00:00
|
|
|
return hex.EncodeToString(p.Bytes())
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bytes returns the underlying bytes of the PrivateKey.
|
|
|
|
func (p *PrivateKey) Bytes() []byte {
|
2020-07-14 05:40:39 +00:00
|
|
|
bytes := p.D.Bytes()
|
|
|
|
result := make([]byte, 32)
|
|
|
|
copy(result[32-len(bytes):], bytes)
|
|
|
|
|
|
|
|
return result
|
2018-03-02 15:24:09 +00:00
|
|
|
}
|