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