/
crypto.go
108 lines (90 loc) · 3.24 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
// 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"
"encoding/binary"
"errors"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/ethsana/sana/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, blockHash []byte) (swarm.Address, error) {
ethAddr, err := NewEthereumAddress(p)
if err != nil {
return swarm.ZeroAddress, err
}
if len(blockHash) != 32 {
return swarm.ZeroAddress, ErrBadHashLength
}
return NewOverlayFromEthereumAddress(ethAddr, networkID, blockHash), nil
}
// NewOverlayFromEthereumAddress constructs a Swarm Address for an Ethereum address.
func NewOverlayFromEthereumAddress(ethAddr []byte, networkID uint64, blockHash []byte) swarm.Address {
netIDBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(netIDBytes, networkID)
data := append(ethAddr, netIDBytes...)
data = append(data, blockHash...)
h := sha3.Sum256(data)
return swarm.NewAddress(h[:])
}
// 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 {
return (*btcec.PrivateKey)(k).Serialize()
}
// 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
}
// 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
}