github.com/ethersphere/bee/v2@v2.2.0/pkg/crypto/crypto.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package crypto
     6  
     7  import (
     8  	"crypto/ecdsa"
     9  	"crypto/elliptic"
    10  	"crypto/rand"
    11  	"crypto/x509"
    12  	"encoding/binary"
    13  	"errors"
    14  	"fmt"
    15  
    16  	"github.com/btcsuite/btcd/btcec/v2"
    17  	"github.com/ethersphere/bee/v2/pkg/swarm"
    18  	"golang.org/x/crypto/sha3"
    19  )
    20  
    21  // RecoverFunc is a function to recover the public key from a signature
    22  type RecoverFunc func(signature, data []byte) (*ecdsa.PublicKey, error)
    23  
    24  var ErrBadHashLength = errors.New("wrong block hash length")
    25  
    26  const (
    27  	AddressSize = 20
    28  )
    29  
    30  // NewOverlayAddress constructs a Swarm Address from ECDSA public key.
    31  func NewOverlayAddress(p ecdsa.PublicKey, networkID uint64, nonce []byte) (swarm.Address, error) {
    32  
    33  	ethAddr, err := NewEthereumAddress(p)
    34  	if err != nil {
    35  		return swarm.ZeroAddress, err
    36  	}
    37  
    38  	if len(nonce) != 32 {
    39  		return swarm.ZeroAddress, ErrBadHashLength
    40  	}
    41  
    42  	return NewOverlayFromEthereumAddress(ethAddr, networkID, nonce)
    43  }
    44  
    45  // NewOverlayFromEthereumAddress constructs a Swarm Address for an Ethereum address.
    46  func NewOverlayFromEthereumAddress(ethAddr []byte, networkID uint64, nonce []byte) (swarm.Address, error) {
    47  
    48  	netIDBytes := make([]byte, 8)
    49  
    50  	binary.LittleEndian.PutUint64(netIDBytes, networkID)
    51  
    52  	data := append(ethAddr, netIDBytes...)
    53  	data = append(data, nonce...)
    54  	h, err := LegacyKeccak256(data)
    55  	if err != nil {
    56  		return swarm.ZeroAddress, err
    57  	}
    58  	return swarm.NewAddress(h[:]), nil
    59  }
    60  
    61  // GenerateSecp256k1Key generates an ECDSA private key using
    62  // secp256k1 elliptic curve.
    63  func GenerateSecp256k1Key() (*ecdsa.PrivateKey, error) {
    64  	return ecdsa.GenerateKey(btcec.S256(), rand.Reader)
    65  }
    66  
    67  // EncodeSecp256k1PrivateKey encodes raw ECDSA private key.
    68  func EncodeSecp256k1PrivateKey(k *ecdsa.PrivateKey) ([]byte, error) {
    69  	pvk, _ := btcec.PrivKeyFromBytes(k.D.Bytes())
    70  	return pvk.Serialize(), nil
    71  }
    72  
    73  // EncodeSecp256k1PublicKey encodes raw ECDSA public key in a 33-byte compressed format.
    74  func EncodeSecp256k1PublicKey(k *ecdsa.PublicKey) []byte {
    75  	var x, y btcec.FieldVal
    76  	x.SetByteSlice(k.X.Bytes())
    77  	y.SetByteSlice(k.Y.Bytes())
    78  	return btcec.NewPublicKey(&x, &y).SerializeCompressed()
    79  }
    80  
    81  // DecodeSecp256k1PrivateKey decodes raw ECDSA private key.
    82  func DecodeSecp256k1PrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
    83  	if l := len(data); l != btcec.PrivKeyBytesLen {
    84  		return nil, fmt.Errorf("secp256k1 data size %d expected %d", l, btcec.PrivKeyBytesLen)
    85  	}
    86  	pvk, _ := btcec.PrivKeyFromBytes(data)
    87  	return pvk.ToECDSA(), nil
    88  }
    89  
    90  // GenerateSecp256k1Key generates an ECDSA private key using
    91  // secp256k1 elliptic curve.
    92  func GenerateSecp256r1Key() (*ecdsa.PrivateKey, error) {
    93  	return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    94  }
    95  
    96  // EncodeSecp256k1PrivateKey encodes raw ECDSA private key.
    97  func EncodeSecp256r1PrivateKey(k *ecdsa.PrivateKey) ([]byte, error) {
    98  	return x509.MarshalECPrivateKey(k)
    99  }
   100  
   101  // DecodeSecp256k1PrivateKey decodes raw ECDSA private key.
   102  func DecodeSecp256r1PrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
   103  	return x509.ParseECPrivateKey(data)
   104  }
   105  
   106  // Secp256k1PrivateKeyFromBytes returns an ECDSA private key based on
   107  // the byte slice.
   108  func Secp256k1PrivateKeyFromBytes(data []byte) *ecdsa.PrivateKey {
   109  	pvk, _ := btcec.PrivKeyFromBytes(data)
   110  	return pvk.ToECDSA()
   111  }
   112  
   113  // NewEthereumAddress returns a binary representation of ethereum blockchain address.
   114  // This function is based on github.com/ethereum/go-ethereum/crypto.PubkeyToAddress.
   115  func NewEthereumAddress(p ecdsa.PublicKey) ([]byte, error) {
   116  	if p.X == nil || p.Y == nil {
   117  		return nil, errors.New("invalid public key")
   118  	}
   119  	pubBytes := elliptic.Marshal(btcec.S256(), p.X, p.Y)
   120  	pubHash, err := LegacyKeccak256(pubBytes[1:])
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	return pubHash[12:], err
   125  }
   126  
   127  func LegacyKeccak256(data []byte) ([]byte, error) {
   128  	var err error
   129  	hasher := sha3.NewLegacyKeccak256()
   130  	_, err = hasher.Write(data)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	return hasher.Sum(nil), err
   135  }