/
legacy_address.go
127 lines (111 loc) · 2.87 KB
/
legacy_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 libada
import (
"errors"
"fmt"
"hash/crc32"
"github.com/fxamacker/cbor/v2"
"github.com/islishude/base58"
)
const (
XPubSize = 64
ByronPubKeyTag uint64 = 0
ByronTag uint64 = 24
)
type LegacyAddress struct {
Hashed []byte
Attrs LegacyAddressAttribute
Tag uint64 // Byron only supports PubKeyTag(0)
}
func NewSimpleLegacyAddress(xpub []byte, networks ...uint32) (*LegacyAddress, error) {
var attr LegacyAddressAttribute
if len(networks) > 0 {
attr.Network = &networks[0]
}
hashed, err := newHashedSpending(xpub, attr)
if err != nil {
return nil, err
}
return &LegacyAddress{Hashed: hashed, Attrs: attr, Tag: ByronPubKeyTag}, nil
}
func newHashedSpending(xpub []byte, attr LegacyAddressAttribute) ([]byte, error) {
if len(xpub) != XPubSize {
return nil, errors.New("xpub size should be 64 bytes")
}
spend, err := cbor.Marshal([]interface{}{ByronPubKeyTag, xpub})
if err != nil {
return nil, err
}
buf, err := cbor.Marshal([]interface{}{ByronPubKeyTag, cbor.RawMessage(spend), attr})
if err != nil {
return nil, err
}
return Sha3AndBlake2b224(buf), nil
}
func (a *LegacyAddress) MarshalCBOR() ([]byte, error) {
if len(a.Hashed) != Hash28Size {
return nil, errors.New("Invalid hash28 data")
}
raw, err := cbor.Marshal([]interface{}{a.Hashed, a.Attrs, a.Tag})
if err != nil {
return nil, err
}
return cbor.Marshal([]interface{}{
cbor.Tag{Number: ByronTag, Content: raw},
uint64(crc32.ChecksumIEEE(raw)),
})
}
func (a *LegacyAddress) UnmarshalCBOR(data []byte) error {
type RawAddress struct {
_ struct{} `cbor:",toarray"`
Tag cbor.Tag
Checksum uint64
}
var rawAddress RawAddress
if err := cbor.Unmarshal(data, &rawAddress); err != nil {
return fmt.Errorf("mashal raw: %s", err)
}
rawTag, ok := rawAddress.Tag.Content.([]byte)
if !ok || rawAddress.Tag.Number != ByronTag {
return errors.New("not a valid byron address")
}
checksum := crc32.ChecksumIEEE(rawTag)
if rawAddress.Checksum != uint64(checksum) {
return errors.New("checksum unmatched")
}
var got struct {
_ struct{} `cbor:",toarray"`
Hashed []byte
Attrs LegacyAddressAttribute
Tag uint64
}
if err := cbor.Unmarshal(rawTag, &got); err != nil {
return err
}
if len(got.Hashed) != Hash28Size || got.Tag != ByronPubKeyTag {
return errors.New("Invalid byron hashed or type")
}
if a == nil {
return errors.New("unmarshal to nil value")
}
*a = LegacyAddress{Hashed: got.Hashed, Attrs: got.Attrs, Tag: got.Tag}
return nil
}
func (a *LegacyAddress) Bytes() []byte {
raw, _ := a.MarshalCBOR()
return raw
}
func (a *LegacyAddress) Kind() AddressKind {
return LegacyAddressKind
}
func (a *LegacyAddress) String() string {
return base58.Encode(a.Bytes())
}
func (a *LegacyAddress) GetNetwork() Network {
if a.Attrs.Network == nil {
return Mainnet
}
return Testnet
}
func (a *LegacyAddress) Prefix() string {
return ""
}