OSDN Git Service

Add sw address
authorjianyixun <317316abcd@163.com>
Tue, 24 Oct 2017 07:25:09 +0000 (15:25 +0800)
committerjianyixun <317316abcd@163.com>
Tue, 24 Oct 2017 07:25:09 +0000 (15:25 +0800)
Add Sigwit address  and chain params

16 files changed:
blockchain/account/accounts.go
blockchain/transact.go
blockchain/txbuilder/txbuilder.go
blockchain/txbuilder/witness.go
common/address.go [new file with mode: 0644]
common/address_test.go [new file with mode: 0644]
common/bech32.go [deleted file]
common/bech32/README.md [new file with mode: 0644]
common/bech32/bech32.go [new file with mode: 0644]
common/bech32/bech32_test.go [new file with mode: 0644]
common/bech32/doc.go [new file with mode: 0644]
common/bech32/example_test.go [new file with mode: 0644]
common/bech32_test.go [deleted file]
common/types.go
config/config.go
consensus/general.go

index e466b90..624da51 100644 (file)
@@ -87,6 +87,7 @@ type Account struct {
        *signers.Signer
        Alias string
        Tags  map[string]interface{}
+       Address  common.Address
 }
 
 // Create creates a new Account.
index d12fe16..47f0b5c 100644 (file)
@@ -41,7 +41,11 @@ func (a *BlockchainReactor) actionDecoder(action string) (func([]byte) (txbuilde
        }
        return decoder, true
 }
