1
1
package bitcoin
2
2
3
3
import (
4
+ "bytes"
5
+ "errors"
6
+
7
+ "crypto/sha256"
8
+
4
9
"github.com/bitcoinsv/bsvd/bsvec"
5
10
"github.com/bitcoinsv/bsvd/chaincfg"
6
11
"github.com/bitcoinsv/bsvutil"
7
12
)
8
13
14
+ // A25 is a type for a 25 byte (not base58 encoded) bitcoin address.
15
+ type A25 [25 ]byte
16
+
17
+ // DoubleSHA256 computes a double sha256 hash of the first 21 bytes of the
18
+ // address. This is the one function shared with the other bitcoin RC task.
19
+ // Returned is the full 32 byte sha256 hash. (The bitcoin checksum will be
20
+ // the first four bytes of the slice.)
21
+ func (a * A25 ) doubleSHA256 () []byte {
22
+ h := sha256 .New ()
23
+ h .Write (a [:21 ])
24
+ d := h .Sum ([]byte {})
25
+ h = sha256 .New ()
26
+ h .Write (d )
27
+ return h .Sum (d [:0 ])
28
+ }
29
+
30
+ // Version returns the version byte of a A25 address
31
+ func (a * A25 ) Version () byte {
32
+ return a [0 ]
33
+ }
34
+
35
+ // EmbeddedChecksum returns the 4 checksum bytes of a A25 address
36
+ func (a * A25 ) EmbeddedChecksum () (c [4 ]byte ) {
37
+ copy (c [:], a [21 :])
38
+ return
39
+ }
40
+
41
+ // Tmpl and Set58 are adapted from the C solution.
42
+ // Go has big integers but this techinique seems better.
43
+ var tmpl = []byte ("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" )
44
+
45
+ // Set58 takes a base58 encoded address and decodes it into the receiver.
46
+ // Errors are returned if the argument is not valid base58 or if the decoded
47
+ // value does not fit in the 25 byte address. The address is not otherwise
48
+ // checked for validity.
49
+ func (a * A25 ) Set58 (s []byte ) error {
50
+ for _ , s1 := range s {
51
+ c := bytes .IndexByte (tmpl , s1 )
52
+ if c < 0 {
53
+ return errors .New ("bad char" )
54
+ }
55
+ for j := 24 ; j >= 0 ; j -- {
56
+ c += 58 * int (a [j ])
57
+ a [j ] = byte (c % 256 )
58
+ c /= 256
59
+ }
60
+ if c > 0 {
61
+ return errors .New ("too long" )
62
+ }
63
+ }
64
+ return nil
65
+ }
66
+
67
+ // ComputeChecksum returns a four byte checksum computed from the first 21
68
+ // bytes of the address. The embedded checksum is not updated.
69
+ func (a * A25 ) ComputeChecksum () (c [4 ]byte ) {
70
+ copy (c [:], a .doubleSHA256 ())
71
+ return
72
+ } /* {{header|Go}} */
73
+
9
74
// AddressFromPrivKey takes a private key string and returns a Bitcoin address
10
75
func AddressFromPrivKey (privKey string ) string {
11
76
pubKey := PrivateKey (privKey ).PubKey ()
@@ -18,3 +83,19 @@ func Address(publicKey *bsvec.PublicKey) (address *bsvutil.LegacyAddressPubKeyHa
18
83
address , _ = bsvutil .NewLegacyAddressPubKeyHash (publicKeyHash , & chaincfg .MainNetParams )
19
84
return
20
85
}
86
+
87
+ // ValidA58 validates a base58 encoded bitcoin address. An address is valid
88
+ // if it can be decoded into a 25 byte address, the version number is 0,
89
+ // and the checksum validates. Return value ok will be true for valid
90
+ // addresses. If ok is false, the address is invalid and the error value
91
+ // may indicate why.
92
+ func ValidA58 (a58 []byte ) (ok bool , err error ) {
93
+ var a A25
94
+ if err := a .Set58 (a58 ); err != nil {
95
+ return false , err
96
+ }
97
+ if a .Version () != 0 {
98
+ return false , errors .New ("not version 0" )
99
+ }
100
+ return a .EmbeddedChecksum () == a .ComputeChecksum (), nil
101
+ }
0 commit comments