From 11d1b7e9b8506cf4afc7d763d00fcdc8ac88e5ce Mon Sep 17 00:00:00 2001 From: Takatoshi Nakagawa Date: Tue, 11 Apr 2017 10:33:40 +0900 Subject: [PATCH] Add go reference implementation --- ref/go/src/bech32/bech32.go | 217 ++++++++++++++++++ ref/go/src/bech32/bech32_test.go | 380 +++++++++++++++++++++++++++++++ ref/go/test.sh | 5 + 3 files changed, 602 insertions(+) create mode 100644 ref/go/src/bech32/bech32.go create mode 100644 ref/go/src/bech32/bech32_test.go create mode 100755 ref/go/test.sh diff --git a/ref/go/src/bech32/bech32.go b/ref/go/src/bech32/bech32.go new file mode 100644 index 0000000..9af271b --- /dev/null +++ b/ref/go/src/bech32/bech32.go @@ -0,0 +1,217 @@ +// 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 bech32 + +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 +} + +// SegwitAddrDecode decodes hrp(human-readable part) Segwit Address(string), returns version(int) and data(bytes array) / or error +func SegwitAddrDecode(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 witness 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 +} + +// SegwitAddrEncode encodes hrp(human-readable part) , version(int) and data(bytes array), returns Segwit Address / or error +func SegwitAddrEncode(hrp string, version int, program []int) (string, error) { + if version < 0 || version > 16 { + return "", fmt.Errorf("invalid witness version : %d", version) + } + if len(program) < 2 || len(program) > 40 { + return "", fmt.Errorf("invalid program length : %d", len(program)) + } + if version == 0 && len(program) != 20 && len(program) != 32 { + return "", fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(program)) + } + data, err := convertbits(program, 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/ref/go/src/bech32/bech32_test.go b/ref/go/src/bech32/bech32_test.go new file mode 100644 index 0000000..4ce22c6 --- /dev/null +++ b/ref/go/src/bech32/bech32_test.go @@ -0,0 +1,380 @@ +// 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 bech32_test + +import ( + "bech32" + "reflect" + "strings" + "testing" +) + +func segwitScriptpubkey(version int, program []int) []int { + if version != 0 { + version += 0x80 + } + 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{ + 0x81, 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{ + 0x90, 0x02, 0x75, 0x1e, + }, + }, + item{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", + []int{ + 0x82, 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 := bech32.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 := bech32.SegwitAddrDecode(hrp, test.address) + if err != nil { + hrp = "tb" + version, program, err = bech32.SegwitAddrDecode(hrp, test.address) + } + ok := err == nil + if ok { + output := segwitScriptpubkey(version, program) + ok = reflect.DeepEqual(output, test.scriptpubkey) + } + if ok { + recreate, err := bech32.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 := bech32.SegwitAddrDecode("bc", test) + t.Logf("bc error:%v\n", bcErr) + _, _, tbErr := bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.Decode("!~1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc356v3") + if err != nil { + t.Errorf("Coverage Decode normal case : FAIL / error :%v", err) + } else { + t.Log("Coverage Decode normal case : ok") + } + _, _, err = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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 = bech32.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) + } +} diff --git a/ref/go/test.sh b/ref/go/test.sh new file mode 100755 index 0000000..cfdea76 --- /dev/null +++ b/ref/go/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export GOPATH=$(pwd) + +go test -v -cover bech32