/
address.go
127 lines (104 loc) · 2.81 KB
/
address.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
package ledger
import (
"bytes"
"crypto/sha256"
"fmt"
"github.com/btcsuite/btcutil/base58"
"github.com/cachecashproject/go-cachecash/ledger/txscript"
"github.com/pkg/errors"
"golang.org/x/crypto/ed25519"
)
const (
AddressHashSize = 20
)
type AddressVersion uint8
// These values are Cachecash-specific and do not line up with Bitcoin address version assignments.
const (
AddressP2WPKHMainnet AddressVersion = 0x01
AddressP2WPKHGoodnet AddressVersion = 0x02
AddressP2WPKHTestnet AddressVersion = 0x03
)
type Address interface {
Bytes() []byte
PubKeyHash() []byte
Base58Check() string
}
type P2WPKHAddress struct {
AddressVersion AddressVersion
WitnessProgramVersion uint8 // Must be 0, as in Bitcoin.
PublicKeyHash []byte
}
var _ Address = (*P2WPKHAddress)(nil)
func MakeP2WPKHAddress(pubKey ed25519.PublicKey) *P2WPKHAddress {
pubHash := txscript.Hash160Sum(pubKey)
return &P2WPKHAddress{
AddressVersion: AddressP2WPKHTestnet,
WitnessProgramVersion: 0,
PublicKeyHash: pubHash[0:AddressHashSize],
}
}
func (a *P2WPKHAddress) Bytes() []byte {
data := []byte{
byte(a.AddressVersion),
a.WitnessProgramVersion,
0x00, // Why do Bitcoin P2WPKH addresses have this extra byte here?
}
data = append(data, a.PublicKeyHash...)
return data
}
func (a *P2WPKHAddress) PubKeyHash() []byte {
return a.PublicKeyHash
}
func (a *P2WPKHAddress) Base58Check() string {
data := a.Bytes()
ck := sha256.Sum256(data)
ck = sha256.Sum256(ck[:])
data = append(data, ck[:4]...)
return base58.Encode(data)
}
func Base58CheckDecode(s string) ([]byte, error) {
// N.B.: If s is not a base58-encoded string, dc will be 0-length.
dc := base58.Decode(s)
if len(dc) <= 4 {
return nil, errors.New("check-encoded address malformed or too short")
}
data := dc[:len(dc)-4]
actualCk := dc[len(dc)-4:]
ck := sha256.Sum256(data)
ck = sha256.Sum256(ck[:])
if !bytes.Equal(actualCk, ck[:4]) {
return nil, fmt.Errorf("checksum failed (got %#x, expected %#x)", ck[:4], actualCk)
}
return data, nil
}
func ParseAddress(s string) (Address, error) {
d, err := Base58CheckDecode(s)
if err != nil {
return nil, err
}
return ParseAddressBytes(d)
}
func ParseAddressBytes(data []byte) (Address, error) {
if len(data) < 1 {
return nil, errors.New("address too short")
}
v := (AddressVersion)(data[0])
switch v {
case AddressP2WPKHMainnet:
case AddressP2WPKHGoodnet:
case AddressP2WPKHTestnet:
a := &P2WPKHAddress{
AddressVersion: v,
WitnessProgramVersion: data[1],
PublicKeyHash: data[3:],
}
if a.WitnessProgramVersion != 0 {
return nil, errors.New("unexpected witness program version")
}
if len(a.PublicKeyHash) != AddressHashSize {
return nil, errors.New("unexpected public key hash size")
}
return a, nil
}
return nil, errors.New("unexpected address version")
}