github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/crypto/keys/private_key.go (about)

     1  package keys
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/sha256"
     8  	"crypto/x509"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"math/big"
    12  
    13  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    14  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    15  	"github.com/nspcc-dev/neo-go/pkg/util"
    16  	"github.com/nspcc-dev/neo-go/pkg/util/slice"
    17  	"github.com/nspcc-dev/rfc6979"
    18  )
    19  
    20  // PrivateKey represents a Neo private key and provides a high level API around
    21  // ecdsa.PrivateKey.
    22  type PrivateKey struct {
    23  	ecdsa.PrivateKey
    24  }
    25  
    26  // NewPrivateKey creates a new random Secp256r1 private key.
    27  func NewPrivateKey() (*PrivateKey, error) {
    28  	return newPrivateKeyOnCurve(elliptic.P256())
    29  }
    30  
    31  // NewSecp256k1PrivateKey creates a new random Secp256k1 private key.
    32  func NewSecp256k1PrivateKey() (*PrivateKey, error) {
    33  	return newPrivateKeyOnCurve(secp256k1.S256())
    34  }
    35  
    36  // newPrivateKeyOnCurve creates a new random private key using curve c.
    37  func newPrivateKeyOnCurve(c elliptic.Curve) (*PrivateKey, error) {
    38  	pk, err := ecdsa.GenerateKey(c, rand.Reader)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &PrivateKey{*pk}, nil
    43  }
    44  
    45  // NewPrivateKeyFromHex returns a Secp256k1 PrivateKey created from the
    46  // given hex string.
    47  func NewPrivateKeyFromHex(str string) (*PrivateKey, error) {
    48  	b, err := hex.DecodeString(str)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	defer slice.Clean(b)
    53  	return NewPrivateKeyFromBytes(b)
    54  }
    55  
    56  // NewPrivateKeyFromBytes returns a NEO Secp256r1 PrivateKey from the given
    57  // byte slice.
    58  func NewPrivateKeyFromBytes(b []byte) (*PrivateKey, error) {
    59  	if len(b) != 32 {
    60  		return nil, fmt.Errorf(
    61  			"invalid byte length: expected %d bytes got %d", 32, len(b),
    62  		)
    63  	}
    64  	var (
    65  		c = elliptic.P256()
    66  		d = new(big.Int).SetBytes(b)
    67  	)
    68  
    69  	x, y := c.ScalarBaseMult(b)
    70  
    71  	return &PrivateKey{
    72  		ecdsa.PrivateKey{
    73  			PublicKey: ecdsa.PublicKey{
    74  				Curve: c,
    75  				X:     x,
    76  				Y:     y,
    77  			},
    78  			D: d,
    79  		},
    80  	}, nil
    81  }
    82  
    83  // NewPrivateKeyFromASN1 returns a NEO Secp256k1 PrivateKey from the ASN.1
    84  // serialized key.
    85  func NewPrivateKeyFromASN1(b []byte) (*PrivateKey, error) {
    86  	privkey, err := x509.ParseECPrivateKey(b)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return &PrivateKey{*privkey}, nil
    91  }
    92  
    93  // PublicKey derives the public key from the private key.
    94  func (p *PrivateKey) PublicKey() *PublicKey {
    95  	result := PublicKey(p.PrivateKey.PublicKey)
    96  	return &result
    97  }
    98  
    99  // NewPrivateKeyFromWIF returns a NEO PrivateKey from the given
   100  // WIF (wallet import format).
   101  func NewPrivateKeyFromWIF(wif string) (*PrivateKey, error) {
   102  	w, err := WIFDecode(wif, WIFVersion)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	return w.PrivateKey, nil
   107  }
   108  
   109  // WIF returns the (wallet import format) of the PrivateKey.
   110  // Good documentation about this process can be found here:
   111  // https://en.bitcoin.it/wiki/Wallet_import_format
   112  func (p *PrivateKey) WIF() string {
   113  	pb := p.Bytes()
   114  	defer slice.Clean(pb)
   115  	w, err := WIFEncode(pb, WIFVersion, true)
   116  	// The only way WIFEncode() can fail is if we're to give it a key of
   117  	// wrong size, but we have a proper key here, aren't we?
   118  	if err != nil {
   119  		panic(err)
   120  	}
   121  	return w
   122  }
   123  
   124  // Destroy wipes the contents of the private key from memory. Any operations
   125  // with the key after call to Destroy have undefined behavior.
   126  func (p *PrivateKey) Destroy() {
   127  	bits := p.D.Bits()
   128  	for i := range bits {
   129  		bits[i] = 0
   130  	}
   131  }
   132  
   133  // Address derives the public NEO address that is coupled with the private key, and
   134  // returns it as a string.
   135  func (p *PrivateKey) Address() string {
   136  	pk := p.PublicKey()
   137  	return pk.Address()
   138  }
   139  
   140  // GetScriptHash returns verification script hash for the public key associated with
   141  // the private key.
   142  func (p *PrivateKey) GetScriptHash() util.Uint160 {
   143  	pk := p.PublicKey()
   144  	return pk.GetScriptHash()
   145  }
   146  
   147  // Sign signs arbitrary length data using the private key. It uses SHA256 to
   148  // calculate hash and then SignHash to create a signature (so you can save on
   149  // hash calculation if you already have it).
   150  func (p *PrivateKey) Sign(data []byte) []byte {
   151  	var digest = sha256.Sum256(data)
   152  
   153  	return p.SignHash(digest)
   154  }
   155  
   156  // SignHash signs a particular hash with the private key.
   157  func (p *PrivateKey) SignHash(digest util.Uint256) []byte {
   158  	r, s := rfc6979.SignECDSA(&p.PrivateKey, digest[:], sha256.New)
   159  	return getSignatureSlice(p.PrivateKey.Curve, r, s)
   160  }
   161  
   162  // SignHashable signs some Hashable item for the network specified using
   163  // hash.NetSha256() with the private key.
   164  func (p *PrivateKey) SignHashable(net uint32, hh hash.Hashable) []byte {
   165  	return p.SignHash(hash.NetSha256(net, hh))
   166  }
   167  
   168  func getSignatureSlice(curve elliptic.Curve, r, s *big.Int) []byte {
   169  	params := curve.Params()
   170  	curveOrderByteSize := params.P.BitLen() / 8
   171  	signature := make([]byte, curveOrderByteSize*2)
   172  	_ = r.FillBytes(signature[:curveOrderByteSize])
   173  	_ = s.FillBytes(signature[curveOrderByteSize:])
   174  
   175  	return signature
   176  }
   177  
   178  // String implements the stringer interface.
   179  func (p *PrivateKey) String() string {
   180  	return hex.EncodeToString(p.Bytes())
   181  }
   182  
   183  // Bytes returns the underlying bytes of the PrivateKey.
   184  func (p *PrivateKey) Bytes() []byte {
   185  	result := make([]byte, 32)
   186  	_ = p.D.FillBytes(result)
   187  
   188  	return result
   189  }