derohe-miniblock-mod/address/bech32_test.go

403 lines
14 KiB
Go

// 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 address
import (
"reflect"
"strings"
"testing"
)
func segwitScriptpubkey(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",
}
var invalidChecksum = []string{
" 1nwldj5",
"\x7F" + "1axkwrx",
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
"pzry9x0s0muk",
"1pzry9x0s0muk",
"x1b4n0q5v",
"li1dgmt3",
"de1lg7wt\xFF",
}
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",
"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
"bc1gmk9yu",
}
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 TestInvalidChecksum(t *testing.T) {
for _, test := range invalidChecksum {
hrp, data, err := Decode(test)
if err != nil {
t.Logf("Invalid checksum for %s : ok / hrp : %+v , data : %+v\n", test, hrp, data)
} else {
t.Errorf("Invalid checksum for %s : FAIL\n", test)
}
}
}
func TestValidAddress(t *testing.T) {
for _, test := range validAddress {
hrp := "bc"
version, program, err := SegwitAddrDecode(hrp, test.address)
if err != nil {
hrp = "tb"
version, program, err = SegwitAddrDecode(hrp, test.address)
}
ok := err == nil
if ok {
output := segwitScriptpubkey(version, program)
ok = reflect.DeepEqual(output, test.scriptpubkey)
}
if ok {
recreate, err := SegwitAddrEncode(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 := SegwitAddrDecode("bc", test)
t.Logf("bc error:%v\n", bcErr)
_, _, tbErr := SegwitAddrDecode("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
// SegwitAddrEncode
bech32String, err = SegwitAddrEncode("bc", 1, []int{0, 1})
if err != nil {
t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err)
} else {
t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String)
}
data = make([]int, 40)
bech32String, err = SegwitAddrEncode("bc", 16, data)
if err != nil {
t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err)
} else {
t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String)
}
data = make([]int, 20)
bech32String, err = SegwitAddrEncode("bc", 0, data)
if err != nil {
t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err)
} else {
t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String)
}
data = make([]int, 32)
bech32String, err = SegwitAddrEncode("bc", 0, data)
if err != nil {
t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err)
} else {
t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String)
}
data = make([]int, 1)
_, err = SegwitAddrEncode("bc", 1, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid program length error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid program length error case : ok / error :", err)
}
data = make([]int, 41)
_, err = SegwitAddrEncode("bc", 1, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid program length error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid program length error case : ok / error :", err)
}
data = make([]int, 26)
_, err = SegwitAddrEncode("bc", 0, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid program length for witness version 0 (per BIP141) error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid program length for witness version 0 (per BIP141) error case : ok / error :", err)
}
data = make([]int, 20)
_, err = SegwitAddrEncode("Bc", 0, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode Encode error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode Encode error case : ok / error :", err)
}
_, err = SegwitAddrEncode("bc", 1, []int{-1, 0})
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid data range error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid data range error case : ok / error :", err)
}
_, err = SegwitAddrEncode("bc", -1, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid witness version error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid witness version error case : ok / error :", err)
}
_, err = SegwitAddrEncode("bc", 17, data)
if err == nil {
t.Errorf("Coverage SegwitAddrEncode invalid witness version error case : FAIL")
} else {
t.Log("Coverage SegwitAddrEncode invalid witness version error case : ok / error :", err)
}
// SegwitAddrDecode
_, _, err = SegwitAddrDecode("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(rune(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(rune(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(rune(33)) + string(rune(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(rune(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(rune(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)
}
}