-
+/*             {"actions": [
+                       {"type": "spend", "asset_id": "%s", "amount": 100},
+                       {"type": "control_account", "asset_id": "%s", "amount": 100, "account_id": "%s"}
+               ]}`
+*/
 func (a *BlockchainReactor) buildSingle(ctx context.Context, req *BuildRequest) (*txbuilder.Template, error) {
        err := a.filterAliases(ctx, req)
        if err != nil {
index 9dd50f5..1ded7b2 100644 (file)
@@ -71,6 +71,7 @@ func Build(ctx context.Context, tx *legacy.TxData, actions []Action, maxTime tim
        return tpl, nil
 }
 
+
 func Sign(ctx context.Context, tpl *Template, xpubs []chainkd.XPub, auth string, signFn SignFunc) error {
        for i, sigInst := range tpl.SigningInstructions {
                for j, sw := range sigInst.SignatureWitnesses {
index 0557827..7aae8d9 100644 (file)
@@ -196,6 +196,7 @@ func (sw signatureWitness) materialize(tpl *Template, index uint32, args *[][]by
        // assumes that everything already in the arg list before this call
        // to Materialize is input to the signature program, so N is
        // len(*args).
+       // 0 sig1 sig2 ... program  100 sig1 sig2 ... program
        *args = append(*args, vm.Int64Bytes(int64(len(*args))))
 
        var nsigs int
diff --git a/common/address.go b/common/address.go
new file mode 100644 (file)
index 0000000..c77eaee
--- /dev/null
@@ -0,0 +1,377 @@
+package common
+
+import (
+    "bytes"
+    "errors"
+    "fmt"
+    "strings"
+
+    "github.com/bytom/consensus"
+    "github.com/bytom/common/bech32"
+)
+
+var (
+    // ErrChecksumMismatch describes an error where decoding failed due
+    // to a bad checksum.
+    ErrChecksumMismatch = errors.New("checksum mismatch")
+
+    // ErrUnknownAddressType describes an error where an address can not
+    // decoded as a specific address type due to the string encoding
+    // begining with an identifier byte unknown to any standard or
+    // registered (via chaincfg.Register) network.
+    ErrUnknownAddressType = errors.New("unknown address type")
+
+    // ErrAddressCollision describes an error where an address can not
+    // be uniquely determined as either a pay-to-pubkey-hash or
+    // pay-to-script-hash address since the leading identifier is used for
+    // describing both address kinds, but for different networks.  Rather
+    // than assuming or defaulting to one or the other, this error is
+    // returned and the caller must decide how to decode the address.
+    ErrAddressCollision = errors.New("address collision")
+
+    // ErrUnsupportedWitnessVer describes an error where a segwit address being
+    // decoded has an unsupported witness version.
+    ErrUnsupportedWitnessVer = errors.New("unsupported witness version")
+
+    // ErrUnsupportedWitnessProgLen describes an error where a segwit address
+    // being decoded has an unsupported witness program length.
+    ErrUnsupportedWitnessProgLen = errors.New("unsupported witness program length")
+
+
+)
+
+// Address is an interface type for any type of destination a transaction
+// output may spend to.  This includes pay-to-pubkey (P2PK), pay-to-pubkey-hash
+// (P2PKH), and pay-to-script-hash (P2SH).  Address is designed to be generic
+// enough that other kinds of addresses may be added in the future without
+// changing the decoding and encoding API.
+type Address interface {
+    // String returns the string encoding of the transaction output
+    // destination.
+    //
+    // Please note that String differs subtly from EncodeAddress: String
+    // will return the value as a string without any conversion, while
+    // EncodeAddress may convert destination types (for example,
+    // converting pubkeys to P2PKH addresses) before encoding as a
+    // payment address string.
+    String() string
+
+    // EncodeAddress returns the string encoding of the payment address
+    // associated with the Address value.  See the comment on String
+    // for how this method differs from String.
+    EncodeAddress() string
+
+    // ScriptAddress returns the raw bytes of the address to be used
+    // when inserting the address into a txout's script.
+    ScriptAddress() []byte
+
+    // IsForNet returns whether or not the address is associated with the
+    // passed bytom network.
+    IsForNet(*consensus.Params) bool
+}
+
+
+
+// encodeSegWitAddress creates a bech32 encoded address string representation
+// from witness version and witness program.
+func encodeSegWitAddress(hrp string, witnessVersion byte, witnessProgram []byte) (string, error) {
+    // Group the address bytes into 5 bit groups, as this is what is used to
+    // encode each character in the address string.
+    converted, err := bech32.ConvertBits(witnessProgram, 8, 5, true)
+    if err != nil {
+        return "", err
+    }
+
+    // Concatenate the witness version and program, and encode the resulting
+    // bytes using bech32 encoding.
+    combined := make([]byte, len(converted)+1)
+    combined[0] = witnessVersion
+    copy(combined[1:], converted)
+    bech, err := bech32.Encode(hrp, combined)
+    if err != nil {
+        return "", err
+    }
+
+    // Check validity by decoding the created address.
+    version, program, err := decodeSegWitAddress(bech)
+    if err != nil {
+        return "", fmt.Errorf("invalid segwit address: %v", err)
+    }
+
+    if version != witnessVersion || !bytes.Equal(program, witnessProgram) {
+        return "", fmt.Errorf("invalid segwit address")
+    }
+
+    return bech, nil
+}
+
+
+
+// DecodeAddress decodes the string encoding of an address and returns
+// the Address if addr is a valid encoding for a known address type.
+//
+// The bytom network the address is associated with is extracted if possible.
+// When the address does not encode the network, such as in the case of a raw
+// public key, the address will be associated with the passed defaultNet.
+func DecodeAddress(addr string, param *consensus.Params) (Address, error) {
+    // Bech32 encoded segwit addresses start with a human-readable part
+    // (hrp) followed by '1'. For Bytom mainnet the hrp is "bm", and for
+    // testnet it is "tm". If the address string has a prefix that matches
+    // one of the prefixes for the known networks, we try to decode it as
+    // a segwit address.
+    oneIndex := strings.LastIndexByte(addr, '1')
+    if oneIndex > 1 {
+        prefix := addr[:oneIndex+1]
+        if consensus.IsBech32SegwitPrefix(prefix, param) {
+            witnessVer, witnessProg, err := decodeSegWitAddress(addr)
+            if err != nil {
+                return nil, err
+            }
+
+            // We currently only support P2WPKH and P2WSH, which is
+            // witness version 0.
+            if witnessVer != 0 {
+                return nil, ErrUnsupportedWitnessVer
+            }
+
+            // The HRP is everything before the found '1'.
+            hrp := prefix[:len(prefix)-1]
+
+            switch len(witnessProg) {
+            case 20:
+                return newAddressWitnessPubKeyHash(hrp, witnessProg)
+            case 32:
+                return newAddressWitnessScriptHash(hrp, witnessProg)
+            default:
+                return nil, ErrUnsupportedWitnessProgLen
+            }
+        }
+    }
+    return nil, ErrUnknownAddressType
+}
+
+// decodeSegWitAddress parses a bech32 encoded segwit address string and
+// returns the witness version and witness program byte representation.
+func decodeSegWitAddress(address string) (byte, []byte, error) {
+    // Decode the bech32 encoded address.
+    _, data, err := bech32.Decode(address)
+    if err != nil {
+        return 0, nil, err
+    }
+
+    // The first byte of the decoded address is the witness version, it must
+    // exist.
+    if len(data) < 1 {
+        return 0, nil, fmt.Errorf("no witness version")
+    }
+
+    // ...and be <= 16.
+    version := data[0]
+    if version > 16 {
+        return 0, nil, fmt.Errorf("invalid witness version: %v", version)
+    }
+
+    // The remaining characters of the address returned are grouped into
+    // words of 5 bits. In order to restore the original witness program
+    // bytes, we'll need to regroup into 8 bit words.
+    regrouped, err := bech32.ConvertBits(data[1:], 5, 8, false)
+    if err != nil {
+        return 0, nil, err
+    }
+
+    // The regrouped data must be between 2 and 40 bytes.
+    if len(regrouped) < 2 || len(regrouped) > 40 {
+        return 0, nil, fmt.Errorf("invalid data length")
+    }
+
+    // For witness version 0, address MUST be exactly 20 or 32 bytes.
+    if version == 0 && len(regrouped) != 20 && len(regrouped) != 32 {
+        return 0, nil, fmt.Errorf("invalid data length for witness "+
+            "version 0: %v", len(regrouped))
+    }
+
+    return version, regrouped, nil
+}
+
+
+// AddressWitnessPubKeyHash is an Address for a pay-to-witness-pubkey-hash
+// (P2WPKH) output. See BIP 173 for further details regarding native segregated
+// witness address encoding:
+// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+type AddressWitnessPubKeyHash struct {
+    hrp            string
+    witnessVersion byte
+    witnessProgram [20]byte
+}
+
+// NewAddressWitnessPubKeyHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessPubKeyHash(witnessProg []byte, param *consensus.Params) (*AddressWitnessPubKeyHash, error) {
+    return newAddressWitnessPubKeyHash(param.Bech32HRPSegwit, witnessProg)
+}
+
+// newAddressWitnessPubKeyHash is an internal helper function to create an
+// AddressWitnessPubKeyHash with a known human-readable part, rather than
+// looking it up through its parameters.
+func newAddressWitnessPubKeyHash(hrp string, witnessProg []byte) (*AddressWitnessPubKeyHash, error) {
+    // Check for valid program length for witness version 0, which is 20
+    // for P2WPKH.
+    if len(witnessProg) != 20 {
+        return nil, errors.New("witness program must be 20 " +
+            "bytes for p2wpkh")
+    }
+
+    addr := &AddressWitnessPubKeyHash{
+        hrp:            strings.ToLower(hrp),
+        witnessVersion: 0x00,
+    }
+
+    copy(addr.witnessProgram[:], witnessProg)
+
+    return addr, nil
+}
+
+// EncodeAddress returns the bech32 string encoding of an
+// AddressWitnessPubKeyHash.
+// Part of the Address interface.
+func (a *AddressWitnessPubKeyHash) EncodeAddress() string {
+    str, err := encodeSegWitAddress(a.hrp, a.witnessVersion,
+        a.witnessProgram[:])
+    if err != nil {
+        return ""
+    }
+    return str
+}
+
+// ScriptAddress returns the witness program for this address.
+// Part of the Address interface.
+func (a *AddressWitnessPubKeyHash) ScriptAddress() []byte {
+    return a.witnessProgram[:]
+}
+
+// IsForNet returns whether or not the AddressWitnessPubKeyHash is associated
+// with the passed bitcoin network.
+// Part of the Address interface.
+func (a *AddressWitnessPubKeyHash) IsForNet(param *consensus.Params) bool {
+    return a.hrp == param.Bech32HRPSegwit
+}
+
+// String returns a human-readable string for the AddressWitnessPubKeyHash.
+// This is equivalent to calling EncodeAddress, but is provided so the type
+// can be used as a fmt.Stringer.
+// Part of the Address interface.
+func (a *AddressWitnessPubKeyHash) String() string {
+    return a.EncodeAddress()
+}
+
+// Hrp returns the human-readable part of the bech32 encoded
+// AddressWitnessPubKeyHash.
+func (a *AddressWitnessPubKeyHash) Hrp() string {
+    return a.hrp
+}
+
+// WitnessVersion returns the witness version of the AddressWitnessPubKeyHash.
+func (a *AddressWitnessPubKeyHash) WitnessVersion() byte {
+    return a.witnessVersion
+}
+
+// WitnessProgram returns the witness program of the AddressWitnessPubKeyHash.
+func (a *AddressWitnessPubKeyHash) WitnessProgram() []byte {
+    return a.witnessProgram[:]
+}
+
+// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
+// byte array.
+func (a *AddressWitnessPubKeyHash) Hash160() *[20]byte {
+    return &a.witnessProgram
+}
+
+// AddressWitnessScriptHash is an Address for a pay-to-witness-script-hash
+// (P2WSH) output. See BIP 173 for further details regarding native segregated
+// witness address encoding:
+// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+type AddressWitnessScriptHash struct {
+    hrp            string
+    witnessVersion byte
+    witnessProgram [32]byte
+}
+
+// NewAddressWitnessScriptHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessScriptHash(witnessProg []byte, param *consensus.Params) (*AddressWitnessScriptHash, error) {
+    return newAddressWitnessScriptHash(param.Bech32HRPSegwit, witnessProg)
+}
+
+// newAddressWitnessScriptHash is an internal helper function to create an
+// AddressWitnessScriptHash with a known human-readable part, rather than
+// looking it up through its parameters.
+func newAddressWitnessScriptHash(hrp string, witnessProg []byte) (*AddressWitnessScriptHash, error) {
+    // Check for valid program length for witness version 0, which is 32
+    // for P2WSH.
+    if len(witnessProg) != 32 {
+        return nil, errors.New("witness program must be 32 " +
+            "bytes for p2wsh")
+    }
+
+    addr := &AddressWitnessScriptHash{
+        hrp:            strings.ToLower(hrp),
+        witnessVersion: 0x00,
+    }
+
+    copy(addr.witnessProgram[:], witnessProg)
+
+    return addr, nil
+}
+
+// EncodeAddress returns the bech32 string encoding of an
+// AddressWitnessScriptHash.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) EncodeAddress() string {
+    str, err := encodeSegWitAddress(a.hrp, a.witnessVersion,
+        a.witnessProgram[:])
+    if err != nil {
+        return ""
+    }
+    return str
+}
+
+// ScriptAddress returns the witness program for this address.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) ScriptAddress() []byte {
+    return a.witnessProgram[:]
+}
+
+// IsForNet returns whether or not the AddressWitnessScriptHash is associated
+// with the passed bytom network.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) IsForNet(param *consensus.Params) bool {
+    return a.hrp == param.Bech32HRPSegwit
+}
+
+// String returns a human-readable string for the AddressWitnessScriptHash.
+// This is equivalent to calling EncodeAddress, but is provided so the type
+// can be used as a fmt.Stringer.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) String() string {
+    return a.EncodeAddress()
+}
+
+// Hrp returns the human-readable part of the bech32 encoded
+// AddressWitnessScriptHash.
+func (a *AddressWitnessScriptHash) Hrp() string {
+    return a.hrp
+}
+
+// WitnessVersion returns the witness version of the AddressWitnessScriptHash.
+func (a *AddressWitnessScriptHash) WitnessVersion() byte {
+    return a.witnessVersion
+}
+
+// WitnessProgram returns the witness program of the AddressWitnessScriptHash.
+func (a *AddressWitnessScriptHash) WitnessProgram() []byte {
+    return a.witnessProgram[:]
+}
+
+// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
+// byte array.
+func (a *AddressWitnessScriptHash) Sha256() *[32]byte {
+    return &a.witnessProgram
+}
\ No newline at end of file
diff --git a/common/address_test.go b/common/address_test.go
new file mode 100644 (file)
index 0000000..745de9b
--- /dev/null
@@ -0,0 +1,384 @@
+package common
+
+import (
+    "bytes"
+    "fmt"
+    "reflect"
+    "strings"
+    "testing"
+
+    "github.com/bytom/consensus"
+    "github.com/bytom/common/bech32"
+
+)
+
+func TestAddresses(t *testing.T) {
+    tests := []struct {
+        name    string
+        addr    string
+        encoded string
+        valid   bool
+        result  Address
+        f       func() (Address, error)
+        net     *consensus.Params
+    }{
+        // Segwit address tests.
+        {
+            name:    "segwit mainnet p2wpkh v0",
+            addr:    "BM1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7K23GYYF",
+            encoded: "bm1qw508d6qejxtdg4y5r3zarvary0c5xw7k23gyyf",
+            valid:   true,
+            result: tstAddressWitnessPubKeyHash(
+                0,
+                [20]byte{
+                    0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+                    0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+                consensus.MainNetParams.Bech32HRPSegwit),
+            f: func() (Address, error) {
+                pkHash := []byte{
+                    0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+                    0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+                return NewAddressWitnessPubKeyHash(pkHash, &consensus.MainNetParams)
+            },
+            net: &consensus.MainNetParams,
+        },
+        {
+            name:    "segwit mainnet p2wsh v0",
+            addr:    "bm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qk5egtg",
+            encoded: "bm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qk5egtg",
+            valid:   true,
+            result: tstAddressWitnessScriptHash(
+                0,
+                [32]byte{
+                    0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+                    0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+                    0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+                    0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+                consensus.MainNetParams.Bech32HRPSegwit),
+            f: func() (Address, error) {
+                scriptHash := []byte{
+                    0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+                    0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+                    0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+                    0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+                return NewAddressWitnessScriptHash(scriptHash, &consensus.MainNetParams)
+            },
+            net: &consensus.MainNetParams,
+        },
+        {
+            name:    "segwit testnet p2wpkh v0",
+            addr:    "tm1qw508d6qejxtdg4y5r3zarvary0c5xw7kw8fqyc",
+            encoded: "tm1qw508d6qejxtdg4y5r3zarvary0c5xw7kw8fqyc",
+            valid:   true,
+            result: tstAddressWitnessPubKeyHash(
+                0,
+                [20]byte{
+                    0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+                    0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+                consensus.TestNetParams.Bech32HRPSegwit),
+            f: func() (Address, error) {
+                pkHash := []byte{
+                    0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+                    0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+                return NewAddressWitnessPubKeyHash(pkHash, &consensus.TestNetParams)
+            },
+            net: &consensus.TestNetParams,
+        },
+        {
+            name:    "segwit testnet p2wsh v0",
+            addr:    "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qqq379v",
+            encoded: "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qqq379v",
+            valid:   true,
+            result: tstAddressWitnessScriptHash(
+                0,
+                [32]byte{
+                    0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+                    0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+                    0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+                    0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+                consensus.TestNetParams.Bech32HRPSegwit),
+            f: func() (Address, error) {
+                scriptHash := []byte{
+                    0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+                    0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+                    0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+                    0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+                return NewAddressWitnessScriptHash(scriptHash, &consensus.TestNetParams)
+            },
+            net: &consensus.TestNetParams,
+        },
+        {
+            name:    "segwit testnet p2wsh witness v0",
+            addr:    "tm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesvkesyk",
+            encoded: "tm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesvkesyk",
+            valid:   true,
+            result:  tstAddressWitnessScriptHash(
+                0,
+                [32]byte{
+                    0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+                    0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+                    0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+                    0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33},
+                consensus.TestNetParams.Bech32HRPSegwit),
+            f: func() (Address, error) {
+                scriptHash := []byte{
+                    0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+                    0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+                    0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+                    0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}
+                return NewAddressWitnessScriptHash(scriptHash, &consensus.TestNetParams)
+            },
+            net: &consensus.TestNetParams,
+        },
+        // Unsupported witness versions (version 0 only supported at this point)
+        {
+            name:  "segwit mainnet witness v1",
+            addr:  "bm1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit mainnet witness v16",
+            addr:  "BM1SW50QA3JX3S",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit mainnet witness v2",
+            addr:  "bm1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        // Invalid segwit addresses
+        {
+            name:  "segwit invalid hrp",
+            addr:  "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
+            valid: false,
+            net:   &consensus.TestNetParams,
+        },
+        {
+            name:  "segwit invalid checksum",
+            addr:  "bm1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit invalid witness version",
+            addr:  "BM13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit invalid program length",
+            addr:  "bm1rw5uspcuh",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit invalid program length",
+            addr:  "bm10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit invalid program length for witness version 0 (per BIP141)",
+            addr:  "BM1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
+            valid: false,
+            net:   &consensus.MainNetParams,
+        },
+        {
+            name:  "segwit mixed case",
+            addr:  "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
+            valid: false,
+            net:   &consensus.TestNetParams,
+        },
+        {
+            name:  "segwit zero padding of more than 4 bits",
+            addr:  "tm1pw508d6qejxtdg4y5r3zarqfsj6c3",
+            valid: false,
+            net:   &consensus.TestNetParams,
+        },
+        {
+            name:  "segwit non-zero padding in 8-to-5 conversion",
+            addr:  "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
+            valid: false,
+            net:   &consensus.TestNetParams,
+        },
+    }
+
+    for _, test := range tests {
+        // Decode addr and compare error against valid.        
+        decoded, err := DecodeAddress(test.addr, test.net)
+        if (err == nil) != test.valid {
+            t.Errorf("%v: decoding test failed: %v", test.name, err)
+            return
+        }
+
+        if err == nil {
+            // Ensure the stringer returns the same address as the
+            // original.
+            
+            if decodedStringer, ok := decoded.(fmt.Stringer); ok {
+                addr := test.addr
+
+                // For Segwit addresses the string representation
+                // will always be lower case, so in that case we
+                // convert the original to lower case first.
+                if strings.Contains(test.name, "segwit") {
+                    addr = strings.ToLower(addr)
+                }
+
+                if addr != decodedStringer.String() {
+                    t.Errorf("%v: String on decoded value does not match expected value: %v != %v",
+                        test.name, test.addr, decodedStringer.String())
+                    return
+                }
+
+            }
+        
+            // Encode again and compare against the original.
+            encoded := decoded.EncodeAddress()
+            if test.encoded != encoded {
+                t.Errorf("%v: decoding and encoding produced different addressess: %v != %v",
+                    test.name, test.encoded, encoded)
+                return
+            }
+
+            // Perform type-specific calculations.
+            var saddr []byte
+            switch decoded.(type) {
+
+            case *AddressWitnessPubKeyHash:
+                saddr = tstAddressSegwitSAddr(encoded)
+            case *AddressWitnessScriptHash:
+                saddr = tstAddressSegwitSAddr(encoded)
+            }
+
+            // Check script address, as well as the Hash160 method for P2PKH and
+            // P2SH addresses.
+            if !bytes.Equal(saddr, decoded.ScriptAddress()) {
+                t.Errorf("%v: script addresses do not match:\n%x != \n%x",
+                    test.name, saddr, decoded.ScriptAddress())
+                return
+            }
+            switch a := decoded.(type) {
+
+            case *AddressWitnessPubKeyHash:
+                if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+                    t.Errorf("%v: hrps do not match:\n%x != \n%x",
+                        test.name, test.net.Bech32HRPSegwit, hrp)
+                    return
+                }
+
+                expVer := test.result.(*AddressWitnessPubKeyHash).WitnessVersion()
+                if v := a.WitnessVersion(); v != expVer {
+                    t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+                        test.name, expVer, v)
+                    return
+                }
+
+                if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+                    t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+                        test.name, saddr, p)
+                    return
+                }
+
+            case *AddressWitnessScriptHash:
+                if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+                    t.Errorf("%v: hrps do not match:\n%x != \n%x",
+                        test.name, test.net.Bech32HRPSegwit, hrp)
+                    return
+                }
+
+                expVer := test.result.(*AddressWitnessScriptHash).WitnessVersion()
+                if v := a.WitnessVersion(); v != expVer {
+                    t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+                        test.name, expVer, v)
+                    return
+                }
+
+                if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+                    t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+                        test.name, saddr, p)
+                    return
+                }
+            }
+
+            // Ensure the address is for the expected network.
+            if !decoded.IsForNet(test.net) {
+                t.Errorf("%v: calculated network does not match expected",
+                    test.name)
+                return
+            }
+        }
+
+        if !test.valid {
+            // If address is invalid, but a creation function exists,
+            // verify that it returns a nil addr and non-nil error.
+            if test.f != nil {
+                _, err := test.f()
+                if err == nil {
+                    t.Errorf("%v: address is invalid but creating new address succeeded",
+                        test.name)
+                    return
+                }
+            }
+            continue
+        }
+
+        // Valid test, compare address created with f against expected result.
+        addr, err := test.f()
+        if err != nil {
+            t.Errorf("%v: address is valid but creating new address failed with error %v",
+                test.name, err)
+            return
+        }
+
+        if !reflect.DeepEqual(addr, test.result) {
+            t.Errorf("%v: created address does not match expected result",
+                test.name)
+            return
+        }
+    }
+}
+
+
+// TstAddressWitnessPubKeyHash creates an AddressWitnessPubKeyHash, initiating
+// the fields as given.
+func tstAddressWitnessPubKeyHash(version byte, program [20]byte,
+    hrp string) *AddressWitnessPubKeyHash {
+
+    return &AddressWitnessPubKeyHash{
+        hrp:            hrp,
+        witnessVersion: version,
+        witnessProgram: program,
+    }
+}
+
+// TstAddressWitnessScriptHash creates an AddressWitnessScriptHash, initiating
+// the fields as given.
+func tstAddressWitnessScriptHash(version byte, program [32]byte,
+    hrp string) *AddressWitnessScriptHash {
+
+    return &AddressWitnessScriptHash{
+        hrp:            hrp,
+        witnessVersion: version,
+        witnessProgram: program,
+    }
+}
+
+// TstAddressSegwitSAddr returns the expected witness program bytes for
+// bech32 encoded P2WPKH and P2WSH bitcoin addresses.
+func tstAddressSegwitSAddr(addr string) []byte {
+    _, data, err := bech32.Decode(addr)
+    if err != nil {
+        return []byte{}
+    }
+
+    // First byte is version, rest is base 32 encoded data.
+    data, err = bech32.ConvertBits(data[1:], 5, 8, false)
+    if err != nil {
+        return []byte{}
+    }
+    return data
+}
diff --git a/common/bech32.go b/common/bech32.go
deleted file mode 100644 (file)
index 98ab5b9..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-// Package bech32 reference implementation for Bech32 and segwit addresses.
-// Copyright (c) 2017 Takatoshi Nakagawa
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-package common
-
-import (
-       "bytes"
-       "fmt"
-       "strings"
-)
-
-var charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
-
-var generator = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
-
-func polymod(values []int) int {
-       chk := 1
-       for _, v := range values {
-               top := chk >> 25
-               chk = (chk&0x1ffffff)<<5 ^ v
-               for i := 0; i < 5; i++ {
-                       if (top>>uint(i))&1 == 1 {
-                               chk ^= generator[i]
-                       }
-               }
-       }
-       return chk
-}
-
-func hrpExpand(hrp string) []int {
-       ret := []int{}
-       for _, c := range hrp {
-               ret = append(ret, int(c>>5))
-       }
-       ret = append(ret, 0)
-       for _, c := range hrp {
-               ret = append(ret, int(c&31))
-       }
-       return ret
-}
-
-func verifyChecksum(hrp string, data []int) bool {
-       return polymod(append(hrpExpand(hrp), data...)) == 1
-}
-
-func createChecksum(hrp string, data []int) []int {
-       values := append(append(hrpExpand(hrp), data...), []int{0, 0, 0, 0, 0, 0}...)
-       mod := polymod(values) ^ 1
-       ret := make([]int, 6)
-       for p := 0; p < len(ret); p++ {
-               ret[p] = (mod >> uint(5*(5-p))) & 31
-       }
-       return ret
-}
-
-// Encode encodes hrp(human-readable part) and data(32bit data array), returns Bech32 / or error
-// if hrp is uppercase, return uppercase Bech32
-func Encode(hrp string, data []int) (string, error) {
-       if (len(hrp) + len(data) + 7) > 90 {
-               return "", fmt.Errorf("too long : hrp length=%d, data length=%d", len(hrp), len(data))
-       }
-       if len(hrp) < 1 {
-               return "", fmt.Errorf("invalid hrp : hrp=%v", hrp)
-       }
-       for p, c := range hrp {
-               if c < 33 || c > 126 {
-                       return "", fmt.Errorf("invalid character human-readable part : hrp[%d]=%d", p, c)
-               }
-       }
-       if strings.ToUpper(hrp) != hrp && strings.ToLower(hrp) != hrp {
-               return "", fmt.Errorf("mix case : hrp=%v", hrp)
-       }
-       lower := strings.ToLower(hrp) == hrp
-       hrp = strings.ToLower(hrp)
-       combined := append(data, createChecksum(hrp, data)...)
-       var ret bytes.Buffer
-       ret.WriteString(hrp)
-       ret.WriteString("1")
-       for idx, p := range combined {
-               if p < 0 || p >= len(charset) {
-                       return "", fmt.Errorf("invalid data : data[%d]=%d", idx, p)
-               }
-               ret.WriteByte(charset[p])
-       }
-       if lower {
-               return ret.String(), nil
-       }
-       return strings.ToUpper(ret.String()), nil
-}
-
-// Decode decodes bechString(Bech32) returns hrp(human-readable part) and data(32bit data array) / or error
-func Decode(bechString string) (string, []int, error) {
-       if len(bechString) > 90 {
-               return "", nil, fmt.Errorf("too long : len=%d", len(bechString))
-       }
-       if strings.ToLower(bechString) != bechString && strings.ToUpper(bechString) != bechString {
-               return "", nil, fmt.Errorf("mixed case")
-       }
-       bechString = strings.ToLower(bechString)
-       pos := strings.LastIndex(bechString, "1")
-       if pos < 1 || pos+7 > len(bechString) {
-               return "", nil, fmt.Errorf("separator '1' at invalid position : pos=%d , len=%d", pos, len(bechString))
-       }
-       hrp := bechString[0:pos]
-       for p, c := range hrp {
-               if c < 33 || c > 126 {
-                       return "", nil, fmt.Errorf("invalid character human-readable part : bechString[%d]=%d", p, c)
-               }
-       }
-       data := []int{}
-       for p := pos + 1; p < len(bechString); p++ {
-               d := strings.Index(charset, fmt.Sprintf("%c", bechString[p]))
-               if d == -1 {
-                       return "", nil, fmt.Errorf("invalid character data part : bechString[%d]=%d", p, bechString[p])
-               }
-               data = append(data, d)
-       }
-       if !verifyChecksum(hrp, data) {
-               return "", nil, fmt.Errorf("invalid checksum")
-       }
-       return hrp, data[:len(data)-6], nil
-}
-
-func convertbits(data []int, frombits, tobits uint, pad bool) ([]int, error) {
-       acc := 0
-       bits := uint(0)
-       ret := []int{}
-       maxv := (1 << tobits) - 1
-       for idx, value := range data {
-               if value < 0 || (value>>frombits) != 0 {
-                       return nil, fmt.Errorf("invalid data range : data[%d]=%d (frombits=%d)", idx, value, frombits)
-               }
-               acc = (acc << frombits) | value
-               bits += frombits
-               for bits >= tobits {
-                       bits -= tobits
-                       ret = append(ret, (acc>>bits)&maxv)
-               }
-       }
-       if pad {
-               if bits > 0 {
-                       ret = append(ret, (acc<<(tobits-bits))&maxv)
-               }
-       } else if bits >= frombits {
-               return nil, fmt.Errorf("illegal zero padding")
-       } else if ((acc << (tobits - bits)) & maxv) != 0 {
-               return nil, fmt.Errorf("non-zero padding")
-       }
-       return ret, nil
-}
-
-// AddressDecode decodes hrp(human-readable part) Address(string), returns version(int) and data(bytes array) / or error
-func AddressDecode(hrp, addr string) (int, []int, error) {
-       dechrp, data, err := Decode(addr)
-       if err != nil {
-               return -1, nil, err
-       }
-       if dechrp != hrp {
-               return -1, nil, fmt.Errorf("invalid human-readable part : %s != %s", hrp, dechrp)
-       }
-       if len(data) < 1 {
-               return -1, nil, fmt.Errorf("invalid decode data length : %d", len(data))
-       }
-       if data[0] > 16 {
-               return -1, nil, fmt.Errorf("invalid address version : %d", data[0])
-       }
-       res, err := convertbits(data[1:], 5, 8, false)
-       if err != nil {
-               return -1, nil, err
-       }
-       if len(res) < 2 || len(res) > 40 {
-               return -1, nil, fmt.Errorf("invalid convertbits length : %d", len(res))
-       }
-       if data[0] == 0 && len(res) != 20 && len(res) != 32 {
-               return -1, nil, fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(res))
-       }
-       return data[0], res, nil
-}
-
-// AddressEncode encodes hrp(human-readable part) , version(int) and data(bytes array), returns  Address / or error
-func AddressEncode(hrp string, version int, pubkey []int) (string, error) {
-       if version < 0 || version > 16 {
-               return "", fmt.Errorf("invalid version : %d", version)
-       }
-       if len(pubkey) < 2 || len(pubkey) > 40 {
-               return "", fmt.Errorf("invalid pubkey hash length : %d", len(pubkey))
-       }
-       if version == 0 && len(pubkey) != 20 && len(pubkey) != 32 {
-               return "", fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(pubkey))
-       }
-       data, err := convertbits(pubkey, 8, 5, true)
-       if err != nil {
-               return "", err
-       }
-       ret, err := Encode(hrp, append([]int{version}, data...))
-       if err != nil {
-               return "", err
-       }
-       return ret, nil
-}
diff --git a/common/bech32/README.md b/common/bech32/README.md
new file mode 100644 (file)
index 0000000..e6fa43f
--- /dev/null
@@ -0,0 +1,29 @@
+bech32
+==========
+
+[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
+[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![GoDoc](https://godoc.org/github.com/btcsuite/btcutil/bech32?status.png)](http://godoc.org/github.com/btcsuite/btcutil/bech32)
+
+Package bech32 provides a Go implementation of the bech32 format specified in
+[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
+
+Test vectors from BIP 173 are added to ensure compatibility with the BIP.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcutil/bech32
+```
+
+## Examples
+
+* [Bech32 decode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-Bech32Decode)
+  Demonstrates how to decode a bech32 encoded string.
+* [Bech32 encode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-BechEncode)
+  Demonstrates how to encode data into a bech32 string.
+
+## License
+
+Package bech32 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/common/bech32/bech32.go b/common/bech32/bech32.go
new file mode 100644 (file)
index 0000000..8bda0a1
--- /dev/null
@@ -0,0 +1,252 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32
+
+import (
+       "fmt"
+       "strings"
+)
+
+const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+
+var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
+
+// Decode decodes a bech32 encoded string, returning the human-readable
+// part and the data part excluding the checksum.
+func Decode(bech string) (string, []byte, error) {
+       // The maximum allowed length for a bech32 string is 90. It must also
+       // be at least 8 characters, since it needs a non-empty HRP, a
+       // separator, and a 6 character checksum.
+       if len(bech) < 8 || len(bech) > 90 {
+               return "", nil, fmt.Errorf("invalid bech32 string length %d",
+                       len(bech))
+       }
+       // Only ASCII characters between 33 and 126 are allowed.
+       for i := 0; i < len(bech); i++ {
+               if bech[i] < 33 || bech[i] > 126 {
+                       return "", nil, fmt.Errorf("invalid character in "+
+                               "string: '%c'", bech[i])
+               }
+       }
+
+       // The characters must be either all lowercase or all uppercase.
+       lower := strings.ToLower(bech)
+       upper := strings.ToUpper(bech)
+       if bech != lower && bech != upper {
+               return "", nil, fmt.Errorf("string not all lowercase or all " +
+                       "uppercase")
+       }
+
+       // We'll work with the lowercase string from now on.
+       bech = lower
+
+       // The string is invalid if the last '1' is non-existent, it is the
+       // first character of the string (no human-readable part) or one of the
+       // last 6 characters of the string (since checksum cannot contain '1'),
+       // or if the string is more than 90 characters in total.
+       one := strings.LastIndexByte(bech, '1')
+       if one < 1 || one+7 > len(bech) {
+               return "", nil, fmt.Errorf("invalid index of 1")
+       }
+
+       // The human-readable part is everything before the last '1'.
+       hrp := bech[:one]
+       data := bech[one+1:]
+
+       // Each character corresponds to the byte with value of the index in
+       // 'charset'.
+       decoded, err := toBytes(data)
+       if err != nil {
+               return "", nil, fmt.Errorf("failed converting data to bytes: "+
+                       "%v", err)
+       }
+
+       if !bech32VerifyChecksum(hrp, decoded) {
+               moreInfo := ""
+               checksum := bech[len(bech)-6:]
+               expected, err := toChars(bech32Checksum(hrp,
+                       decoded[:len(decoded)-6]))
+               if err == nil {
+                       moreInfo = fmt.Sprintf("Expected %v, got %v.",
+                               expected, checksum)
+               }
+               return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
+       }
+
+       // We exclude the last 6 bytes, which is the checksum.
+       return hrp, decoded[:len(decoded)-6], nil
+}
+
+// Encode encodes a byte slice into a bech32 string with the
+// human-readable part hrb. Note that the bytes must each encode 5 bits
+// (base32).
+func Encode(hrp string, data []byte) (string, error) {
+       // Calculate the checksum of the data and append it at the end.
+       checksum := bech32Checksum(hrp, data)
+       combined := append(data, checksum...)
+
+       // The resulting bech32 string is the concatenation of the hrp, the
+       // separator 1, data and checksum. Everything after the separator is
+       // represented using the specified charset.
+       dataChars, err := toChars(combined)
+       if err != nil {
+               return "", fmt.Errorf("unable to convert data bytes to chars: "+
+                       "%v", err)
+       }
+       return hrp + "1" + dataChars, nil
+}
+
+// toBytes converts each character in the string 'chars' to the value of the
+// index of the correspoding character in 'charset'.
+func toBytes(chars string) ([]byte, error) {
+       decoded := make([]byte, 0, len(chars))
+       for i := 0; i < len(chars); i++ {
+               index := strings.IndexByte(charset, chars[i])
+               if index < 0 {
+                       return nil, fmt.Errorf("invalid character not part of "+
+                               "charset: %v", chars[i])
+               }
+               decoded = append(decoded, byte(index))
+       }
+       return decoded, nil
+}
+
+// toChars converts the byte slice 'data' to a string where each byte in 'data'
+// encodes the index of a character in 'charset'.
+func toChars(data []byte) (string, error) {
+       result := make([]byte, 0, len(data))
+       for _, b := range data {
+               if int(b) >= len(charset) {
+                       return "", fmt.Errorf("invalid data byte: %v", b)
+               }
+               result = append(result, charset[b])
+       }
+       return string(result), nil
+}
+
+// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
+// to a byte slice where each byte is encoding toBits bits.
+func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
+       if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
+               return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
+       }
+
+       // The final bytes, each byte encoding toBits bits.
+       var regrouped []byte
+
+       // Keep track of the next byte we create and how many bits we have
+       // added to it out of the toBits goal.
+       nextByte := byte(0)
+       filledBits := uint8(0)
+
+       for _, b := range data {
+
+               // Discard unused bits.
+               b = b << (8 - fromBits)
+
+               // How many bits remaining to extract from the input data.
+               remFromBits := fromBits
+               for remFromBits > 0 {
+                       // How many bits remaining to be added to the next byte.
+                       remToBits := toBits - filledBits
+
+                       // The number of bytes to next extract is the minimum of
+                       // remFromBits and remToBits.
+                       toExtract := remFromBits
+                       if remToBits < toExtract {
+                               toExtract = remToBits
+                       }
+
+                       // Add the next bits to nextByte, shifting the already
+                       // added bits to the left.
+                       nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
+
+                       // Discard the bits we just extracted and get ready for
+                       // next iteration.
+                       b = b << toExtract
+                       remFromBits -= toExtract
+                       filledBits += toExtract
+
+                       // If the nextByte is completely filled, we add it to
+                       // our regrouped bytes and start on the next byte.
+                       if filledBits == toBits {
+                               regrouped = append(regrouped, nextByte)
+                               filledBits = 0
+                               nextByte = 0
+                       }
+               }
+       }
+
+       // We pad any unfinished group if specified.
+       if pad && filledBits > 0 {
+               nextByte = nextByte << (toBits - filledBits)
+               regrouped = append(regrouped, nextByte)
+               filledBits = 0
+               nextByte = 0
+       }
+
+       // Any incomplete group must be <= 4 bits, and all zeroes.
+       if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
+               return nil, fmt.Errorf("invalid incomplete group")
+       }
+
+       return regrouped, nil
+}
+
+// For more details on the checksum calculation, please refer to BIP 173.
+func bech32Checksum(hrp string, data []byte) []byte {
+       // Convert the bytes to list of integers, as this is needed for the
+       // checksum calculation.
+       integers := make([]int, len(data))
+       for i, b := range data {
+               integers[i] = int(b)
+       }
+       values := append(bech32HrpExpand(hrp), integers...)
+       values = append(values, []int{0, 0, 0, 0, 0, 0}...)
+       polymod := bech32Polymod(values) ^ 1
+       var res []byte
+       for i := 0; i < 6; i++ {
+               res = append(res, byte((polymod>>uint(5*(5-i)))&31))
+       }
+       return res
+}
+
+// For more details on the polymod calculation, please refer to BIP 173.
+func bech32Polymod(values []int) int {
+       chk := 1
+       for _, v := range values {
+               b := chk >> 25
+               chk = (chk&0x1ffffff)<<5 ^ v
+               for i := 0; i < 5; i++ {
+                       if (b>>uint(i))&1 == 1 {
+                               chk ^= gen[i]
+                       }
+               }
+       }
+       return chk
+}
+
+// For more details on HRP expansion, please refer to BIP 173.
+func bech32HrpExpand(hrp string) []int {
+       v := make([]int, 0, len(hrp)*2+1)
+       for i := 0; i < len(hrp); i++ {
+               v = append(v, int(hrp[i]>>5))
+       }
+       v = append(v, 0)
+       for i := 0; i < len(hrp); i++ {
+               v = append(v, int(hrp[i]&31))
+       }
+       return v
+}
+
+// For more details on the checksum verification, please refer to BIP 173.
+func bech32VerifyChecksum(hrp string, data []byte) bool {
+       integers := make([]int, len(data))
+       for i, b := range data {
+               integers[i] = int(b)
+       }
+       concat := append(bech32HrpExpand(hrp), integers...)
+       return bech32Polymod(concat) == 1
+}
diff --git a/common/bech32/bech32_test.go b/common/bech32/bech32_test.go
new file mode 100644 (file)
index 0000000..1322386
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32_test
+
+import (
+       "strings"
+       "testing"
+
+       "github.com/btcsuite/btcutil/bech32"
+)
+
+func TestBech32(t *testing.T) {
+       tests := []struct {
+               str   string
+               valid bool
+       }{
+               {"A12UEL5L", true},
+               {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", true},
+               {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", true},
+               {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", true},
+               {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", true},
+               {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", false},                                // invalid checksum
+               {"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", false},                                // invalid character (space) in hrp
+               {"spl" + string(127) + "t1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false},              // invalid character (DEL) in hrp
+               {"split1cheo2y9e2w", false},                                                                            // invalid character (o) in data part
+               {"split1a2y9w", false},                                                                                 // too short data part
+               {"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false},                                     // empty hrp
+               {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", false}, // too long
+       }
+
+       for _, test := range tests {
+               str := test.str
+               hrp, decoded, err := bech32.Decode(str)
+               if !test.valid {
+                       // Invalid string decoding should result in error.
+                       if err == nil {
+                               t.Error("expected decoding to fail for "+
+                                       "invalid string %v", test.str)
+                       }
+                       continue
+               }
+
+               // Valid string decoding should result in no error.
+               if err != nil {
+                       t.Errorf("expected string to be valid bech32: %v", err)
+               }
+
+               // Check that it encodes to the same string
+               encoded, err := bech32.Encode(hrp, decoded)
+               if err != nil {
+                       t.Errorf("encoding failed: %v", err)
+               }
+
+               if encoded != strings.ToLower(str) {
+                       t.Errorf("expected data to encode to %v, but got %v",
+                               str, encoded)
+               }
+
+               // Flip a bit in the string an make sure it is caught.
+               pos := strings.LastIndexAny(str, "1")
+               flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
+               _, _, err = bech32.Decode(flipped)
+               if err == nil {
+                       t.Error("expected decoding to fail")
+               }
+       }
+}
diff --git a/common/bech32/doc.go b/common/bech32/doc.go
new file mode 100644 (file)
index 0000000..2d64fbe
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package bech32 provides a Go implementation of the bech32 format specified in
+BIP 173.
+
+Bech32 strings consist of a human-readable part (hrp), followed by the
+separator 1, then a checksummed data part encoded using the 32 characters
+"qpzry9x8gf2tvdw0s3jn54khce6mua7l".
+
+More info: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+*/
+package bech32
diff --git a/common/bech32/example_test.go b/common/bech32/example_test.go
new file mode 100644 (file)
index 0000000..515f0a9
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32_test
+
+import (
+       "encoding/hex"
+       "fmt"
+
+       "github.com/btcsuite/btcutil/bech32"
+)
+
+// This example demonstrates how to decode a bech32 encoded string.
+func ExampleDecode() {
+       encoded := "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"
+       hrp, decoded, err := bech32.Decode(encoded)
+       if err != nil {
+               fmt.Println("Error:", err)
+       }
+
+       // Show the decoded data.
+       fmt.Println("Decoded human-readable part:", hrp)
+       fmt.Println("Decoded Data:", hex.EncodeToString(decoded))
+
+       // Output:
+       // Decoded human-readable part: bc
+       // Decoded Data: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
+}
+
+// This example demonstrates how to encode data into a bech32 string.
+func ExampleEncode() {
+       data := []byte("Test data")
+       // Convert test data to base32:
+       conv, err := bech32.ConvertBits(data, 8, 5, true)
+       if err != nil {
+               fmt.Println("Error:", err)
+       }
+       encoded, err := bech32.Encode("customHrp!11111q", conv)
+       if err != nil {
+               fmt.Println("Error:", err)
+       }
+
+       // Show the encoded data.
+       fmt.Println("Encoded Data:", encoded)
+
+       // Output:
+       // Encoded Data: customHrp!11111q123jhxapqv3shgcgumastr
+}
diff --git a/common/bech32_test.go b/common/bech32_test.go
deleted file mode 100644 (file)
index 6b21379..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright (c) 2017 Takatoshi Nakagawa
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-package common
-
-import (
-       "reflect"
-       "strings"
-       "testing"
-)
-
-func ScriptPubkey(version int, program []int) []int {
-       if version != 0 {
-               version += 0x50
-       }
-       return append(append([]int{version}, len(program)), program...)
-}
-
-var validChecksum = []string{
-       "A12UEL5L",
-       "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
-       "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
-       "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
-       "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
-}
-
-type item struct {
-       address      string
-       scriptpubkey []int
-}
-
-var validAddress = []item{
-       item{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
-               []int{
-                       0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
-                       0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
-               },
-       },
-       item{"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
-               []int{
-                       0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
-                       0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
-                       0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
-                       0x62,
-               },
-       },
-       item{"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
-               []int{
-                       0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
-                       0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
-                       0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
-                       0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
-               },
-       },
-       item{"BC1SW50QA3JX3S",
-               []int{
-                       0x60, 0x02, 0x75, 0x1e,
-               },
-       },
-       item{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
-               []int{
-                       0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
-                       0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23,
-               },
-       },
-       item{"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
-               []int{
-                       0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
-                       0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
-                       0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
-                       0x33,
-               },
-       },
-}
-
-var invalidAddress = []string{
-       "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
-       "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
-       "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
-       "bc1rw5uspcuh",
-       "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
-       "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
-       "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
-       "tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
-       "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
-}
-
-func TestValidChecksum(t *testing.T) {
-       for _, test := range validChecksum {
-               hrp, data, err := Decode(test)
-               if err != nil {
-                       t.Errorf("Valid checksum for %s : FAIL / error %+v\n", test, err)
-               } else {
-                       t.Logf("Valid checksum for %s : ok / hrp : %+v , data : %+v\n", test, hrp, data)
-               }
-       }
-}
-
-func TestValidAddress(t *testing.T) {
-       for _, test := range validAddress {
-               hrp := "bc"
-               version, program, err := AddressDecode(hrp, test.address)
-               if err != nil {
-                       hrp = "tb"
-                       version, program, err = AddressDecode(hrp, test.address)
-               }
-               ok := err == nil
-               if ok {
-                       output := ScriptPubkey(version, program)
-                       ok = reflect.DeepEqual(output, test.scriptpubkey)
-               }
-               if ok {
-                       recreate, err := AddressEncode(hrp, version, program)
-                       if err == nil {
-                               ok = recreate == strings.ToLower(test.address)
-                       }
-               }
-               if ok {
-                       t.Logf("Valid address %v : ok\n", test.address)
-               } else {
-                       t.Errorf("Valid address %v : FAIL\n", test.address)
-               }
-       }
-}
-
-func TestInvalidAddress(t *testing.T) {
-       for _, test := range invalidAddress {
-               _, _, bcErr := AddressDecode("bc", test)
-               t.Logf("bc error:%v\n", bcErr)
-               _, _, tbErr := AddressDecode("tb", test)
-               t.Logf("tb error:%v\n", tbErr)
-               if bcErr != nil && tbErr != nil {
-                       t.Logf("Invalid address %v : ok\n", test)
-               } else {
-                       t.Errorf("Invalid address %v : FAIL\n", test)
-               }
-       }
-}
-
-// add coverage tests
-
-func TestCoverage(t *testing.T) {
-       var err error
-       var bech32String string
-       var hrp string
-       var data []int
-
-       // AddressEncode
-       bech32String, err = AddressEncode("bc", 1, []int{0, 1})
-       if err != nil {
-               t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
-       } else {
-               t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
-       }
-       data = make([]int, 40)
-       bech32String, err = AddressEncode("bc", 16, data)
-       if err != nil {
-               t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
-       } else {
-               t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
-       }
-       data = make([]int, 20)
-       bech32String, err = AddressEncode("bc", 0, data)
-       if err != nil {
-               t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
-       } else {
-               t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
-       }
-       data = make([]int, 32)
-       bech32String, err = AddressEncode("bc", 0, data)
-       if err != nil {
-               t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
-       } else {
-               t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
-       }
-       data = make([]int, 1)
-       _, err = AddressEncode("bc", 1, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid program length error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid program length error case : ok / error :", err)
-       }
-       data = make([]int, 41)
-       _, err = AddressEncode("bc", 1, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid program length error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid program length error case : ok / error :", err)
-       }
-       data = make([]int, 26)
-       _, err = AddressEncode("bc", 0, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid program length for witness version 0 (per BIP141) error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid program length for witness version 0 (per BIP141) error case : ok / error :", err)
-       }
-       data = make([]int, 20)
-       _, err = AddressEncode("Bc", 0, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode Encode error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode Encode error case : ok / error :", err)
-       }
-       _, err = AddressEncode("bc", 1, []int{-1, 0})
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid data range error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid data range error case : ok / error :", err)
-       }
-       _, err = AddressEncode("bc", -1, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid witness version error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid witness version error case : ok / error :", err)
-       }
-       _, err = AddressEncode("bc", 17, data)
-       if err == nil {
-               t.Errorf("Coverage AddressEncode invalid witness version error case : FAIL")
-       } else {
-               t.Log("Coverage AddressEncode invalid witness version error case : ok / error :", err)
-       }
-
-       // SegwitAddrDecode
-       _, _, err = AddressDecode("a", "A12UEL5L")
-       if err == nil {
-               t.Errorf("Coverage SegwitAddrDecode invalid decode data length error case : FAIL")
-       } else {
-               t.Log("Coverage SegwitAddrDecode invalid decode data length error case : ok / error :", err)
-       }
-
-       // Decode
-       _, _, err = Decode("!~1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc356v3")
-       if err != nil {
-               t.Errorf("Coverage Decode normal case : FAIL / error :%v", err)
-       } else {
-               t.Log("Coverage Decode normal case : ok")
-       }
-       _, _, err = Decode("a1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")
-       if err == nil {
-               t.Errorf("Coverage Decode too long error case : FAIL")
-       } else {
-               t.Log("Coverage Decode too long error case : ok / error :", err)
-       }
-       _, _, err = Decode("1")
-       if err == nil {
-               t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL")
-       } else {
-               t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err)
-       }
-       _, _, err = Decode("a1qqqqq")
-       if err == nil {
-               t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL")
-       } else {
-               t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err)
-       }
-       _, _, err = Decode("a" + string(32) + "1qqqqqq")
-       if err == nil {
-               t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL")
-       } else {
-               t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err)
-       }
-       _, _, err = Decode("a" + string(127) + "1qqqqqq")
-       if err == nil {
-               t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL")
-       } else {
-               t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err)
-       }
-       _, _, err = Decode("a1qqqqqb")
-       if err == nil {
-               t.Errorf("Coverage Decode invalid character data part error case : FAIL")
-       } else {
-               t.Log("Coverage Decode invalid character data part erroer case : ok / error :", err)
-       }
-
-       // Encode
-       hrp = "bc"
-       data = []int{}
-       bech32String, err = Encode(hrp, data)
-       if err != nil || bech32String != strings.ToLower(bech32String) {
-               t.Errorf("Coverage Encode lower case : FAIL / bech32String : %v , error : %v", bech32String, err)
-       } else {
-               t.Log("Coverage Encode lower case : ok / bech32String : ", bech32String)
-       }
-       hrp = "BC"
-       bech32String, err = Encode(hrp, data)
-       if err != nil || bech32String != strings.ToUpper(bech32String) {
-               t.Errorf("Coverage Encode upper case : FAIL / bech32String : %v , error : %v", bech32String, err)
-       } else {
-               t.Log("Coverage Encode upper case : ok / bech32String : ", bech32String)
-       }
-       hrp = "bc"
-       data = make([]int, 90-7-len(hrp)+1)
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode too long error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode too long error case : ok / error : ", err)
-       }
-       hrp = ""
-       data = make([]int, 90-7-len(hrp))
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode invalid hrp error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode invalid hrp error case : ok / error : ", err)
-       }
-       hrp = "Bc"
-       data = make([]int, 90-7-len(hrp))
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode mix case error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode mix case error case : ok / error : ", err)
-       }
-       hrp = string(33) + string(126)
-       data = make([]int, 90-7-len(hrp))
-       bech32String, err = Encode(hrp, data)
-       if err != nil {
-               t.Errorf("Coverage Encode normal case : FAIL / error : %v", err)
-       } else {
-               t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String)
-       }
-       hrp = string(32) + "c"
-       data = make([]int, 90-7-len(hrp))
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err)
-       }
-       hrp = "b" + string(127)
-       data = make([]int, 90-7-len(hrp))
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err)
-       }
-       hrp = "bc"
-       data = []int{0, 31}
-       bech32String, err = Encode(hrp, data)
-       if err != nil {
-               t.Errorf("Coverage Encode normal case : FAIL / error : %v", err)
-       } else {
-               t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String)
-       }
-       hrp = "bc"
-       data = []int{-1}
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode invalid data error case : ok / error : ", err)
-       }
-       hrp = "bc"
-       data = []int{32}
-       bech32String, err = Encode(hrp, data)
-       if err == nil {
-               t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String)
-       } else {
-               t.Log("Coverage Encode invalid data error case : ok / error : ", err)
-       }
-}
index 29b6fb2..b63ce3a 100644 (file)
@@ -114,6 +114,7 @@ func EmptyHash(h Hash) bool {
 }
 
 /////////// Address
+/*
 func BytesToAddress(b []byte) Address {
        var a Address
        a.SetBytes(b)
@@ -195,3 +196,4 @@ func PP(value []byte) string {
 
        return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4])
 }
+*/
\ No newline at end of file
index cfea436..e4c7b31 100644 (file)
@@ -9,7 +9,7 @@ import (
 type Config struct {
        // Top level options use an anonymous struct
        BaseConfig `mapstructure:",squash"`
-
+       ChainConfig 
        // Options for services
        RPC *RPCConfig `mapstructure:"rpc"`
        P2P *P2PConfig `mapstructure:"p2p"`
@@ -50,9 +50,6 @@ type BaseConfig struct {
        // This should be set in viper so it can unmarshal into this struct
        RootDir string `mapstructure:"home"`
 
-       // The ID of the chain to join (should be signed with every transaction and vote)
-       ChainID string `mapstructure:"chain_id"`
-
        // A JSON file containing the initial validator set and other meta data
        Genesis string `mapstructure:"genesis_file"`
 
@@ -139,6 +136,26 @@ func DefaultPackageLogLevels() string {
        return fmt.Sprintf("state:info,*:%s", DefaultLogLevel())
 }
 
+
+//-----------------------------------------------------------------------------
+// ChainConfig
+
+type ChainConfig struct {
+       // The ID of the chain to join (should be signed with every transaction and vote)
+       ChainID string `mapstructure:"chain_id"`
+               // Human-readable part for Bech32 encoded segwit addresses, as defined
+       // in BIP 173.
+       Bech32HRPSegwit string `mapstructure:"bech32_hrp"`
+
+}
+
+func DefaultChainConfig() *ChainConfig {
+       return &ChainConfig{
+               ChainID:     "bytom-main",
+               Bech32HRPSegwit: "bm"
+       }
+}
+
 //-----------------------------------------------------------------------------
 // RPCConfig
 
index c694fb0..c40d8f3 100644 (file)
@@ -1,6 +1,7 @@
 package consensus
 
 import (
+       "strings"
        "github.com/bytom/protocol/bc"
 )
 
@@ -38,3 +39,38 @@ func BlockSubsidy(height uint64) uint64 {
 func InitBlock() []byte {
        return []byte("0301000000000000000000000000000000000000000000000000000000000000000000ece090e7eb2b4078a79ed5c640a026361c4af77a37342e503cc68493229996e11dd9be38b18f5b492159980684155da19e87de0d1b37b35c1a1123770ec1dcc710aabe77607cce00b1c5a181808080802e0107010700ece090e7eb2b000001012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8080ccdee2a69fb314010151000000")
 }
+
+
+// IsBech32SegwitPrefix returns whether the prefix is a known prefix for segwit
+// addresses on any default or registered network.  This is used when decoding
+// an address string into a specific address type.
+func IsBech32SegwitPrefix(prefix string,  params *Params) bool {
+       prefix = strings.ToLower(prefix)
+       if prefix == params.Bech32HRPSegwit+"1"  {
+               return true
+       } else {
+               return false
+       }
+}
+
+
+type Params struct {
+       // Name defines a human-readable identifier for the network.
+       Name string
+
+       Bech32HRPSegwit string
+
+}
+
+
+var MainNetParams = Params {
+       Name: "main",
+       Bech32HRPSegwit: "bm",
+}
+
+
+var TestNetParams = Params {
+       Name: "test",
+       Bech32HRPSegwit: "tm",
+}
+