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 }