254
vendor/github.com/status-im/status-go/eth-node/crypto/crypto.go
generated
vendored
Normal file
254
vendor/github.com/status-im/status-go/eth-node/crypto/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
types "github.com/status-im/status-go/eth-node/types"
|
||||
|
||||
gethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
aesNonceLength = 12
|
||||
)
|
||||
|
||||
// Sign calculates an ECDSA signature.
|
||||
//
|
||||
// This function is susceptible to chosen plaintext attacks that can leak
|
||||
// information about the private key that is used for signing. Callers must
|
||||
// be aware that the given digest cannot be chosen by an adversery. Common
|
||||
// solution is to hash any input before calculating the signature.
|
||||
//
|
||||
// The produced signature is in the [R || S || V] format where V is 0 or 1.
|
||||
func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||
return gethcrypto.Sign(digestHash, prv)
|
||||
}
|
||||
|
||||
// SignBytes signs the hash of arbitrary data.
|
||||
func SignBytes(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||
return Sign(Keccak256(data), prv)
|
||||
}
|
||||
|
||||
// SignBytesAsHex signs the Keccak256 hash of arbitrary data and returns its hex representation.
|
||||
func SignBytesAsHex(data []byte, identity *ecdsa.PrivateKey) (string, error) {
|
||||
signature, err := SignBytes(data, identity)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(signature), nil
|
||||
}
|
||||
|
||||
// SignStringAsHex signs the Keccak256 hash of arbitrary string and returns its hex representation.
|
||||
func SignStringAsHex(data string, identity *ecdsa.PrivateKey) (string, error) {
|
||||
return SignBytesAsHex([]byte(data), identity)
|
||||
}
|
||||
|
||||
// VerifySignatures verifies tuples of signatures content/hash/public key
|
||||
func VerifySignatures(signaturePairs [][3]string) error {
|
||||
for _, signaturePair := range signaturePairs {
|
||||
content := Keccak256([]byte(signaturePair[0]))
|
||||
|
||||
signature, err := hex.DecodeString(signaturePair[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicKeyBytes, err := hex.DecodeString(signaturePair[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicKey, err := UnmarshalPubkey(publicKeyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recoveredKey, err := SigToPub(
|
||||
content,
|
||||
signature,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if PubkeyToAddress(*recoveredKey) != PubkeyToAddress(*publicKey) {
|
||||
return errors.New("identity key and signature mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractSignatures extract from tuples of signatures content a public key
|
||||
// DEPRECATED: use ExtractSignature
|
||||
func ExtractSignatures(signaturePairs [][2]string) ([]string, error) {
|
||||
response := make([]string, len(signaturePairs))
|
||||
for i, signaturePair := range signaturePairs {
|
||||
content := Keccak256([]byte(signaturePair[0]))
|
||||
|
||||
signature, err := hex.DecodeString(signaturePair[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recoveredKey, err := SigToPub(
|
||||
content,
|
||||
signature,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response[i] = fmt.Sprintf("%x", FromECDSAPub(recoveredKey))
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ExtractSignature returns a public key for a given data and signature.
|
||||
func ExtractSignature(data, signature []byte) (*ecdsa.PublicKey, error) {
|
||||
dataHash := Keccak256(data)
|
||||
return SigToPub(dataHash, signature)
|
||||
}
|
||||
|
||||
func EncryptSymmetric(key, plaintext []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
|
||||
salt, err := generateSecureRandomData(aesNonceLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := aesgcm.Seal(nil, salt, plaintext, nil)
|
||||
return append(encrypted, salt...), nil
|
||||
}
|
||||
|
||||
func DecryptSymmetric(key []byte, cyphertext []byte) ([]byte, error) {
|
||||
// symmetric messages are expected to contain the 12-byte nonce at the end of the payload
|
||||
if len(cyphertext) < aesNonceLength {
|
||||
return nil, errors.New("missing salt or invalid payload in symmetric message")
|
||||
}
|
||||
salt := cyphertext[len(cyphertext)-aesNonceLength:]
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decrypted, err := aesgcm.Open(nil, salt, cyphertext[:len(cyphertext)-aesNonceLength], nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
func containsOnlyZeros(data []byte) bool {
|
||||
for _, b := range data {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func validateDataIntegrity(k []byte, expectedSize int) bool {
|
||||
if len(k) != expectedSize {
|
||||
return false
|
||||
}
|
||||
if containsOnlyZeros(k) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func generateSecureRandomData(length int) ([]byte, error) {
|
||||
res := make([]byte, length)
|
||||
|
||||
_, err := rand.Read(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !validateDataIntegrity(res, length) {
|
||||
return nil, errors.New("crypto/rand failed to generate secure random data")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// TextHash is a helper function that calculates a hash for the given message that can be
|
||||
// safely used to calculate a signature from.
|
||||
//
|
||||
// The hash is calulcated as
|
||||
//
|
||||
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
||||
//
|
||||
// This gives context to the signed message and prevents signing of transactions.
|
||||
func TextHash(data []byte) []byte {
|
||||
hash, _ := TextAndHash(data)
|
||||
return hash
|
||||
}
|
||||
|
||||
// TextAndHash is a helper function that calculates a hash for the given message that can be
|
||||
// safely used to calculate a signature from.
|
||||
//
|
||||
// The hash is calulcated as
|
||||
//
|
||||
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
||||
//
|
||||
// This gives context to the signed message and prevents signing of transactions.
|
||||
func TextAndHash(data []byte) ([]byte, string) {
|
||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data))
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
_, _ = hasher.Write([]byte(msg))
|
||||
return hasher.Sum(nil), msg
|
||||
}
|
||||
|
||||
func EcRecover(ctx context.Context, data types.HexBytes, sig types.HexBytes) (types.Address, error) {
|
||||
// Returns the address for the Account that was used to create the signature.
|
||||
//
|
||||
// Note, this function is compatible with eth_sign and personal_sign. As such it recovers
|
||||
// the address of:
|
||||
// hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}")
|
||||
// addr = ecrecover(hash, signature)
|
||||
//
|
||||
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
|
||||
// the V value must be be 27 or 28 for legacy reasons.
|
||||
//
|
||||
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
||||
if len(sig) != 65 {
|
||||
return types.Address{}, fmt.Errorf("signature must be 65 bytes long")
|
||||
}
|
||||
if sig[64] != 27 && sig[64] != 28 {
|
||||
return types.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
||||
}
|
||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||
hash := TextHash(data)
|
||||
rpk, err := SigToPub(hash, sig)
|
||||
if err != nil {
|
||||
return types.Address{}, err
|
||||
}
|
||||
return PubkeyToAddress(*rpk), nil
|
||||
}
|
||||
366
vendor/github.com/status-im/status-go/eth-node/crypto/ecies/ecies.go
generated
vendored
Normal file
366
vendor/github.com/status-im/status-go/eth-node/crypto/ecies/ecies.go
generated
vendored
Normal file
@@ -0,0 +1,366 @@
|
||||
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
|
||||
// Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package ecies
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrImport = fmt.Errorf("ecies: failed to import key")
|
||||
ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
|
||||
ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters")
|
||||
ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
|
||||
ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
|
||||
ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big")
|
||||
)
|
||||
|
||||
// PublicKey is a representation of an elliptic curve public key.
|
||||
type PublicKey struct {
|
||||
X *big.Int
|
||||
Y *big.Int
|
||||
elliptic.Curve
|
||||
Params *ECIESParams
|
||||
}
|
||||
|
||||
// Export an ECIES public key as an ECDSA public key.
|
||||
func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
|
||||
return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}
|
||||
}
|
||||
|
||||
// Import an ECDSA public key as an ECIES public key.
|
||||
func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
|
||||
return &PublicKey{
|
||||
X: pub.X,
|
||||
Y: pub.Y,
|
||||
Curve: pub.Curve,
|
||||
Params: ParamsFromCurve(pub.Curve),
|
||||
}
|
||||
}
|
||||
|
||||
// PrivateKey is a representation of an elliptic curve private key.
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
// Export an ECIES private key as an ECDSA private key.
|
||||
func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
|
||||
pub := &prv.PublicKey
|
||||
pubECDSA := pub.ExportECDSA()
|
||||
return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}
|
||||
}
|
||||
|
||||
// Import an ECDSA private key as an ECIES private key.
|
||||
func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
|
||||
pub := ImportECDSAPublic(&prv.PublicKey)
|
||||
return &PrivateKey{*pub, prv.D}
|
||||
}
|
||||
|
||||
// Generate an elliptic curve public / private keypair. If params is nil,
|
||||
// the recommended default parameters for the key will be chosen.
|
||||
func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
|
||||
pb, x, y, err := elliptic.GenerateKey(curve, rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
prv = new(PrivateKey)
|
||||
prv.PublicKey.X = x
|
||||
prv.PublicKey.Y = y
|
||||
prv.PublicKey.Curve = curve
|
||||
prv.D = new(big.Int).SetBytes(pb)
|
||||
if params == nil {
|
||||
params = ParamsFromCurve(curve)
|
||||
}
|
||||
prv.PublicKey.Params = params
|
||||
return
|
||||
}
|
||||
|
||||
// MaxSharedKeyLength returns the maximum length of the shared key the
|
||||
// public key can produce.
|
||||
func MaxSharedKeyLength(pub *PublicKey) int {
|
||||
return (pub.Curve.Params().BitSize + 7) / 8
|
||||
}
|
||||
|
||||
// ECDH key agreement method used to establish secret keys for encryption.
|
||||
func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
|
||||
if prv.PublicKey.Curve != pub.Curve {
|
||||
return nil, ErrInvalidCurve
|
||||
}
|
||||
if skLen+macLen > MaxSharedKeyLength(pub) {
|
||||
return nil, ErrSharedKeyTooBig
|
||||
}
|
||||
|
||||
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
|
||||
if x == nil {
|
||||
return nil, ErrSharedKeyIsPointAtInfinity
|
||||
}
|
||||
|
||||
sk = make([]byte, skLen+macLen)
|
||||
skBytes := x.Bytes()
|
||||
copy(sk[len(sk)-len(skBytes):], skBytes)
|
||||
return sk, nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
|
||||
ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
|
||||
ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
|
||||
)
|
||||
|
||||
var (
|
||||
big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
|
||||
big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
|
||||
)
|
||||
|
||||
func incCounter(ctr []byte) {
|
||||
if ctr[3]++; ctr[3] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[2]++; ctr[2] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[1]++; ctr[1] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[0]++; ctr[0] != 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
|
||||
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
|
||||
if s1 == nil {
|
||||
s1 = make([]byte, 0)
|
||||
}
|
||||
|
||||
reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
|
||||
if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
|
||||
fmt.Println(big2To32M1)
|
||||
return nil, ErrKeyDataTooLong
|
||||
}
|
||||
|
||||
counter := []byte{0, 0, 0, 1}
|
||||
k = make([]byte, 0)
|
||||
|
||||
for i := 0; i <= reps; i++ {
|
||||
hash.Write(counter)
|
||||
hash.Write(z)
|
||||
hash.Write(s1)
|
||||
k = append(k, hash.Sum(nil)...)
|
||||
hash.Reset()
|
||||
incCounter(counter)
|
||||
}
|
||||
|
||||
k = k[:kdLen]
|
||||
return
|
||||
}
|
||||
|
||||
// messageTag computes the MAC of a message (called the tag) as per
|
||||
// SEC 1, 3.5.
|
||||
func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
|
||||
mac := hmac.New(hash, km)
|
||||
mac.Write(msg)
|
||||
mac.Write(shared)
|
||||
tag := mac.Sum(nil)
|
||||
return tag
|
||||
}
|
||||
|
||||
// Generate an initialisation vector for CTR mode.
|
||||
func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
|
||||
iv = make([]byte, params.BlockSize)
|
||||
_, err = io.ReadFull(rand, iv)
|
||||
return
|
||||
}
|
||||
|
||||
// symEncrypt carries out CTR encryption using the block cipher specified in the
|
||||
// parameters.
|
||||
func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
|
||||
c, err := params.Cipher(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
iv, err := generateIV(params, rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ctr := cipher.NewCTR(c, iv)
|
||||
|
||||
ct = make([]byte, len(m)+params.BlockSize)
|
||||
copy(ct, iv)
|
||||
ctr.XORKeyStream(ct[params.BlockSize:], m)
|
||||
return
|
||||
}
|
||||
|
||||
// symDecrypt carries out CTR decryption using the block cipher specified in
|
||||
// the parameters
|
||||
func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
|
||||
c, err := params.Cipher(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctr := cipher.NewCTR(c, ct[:params.BlockSize])
|
||||
|
||||
m = make([]byte, len(ct)-params.BlockSize)
|
||||
ctr.XORKeyStream(m, ct[params.BlockSize:])
|
||||
return
|
||||
}
|
||||
|
||||
// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.
|
||||
//
|
||||
// s1 and s2 contain shared information that is not part of the resulting
|
||||
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
|
||||
// shared information parameters aren't being used, they should be nil.
|
||||
func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
|
||||
params := pub.Params
|
||||
if params == nil {
|
||||
if params = ParamsFromCurve(pub.Curve); params == nil {
|
||||
err = ErrUnsupportedECIESParameters
|
||||
return
|
||||
}
|
||||
}
|
||||
R, err := GenerateKey(rand, pub.Curve, params)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash := params.Hash()
|
||||
z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
Ke := K[:params.KeyLen]
|
||||
Km := K[params.KeyLen:]
|
||||
hash.Write(Km)
|
||||
Km = hash.Sum(nil)
|
||||
hash.Reset()
|
||||
|
||||
em, err := symEncrypt(rand, params, Ke, m)
|
||||
if err != nil || len(em) <= params.BlockSize {
|
||||
return
|
||||
}
|
||||
|
||||
d := messageTag(params.Hash, Km, em, s2)
|
||||
|
||||
Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
|
||||
ct = make([]byte, len(Rb)+len(em)+len(d))
|
||||
copy(ct, Rb)
|
||||
copy(ct[len(Rb):], em)
|
||||
copy(ct[len(Rb)+len(em):], d)
|
||||
return
|
||||
}
|
||||
|
||||
// Decrypt decrypts an ECIES ciphertext.
|
||||
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
|
||||
if len(c) == 0 {
|
||||
return nil, ErrInvalidMessage
|
||||
}
|
||||
params := prv.PublicKey.Params
|
||||
if params == nil {
|
||||
if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
|
||||
err = ErrUnsupportedECIESParameters
|
||||
return
|
||||
}
|
||||
}
|
||||
hash := params.Hash()
|
||||
|
||||
var (
|
||||
rLen int
|
||||
hLen int = hash.Size()
|
||||
mStart int
|
||||
mEnd int
|
||||
)
|
||||
|
||||
switch c[0] {
|
||||
case 2, 3, 4:
|
||||
rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
|
||||
if len(c) < (rLen + hLen + 1) {
|
||||
err = ErrInvalidMessage
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = ErrInvalidPublicKey
|
||||
return
|
||||
}
|
||||
|
||||
mStart = rLen
|
||||
mEnd = len(c) - hLen
|
||||
|
||||
R := new(PublicKey)
|
||||
R.Curve = prv.PublicKey.Curve
|
||||
R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
|
||||
if R.X == nil {
|
||||
err = ErrInvalidPublicKey
|
||||
return
|
||||
}
|
||||
if !R.Curve.IsOnCurve(R.X, R.Y) {
|
||||
err = ErrInvalidCurve
|
||||
return
|
||||
}
|
||||
|
||||
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
Ke := K[:params.KeyLen]
|
||||
Km := K[params.KeyLen:]
|
||||
hash.Write(Km)
|
||||
Km = hash.Sum(nil)
|
||||
hash.Reset()
|
||||
|
||||
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
|
||||
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
|
||||
err = ErrInvalidMessage
|
||||
return
|
||||
}
|
||||
|
||||
m, err = symDecrypt(params, Ke, c[mStart:mEnd])
|
||||
return
|
||||
}
|
||||
117
vendor/github.com/status-im/status-go/eth-node/crypto/ecies/params.go
generated
vendored
Normal file
117
vendor/github.com/status-im/status-go/eth-node/crypto/ecies/params.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
|
||||
// Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package ecies
|
||||
|
||||
// This file contains parameters for ECIES encryption, specifying the
|
||||
// symmetric encryption and HMAC parameters.
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
gethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultCurve = gethcrypto.S256()
|
||||
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
|
||||
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
|
||||
)
|
||||
|
||||
type ECIESParams struct {
|
||||
Hash func() hash.Hash // hash function
|
||||
hashAlgo crypto.Hash
|
||||
Cipher func([]byte) (cipher.Block, error) // symmetric cipher
|
||||
BlockSize int // block size of symmetric cipher
|
||||
KeyLen int // length of symmetric key
|
||||
}
|
||||
|
||||
// Standard ECIES parameters:
|
||||
// * ECIES using AES128 and HMAC-SHA-256-16
|
||||
// * ECIES using AES256 and HMAC-SHA-256-32
|
||||
// * ECIES using AES256 and HMAC-SHA-384-48
|
||||
// * ECIES using AES256 and HMAC-SHA-512-64
|
||||
|
||||
var (
|
||||
ECIES_AES128_SHA256 = &ECIESParams{
|
||||
Hash: sha256.New,
|
||||
hashAlgo: crypto.SHA256,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 16,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA256 = &ECIESParams{
|
||||
Hash: sha256.New,
|
||||
hashAlgo: crypto.SHA256,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA384 = &ECIESParams{
|
||||
Hash: sha512.New384,
|
||||
hashAlgo: crypto.SHA384,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA512 = &ECIESParams{
|
||||
Hash: sha512.New,
|
||||
hashAlgo: crypto.SHA512,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
)
|
||||
|
||||
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
|
||||
gethcrypto.S256(): ECIES_AES128_SHA256,
|
||||
elliptic.P256(): ECIES_AES128_SHA256,
|
||||
elliptic.P384(): ECIES_AES256_SHA384,
|
||||
elliptic.P521(): ECIES_AES256_SHA512,
|
||||
}
|
||||
|
||||
func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
|
||||
paramsFromCurve[curve] = params
|
||||
}
|
||||
|
||||
// ParamsFromCurve selects parameters optimal for the selected elliptic curve.
|
||||
// Only the curves P256, P384, and P512 are supported.
|
||||
func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
|
||||
return paramsFromCurve[curve]
|
||||
}
|
||||
197
vendor/github.com/status-im/status-go/eth-node/crypto/ethereum_crypto.go
generated
vendored
Normal file
197
vendor/github.com/status-im/status-go/eth-node/crypto/ethereum_crypto.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
dr "github.com/status-im/doubleratchet"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto/ecies"
|
||||
)
|
||||
|
||||
// EthereumCrypto is an implementation of Crypto with cryptographic primitives recommended
|
||||
// by the Double Ratchet Algorithm specification. However, some details are different,
|
||||
// see function comments for details.
|
||||
type EthereumCrypto struct{}
|
||||
|
||||
// See the Crypto interface.
|
||||
func (c EthereumCrypto) GenerateDH() (dr.DHPair, error) {
|
||||
keys, err := GenerateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return DHPair{
|
||||
PubKey: CompressPubkey(&keys.PublicKey),
|
||||
PrvKey: FromECDSA(keys),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// See the Crypto interface.
|
||||
func (c EthereumCrypto) DH(dhPair dr.DHPair, dhPub dr.Key) (dr.Key, error) {
|
||||
tmpKey := dhPair.PrivateKey()
|
||||
privateKey, err := ToECDSA(tmpKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eciesPrivate := ecies.ImportECDSA(privateKey)
|
||||
|
||||
publicKey, err := DecompressPubkey(dhPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eciesPublic := ecies.ImportECDSAPublic(publicKey)
|
||||
|
||||
key, err := eciesPrivate.GenerateShared(
|
||||
eciesPublic,
|
||||
16,
|
||||
16,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// See the Crypto interface.
|
||||
func (c EthereumCrypto) KdfRK(rk, dhOut dr.Key) (dr.Key, dr.Key, dr.Key) {
|
||||
var (
|
||||
// We can use a non-secret constant as the last argument
|
||||
r = hkdf.New(sha256.New, dhOut, rk, []byte("rsZUpEuXUqqwXBvSy3EcievAh4cMj6QL"))
|
||||
buf = make([]byte, 96)
|
||||
)
|
||||
|
||||
rootKey := make(dr.Key, 32)
|
||||
chainKey := make(dr.Key, 32)
|
||||
headerKey := make(dr.Key, 32)
|
||||
|
||||
// The only error here is an entropy limit which won't be reached for such a short buffer.
|
||||
_, _ = io.ReadFull(r, buf)
|
||||
|
||||
copy(rootKey, buf[:32])
|
||||
copy(chainKey, buf[32:64])
|
||||
copy(headerKey, buf[64:96])
|
||||
return rootKey, chainKey, headerKey
|
||||
}
|
||||
|
||||
// See the Crypto interface.
|
||||
func (c EthereumCrypto) KdfCK(ck dr.Key) (dr.Key, dr.Key) {
|
||||
const (
|
||||
ckInput = 15
|
||||
mkInput = 16
|
||||
)
|
||||
|
||||
chainKey := make(dr.Key, 32)
|
||||
msgKey := make(dr.Key, 32)
|
||||
|
||||
h := hmac.New(sha256.New, ck)
|
||||
|
||||
_, _ = h.Write([]byte{ckInput})
|
||||
copy(chainKey, h.Sum(nil))
|
||||
h.Reset()
|
||||
|
||||
_, _ = h.Write([]byte{mkInput})
|
||||
copy(msgKey, h.Sum(nil))
|
||||
|
||||
return chainKey, msgKey
|
||||
}
|
||||
|
||||
// Encrypt uses a slightly different approach than in the algorithm specification:
|
||||
// it uses AES-256-CTR instead of AES-256-CBC for security, ciphertext length and implementation
|
||||
// complexity considerations.
|
||||
func (c EthereumCrypto) Encrypt(mk dr.Key, plaintext, ad []byte) ([]byte, error) {
|
||||
encKey, authKey, iv := c.deriveEncKeys(mk)
|
||||
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
copy(ciphertext, iv[:])
|
||||
|
||||
block, err := aes.NewCipher(encKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stream := cipher.NewCTR(block, iv[:])
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
return append(ciphertext, c.computeSignature(authKey, ciphertext, ad)...), nil
|
||||
}
|
||||
|
||||
// See the Crypto interface.
|
||||
func (c EthereumCrypto) Decrypt(mk dr.Key, authCiphertext, ad []byte) ([]byte, error) {
|
||||
var (
|
||||
l = len(authCiphertext)
|
||||
ciphertext = authCiphertext[:l-sha256.Size]
|
||||
signature = authCiphertext[l-sha256.Size:]
|
||||
)
|
||||
|
||||
// Check the signature.
|
||||
encKey, authKey, _ := c.deriveEncKeys(mk)
|
||||
|
||||
if s := c.computeSignature(authKey, ciphertext, ad); !bytes.Equal(s, signature) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
// Decrypt.
|
||||
block, err := aes.NewCipher(encKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stream := cipher.NewCTR(block, ciphertext[:aes.BlockSize])
|
||||
plaintext := make([]byte, len(ciphertext[aes.BlockSize:]))
|
||||
|
||||
stream.XORKeyStream(plaintext, ciphertext[aes.BlockSize:])
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// deriveEncKeys derive keys for message encryption and decryption. Returns (encKey, authKey, iv, err).
|
||||
func (c EthereumCrypto) deriveEncKeys(mk dr.Key) (dr.Key, dr.Key, [16]byte) {
|
||||
// First, derive encryption and authentication key out of mk.
|
||||
salt := make([]byte, 32)
|
||||
var (
|
||||
r = hkdf.New(sha256.New, mk, salt, []byte("pcwSByyx2CRdryCffXJwy7xgVZWtW5Sh"))
|
||||
buf = make([]byte, 80)
|
||||
)
|
||||
|
||||
encKey := make(dr.Key, 32)
|
||||
authKey := make(dr.Key, 32)
|
||||
var iv [16]byte
|
||||
|
||||
// The only error here is an entropy limit which won't be reached for such a short buffer.
|
||||
_, _ = io.ReadFull(r, buf)
|
||||
|
||||
copy(encKey, buf[0:32])
|
||||
copy(authKey, buf[32:64])
|
||||
copy(iv[:], buf[64:80])
|
||||
return encKey, authKey, iv
|
||||
}
|
||||
|
||||
func (c EthereumCrypto) computeSignature(authKey, ciphertext, associatedData []byte) []byte {
|
||||
h := hmac.New(sha256.New, authKey)
|
||||
_, _ = h.Write(associatedData)
|
||||
_, _ = h.Write(ciphertext)
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
type DHPair struct {
|
||||
PrvKey dr.Key
|
||||
PubKey dr.Key
|
||||
}
|
||||
|
||||
func (p DHPair) PrivateKey() dr.Key {
|
||||
return p.PrvKey
|
||||
}
|
||||
|
||||
func (p DHPair) PublicKey() dr.Key {
|
||||
return p.PubKey
|
||||
}
|
||||
237
vendor/github.com/status-im/status-go/eth-node/crypto/gethcrypto.go
generated
vendored
Normal file
237
vendor/github.com/status-im/status-go/eth-node/crypto/gethcrypto.go
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
)
|
||||
|
||||
// SignatureLength indicates the byte length required to carry a signature with recovery id.
|
||||
const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id
|
||||
|
||||
// RecoveryIDOffset points to the byte offset within the signature that contains the recovery id.
|
||||
const RecoveryIDOffset = 64
|
||||
|
||||
// DigestLength sets the signature digest exact length
|
||||
const DigestLength = 32
|
||||
|
||||
var (
|
||||
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
|
||||
)
|
||||
|
||||
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
|
||||
|
||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||
func Keccak256(data ...[]byte) []byte {
|
||||
d := sha3.NewLegacyKeccak256()
|
||||
for _, b := range data {
|
||||
_, _ = d.Write(b)
|
||||
}
|
||||
return d.Sum(nil)
|
||||
}
|
||||
|
||||
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
|
||||
// converting it to an internal Hash data structure.
|
||||
func Keccak256Hash(data ...[]byte) (h types.Hash) {
|
||||
d := sha3.NewLegacyKeccak256()
|
||||
for _, b := range data {
|
||||
_, _ = d.Write(b)
|
||||
}
|
||||
d.Sum(h[:0])
|
||||
return h
|
||||
}
|
||||
|
||||
// Keccak512 calculates and returns the Keccak512 hash of the input data.
|
||||
func Keccak512(data ...[]byte) []byte {
|
||||
d := sha3.NewLegacyKeccak512()
|
||||
for _, b := range data {
|
||||
_, _ = d.Write(b)
|
||||
}
|
||||
return d.Sum(nil)
|
||||
}
|
||||
|
||||
// CreateAddress creates an ethereum address given the bytes and the nonce
|
||||
func CreateAddress(b types.Address, nonce uint64) types.Address {
|
||||
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
|
||||
return types.BytesToAddress(Keccak256(data)[12:])
|
||||
}
|
||||
|
||||
// CreateAddress2 creates an ethereum address given the address bytes, initial
|
||||
// contract code hash and a salt.
|
||||
func CreateAddress2(b types.Address, salt [32]byte, inithash []byte) types.Address {
|
||||
return types.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:])
|
||||
}
|
||||
|
||||
// ToECDSA creates a private key with the given D value.
|
||||
func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
|
||||
return toECDSA(d, true)
|
||||
}
|
||||
|
||||
// ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
|
||||
// never be used unless you are sure the input is valid and want to avoid hitting
|
||||
// errors due to bad origin encoding (0 prefixes cut off).
|
||||
func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey {
|
||||
priv, _ := toECDSA(d, false)
|
||||
return priv
|
||||
}
|
||||
|
||||
// toECDSA creates a private key with the given D value. The strict parameter
|
||||
// controls whether the key's length should be enforced at the curve size or
|
||||
// it can also accept legacy encodings (0 prefixes).
|
||||
func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
|
||||
priv := new(ecdsa.PrivateKey)
|
||||
priv.PublicKey.Curve = S256()
|
||||
if strict && 8*len(d) != priv.Params().BitSize {
|
||||
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
|
||||
}
|
||||
priv.D = new(big.Int).SetBytes(d)
|
||||
|
||||
// The priv.D must < N
|
||||
if priv.D.Cmp(secp256k1N) >= 0 {
|
||||
return nil, fmt.Errorf("invalid private key, >=N")
|
||||
}
|
||||
// The priv.D must not be zero or negative.
|
||||
if priv.D.Sign() <= 0 {
|
||||
return nil, fmt.Errorf("invalid private key, zero or negative")
|
||||
}
|
||||
|
||||
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
|
||||
if priv.PublicKey.X == nil {
|
||||
return nil, errors.New("invalid private key")
|
||||
}
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// FromECDSA exports a private key into a binary dump.
|
||||
func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
||||
if priv == nil {
|
||||
return nil
|
||||
}
|
||||
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
||||
}
|
||||
|
||||
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||
x, y := elliptic.Unmarshal(S256(), pub)
|
||||
if x == nil {
|
||||
return nil, errInvalidPubkey
|
||||
}
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||
}
|
||||
|
||||
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
||||
if pub == nil || pub.X == nil || pub.Y == nil {
|
||||
return nil
|
||||
}
|
||||
return elliptic.Marshal(S256(), pub.X, pub.Y)
|
||||
}
|
||||
|
||||
// HexToECDSA parses a secp256k1 private key.
|
||||
func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
|
||||
b, err := hex.DecodeString(hexkey)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid hex string")
|
||||
}
|
||||
return ToECDSA(b)
|
||||
}
|
||||
|
||||
// LoadECDSA loads a secp256k1 private key from the given file.
|
||||
func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
|
||||
buf := make([]byte, 64)
|
||||
fd, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
if _, err := io.ReadFull(fd, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := hex.DecodeString(string(buf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToECDSA(key)
|
||||
}
|
||||
|
||||
// SaveECDSA saves a secp256k1 private key to the given file with
|
||||
// restrictive permissions. The key data is saved hex-encoded.
|
||||
func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
|
||||
k := hex.EncodeToString(FromECDSA(key))
|
||||
return ioutil.WriteFile(file, []byte(k), 0600)
|
||||
}
|
||||
|
||||
func GenerateKey() (*ecdsa.PrivateKey, error) {
|
||||
return ecdsa.GenerateKey(S256(), rand.Reader)
|
||||
}
|
||||
|
||||
func PubkeyToAddress(p ecdsa.PublicKey) types.Address {
|
||||
pubBytes := FromECDSAPub(&p)
|
||||
return types.BytesToAddress(Keccak256(pubBytes[1:])[12:])
|
||||
}
|
||||
|
||||
// Ecrecover returns the uncompressed public key that created the given signature.
|
||||
func Ecrecover(hash, sig []byte) ([]byte, error) {
|
||||
return secp256k1.RecoverPubkey(hash, sig)
|
||||
}
|
||||
|
||||
// SigToPub returns the public key that created the given signature.
|
||||
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
|
||||
s, err := Ecrecover(hash, sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
x, y := elliptic.Unmarshal(S256(), s)
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||
}
|
||||
|
||||
// DecompressPubkey parses a public key in the 33-byte compressed format.
|
||||
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
||||
x, y := secp256k1.DecompressPubkey(pubkey)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("invalid public key")
|
||||
}
|
||||
return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil
|
||||
}
|
||||
|
||||
// CompressPubkey encodes a public key to the 33-byte compressed format.
|
||||
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
||||
return secp256k1.CompressPubkey(pubkey.X, pubkey.Y)
|
||||
}
|
||||
|
||||
// S256 returns an instance of the secp256k1 curve.
|
||||
func S256() elliptic.Curve {
|
||||
return secp256k1.S256()
|
||||
}
|
||||
Reference in New Issue
Block a user