220 lines
6.9 KiB
Go
Raw Normal View History

2021-11-22 16:05:02 +00:00
// 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 rpc
import (
"bytes"
"fmt"
"strings"
)
var charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
var generator = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
var length_check = false // dero removes length checks from bech32
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 length_check && (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 length_check && 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
}