-
Notifications
You must be signed in to change notification settings - Fork 409
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add functions to encode and decode payment addresses.
- Loading branch information
Showing
3 changed files
with
178 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package btcutil | ||
|
||
import ( | ||
"bytes" | ||
"code.google.com/p/go.crypto/ripemd160" | ||
"errors" | ||
"github.com/conformal/btcwire" | ||
) | ||
|
||
// ErrAddrUnknownNet describes an error where the address identifier | ||
// byte is not recognized as belonging to neither the Bitcoin MainNet nor | ||
// TestNet. | ||
var ErrAddrUnknownNet = errors.New("unrecognized network identifier byte") | ||
|
||
// ErrMalformedAddress describes an error where an address is improperly | ||
// formatted, either due to an incorrect length of the hashed pubkey or | ||
// a non-matching checksum. | ||
var ErrMalformedAddress = errors.New("malformed address") | ||
|
||
// Constants used to specify which network a payment address belongs | ||
// to. Mainnet address cannot be used on the Testnet, and vice versa. | ||
const ( | ||
// MainNetAddr is the address identifier for MainNet | ||
MainNetAddr = 0x00 | ||
|
||
// TestNetAddr is the address identifier for TestNet | ||
TestNetAddr = 0x6f | ||
) | ||
|
||
// EncodeAddress takes a 20-byte raw payment address (hash160 of the | ||
// uncompressed pubkey) and a network identifying byte and encodes the | ||
// payment address in a human readable string. | ||
func EncodeAddress(addrHash []byte, netID byte) (encoded string, err error) { | ||
if len(addrHash) != ripemd160.Size { | ||
return "", ErrMalformedAddress | ||
} | ||
if netID != MainNetAddr && netID != TestNetAddr { | ||
return "", ErrAddrUnknownNet | ||
} | ||
|
||
tosum := append([]byte{netID}, addrHash...) | ||
cksum := btcwire.DoubleSha256(tosum) | ||
|
||
a := append([]byte{netID}, addrHash...) | ||
a = append(a, cksum[:4]...) | ||
|
||
return Base58Encode(a), nil | ||
} | ||
|
||
// DecodeAddress decodes a human readable payment address string | ||
// returning the 20-byte decoded address, along with the network | ||
// identifying byte. | ||
func DecodeAddress(addr string) (addrHash []byte, netID byte, err error) { | ||
decoded := Base58Decode(addr) | ||
|
||
// Length of decoded address must be 20 bytes + 1 byte for a network | ||
// identifier byte + 4 bytes of checksum. | ||
if len(decoded) != ripemd160.Size+5 { | ||
return nil, 0x00, ErrMalformedAddress | ||
} | ||
|
||
netID = decoded[0] | ||
if netID != MainNetAddr && netID != TestNetAddr { | ||
return nil, 0x00, ErrAddrUnknownNet | ||
} | ||
addrHash = decoded[1:21] | ||
|
||
// Checksum is first four bytes of double SHA256 of the network byte | ||
// and addrHash. Verify this matches the final 4 bytes of the decoded | ||
// address. | ||
tosum := append([]byte{netID}, addrHash...) | ||
cksum := btcwire.DoubleSha256(tosum)[:4] | ||
if !bytes.Equal(cksum, decoded[len(decoded)-4:]) { | ||
return nil, 0x00, ErrMalformedAddress | ||
} | ||
|
||
return addrHash, netID, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright (c) 2013 Conformal Systems LLC. | ||
// Use of this source code is governed by an ISC | ||
// license that can be found in the LICENSE file. | ||
|
||
package btcutil_test | ||
|
||
import ( | ||
"bytes" | ||
"github.com/conformal/btcutil" | ||
"testing" | ||
) | ||
|
||
var encodeTests = []struct { | ||
raw []byte | ||
net byte | ||
res string | ||
err error | ||
}{ | ||
{[]byte{0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc, 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}, | ||
btcutil.MainNetAddr, "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", nil}, | ||
{[]byte{0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}, | ||
btcutil.MainNetAddr, "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG", nil}, | ||
{[]byte{0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83, 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}, | ||
btcutil.TestNetAddr, "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz", nil}, | ||
|
||
// Raw address not 20 bytes (padded with leading 0s) | ||
{[]byte{0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}, | ||
btcutil.MainNetAddr, "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG", btcutil.ErrMalformedAddress}, | ||
|
||
// Bad network byte | ||
{make([]byte, 20), btcutil.MainNetAddr + 1, "", btcutil.ErrAddrUnknownNet}, | ||
} | ||
|
||
func TestEncodeAddresses(t *testing.T) { | ||
for i := range encodeTests { | ||
res, err := btcutil.EncodeAddress(encodeTests[i].raw, | ||
encodeTests[i].net) | ||
if err != encodeTests[i].err { | ||
t.Error(err) | ||
continue | ||
} | ||
if err == nil && res != encodeTests[i].res { | ||
t.Errorf("Results differ: Expected '%s', returned '%s'", | ||
encodeTests[i].res, res) | ||
} | ||
} | ||
} | ||
|
||
var decodeTests = []struct { | ||
addr string | ||
res []byte | ||
net byte | ||
err error | ||
}{ | ||
{"1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", | ||
[]byte{0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc, 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}, | ||
btcutil.MainNetAddr, nil}, | ||
{"mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz", | ||
[]byte{0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83, 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}, | ||
btcutil.TestNetAddr, nil}, | ||
|
||
// Wrong length | ||
{"01MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", nil, btcutil.MainNetAddr, btcutil.ErrMalformedAddress}, | ||
|
||
// Bad magic | ||
{"2MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", nil, btcutil.MainNetAddr, btcutil.ErrAddrUnknownNet}, | ||
|
||
// Bad checksum | ||
{"1MirQ9bwyQcGVJPwKUgapu5ouK2E2dpuqz", nil, btcutil.MainNetAddr, btcutil.ErrMalformedAddress}, | ||
} | ||
|
||
func TestDecodeAddresses(t *testing.T) { | ||
for i := range decodeTests { | ||
res, _, err := btcutil.DecodeAddress(decodeTests[i].addr) | ||
if err != decodeTests[i].err { | ||
t.Error(err) | ||
} | ||
if err == nil && !bytes.Equal(res, decodeTests[i].res) { | ||
t.Errorf("Results differ: Expected '%v', returned '%v'", | ||
decodeTests[i].res, res) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
|
||
github.com/conformal/btcutil/base58.go Base58Decode 100.00% (20/20) | ||
github.com/conformal/btcutil/block.go Block.TxSha 100.00% (11/11) | ||
github.com/conformal/btcutil/block.go Block.TxShas 100.00% (10/10) | ||
github.com/conformal/btcutil/block.go NewBlockFromBytes 100.00% (7/7) | ||
github.com/conformal/btcutil/block.go Block.Sha 100.00% (5/5) | ||
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go OutOfRangeError.Error 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.ProtocolVersion 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1) | ||
github.com/conformal/btcutil/base58.go Base58Encode 93.33% (14/15) | ||
github.com/conformal/btcutil/block.go Block.TxLoc 88.89% (8/9) | ||
github.com/conformal/btcutil/block.go Block.Bytes 88.89% (8/9) | ||
github.com/conformal/btcutil ------------------------- 96.77% (90/93) | ||
github.com/conformal/btcutil/base58.go Base58Decode 100.00% (20/20) | ||
github.com/conformal/btcutil/base58.go Base58Encode 100.00% (15/15) | ||
github.com/conformal/btcutil/addrconvs.go DecodeAddress 100.00% (12/12) | ||
github.com/conformal/btcutil/block.go Block.TxSha 100.00% (11/11) | ||
github.com/conformal/btcutil/block.go Block.TxShas 100.00% (10/10) | ||
github.com/conformal/btcutil/addrconvs.go EncodeAddress 100.00% (9/9) | ||
github.com/conformal/btcutil/block.go NewBlockFromBytes 100.00% (7/7) | ||
github.com/conformal/btcutil/block.go Block.Sha 100.00% (5/5) | ||
github.com/conformal/btcutil/block.go OutOfRangeError.Error 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1) | ||
github.com/conformal/btcutil/block.go Block.TxLoc 88.89% (8/9) | ||
github.com/conformal/btcutil/block.go Block.Bytes 88.89% (8/9) | ||
github.com/conformal/btcutil ------------------------- 98.23% (111/113) | ||
|