github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/others/bech32/bech32.go (about)

     1  package bech32
     2  
     3  import (
     4  	"bytes"
     5  )
     6  
     7  func bech32_polymod_step(pre uint32) uint32 {
     8  	b := uint32(pre >> 25)
     9  	return ((pre & 0x1FFFFFF) << 5) ^
    10  		(-((b >> 0) & 1) & 0x3b6a57b2) ^
    11  		(-((b >> 1) & 1) & 0x26508e6d) ^
    12  		(-((b >> 2) & 1) & 0x1ea119fa) ^
    13  		(-((b >> 3) & 1) & 0x3d4233dd) ^
    14  		(-((b >> 4) & 1) & 0x2a1462b3)
    15  }
    16  
    17  func bech32_final_constant(bech32m bool) uint32 {
    18  	if bech32m {
    19  		return 0x2bc830a3
    20  	}
    21  	return 1
    22  }
    23  
    24  const (
    25  	charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
    26  )
    27  
    28  var (
    29  	charset_rev = [128]byte{
    30  		99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
    31  		99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
    32  		99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
    33  		15, 99, 10, 17, 21, 20, 26, 30, 7, 5, 99, 99, 99, 99, 99, 99,
    34  		99, 29, 99, 24, 13, 25, 9, 8, 23, 99, 18, 22, 31, 27, 19, 99,
    35  		1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, 99, 99, 99, 99, 99,
    36  		99, 29, 99, 24, 13, 25, 9, 8, 23, 99, 18, 22, 31, 27, 19, 99,
    37  		1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, 99, 99, 99, 99, 99}
    38  )
    39  
    40  // Encode returns an empty string on error.
    41  func Encode(hrp string, data []byte, bech32m bool) string {
    42  	var chk uint32 = 1
    43  	var i int
    44  	output := new(bytes.Buffer)
    45  	for i = range hrp {
    46  		ch := int(hrp[i])
    47  		if ch < 33 || ch > 126 {
    48  			return ""
    49  		}
    50  
    51  		if ch >= 'A' && ch <= 'Z' {
    52  			return ""
    53  		}
    54  		chk = bech32_polymod_step(chk) ^ (uint32(ch) >> 5)
    55  		i++
    56  	}
    57  	if i+7+len(data) > 90 {
    58  		return ""
    59  	}
    60  	chk = bech32_polymod_step(chk)
    61  	for i := range hrp {
    62  		tmp := hrp[i]
    63  		chk = bech32_polymod_step(chk) ^ uint32(tmp&0x1f)
    64  		output.WriteByte(tmp)
    65  	}
    66  	output.WriteByte('1')
    67  
    68  	for i = range data {
    69  		if (data[i] >> 5) != 0 {
    70  			return ""
    71  		}
    72  		chk = bech32_polymod_step(chk) ^ uint32(data[i])
    73  		output.WriteByte(charset[data[i]])
    74  	}
    75  	for i = 0; i < 6; i++ {
    76  		chk = bech32_polymod_step(chk)
    77  	}
    78  	chk ^= bech32_final_constant(bech32m)
    79  	for i = 0; i < 6; i++ {
    80  		output.WriteByte(charset[(chk>>uint((5-i)*5))&0x1f])
    81  	}
    82  	return output.String()
    83  }
    84  
    85  // Decode returns ("", nil) on error.
    86  func Decode(input string) (res_hrp string, res_data []byte, bech32m bool) {
    87  	var chk uint32 = 1
    88  	var i, data_len, hrp_len int
    89  	var have_lower, have_upper bool
    90  	if len(input) < 8 || len(input) > 90 {
    91  		return
    92  	}
    93  	for data_len < len(input) && input[(len(input)-1)-data_len] != '1' {
    94  		data_len++
    95  	}
    96  	hrp_len = len(input) - (1 + data_len)
    97  	if hrp_len < 1 || data_len < 6 {
    98  		return
    99  	}
   100  	data_len -= 6
   101  	hrp := make([]byte, hrp_len)
   102  	data := make([]byte, data_len)
   103  	for i = 0; i < hrp_len; i++ {
   104  		ch := input[i]
   105  		if ch < 33 || ch > 126 {
   106  			return
   107  		}
   108  		if ch >= 'a' && ch <= 'z' {
   109  			have_lower = true
   110  		} else if ch >= 'A' && ch <= 'Z' {
   111  			have_upper = true
   112  			ch = (ch - 'A') + 'a'
   113  		}
   114  		hrp[i] = ch
   115  		chk = bech32_polymod_step(chk) ^ uint32(ch>>5)
   116  	}
   117  	chk = bech32_polymod_step(chk)
   118  	for i = 0; i < hrp_len; i++ {
   119  		chk = bech32_polymod_step(chk) ^ uint32(input[i]&0x1f)
   120  	}
   121  	i++
   122  	for i < len(input) {
   123  		if (input[i] & 0x80) != 0 {
   124  			return
   125  		}
   126  		v := charset_rev[(input[i])]
   127  		if v > 31 {
   128  			return
   129  		}
   130  		if input[i] >= 'a' && input[i] <= 'z' {
   131  			have_lower = true
   132  		}
   133  		if input[i] >= 'A' && input[i] <= 'Z' {
   134  			have_upper = true
   135  		}
   136  		chk = bech32_polymod_step(chk) ^ uint32(v)
   137  		if i+6 < len(input) {
   138  			data[i-(1+hrp_len)] = v
   139  		}
   140  		i++
   141  	}
   142  	if have_lower && have_upper {
   143  		return
   144  	}
   145  	if chk == bech32_final_constant(false) {
   146  		res_hrp = string(hrp)
   147  		res_data = data
   148  	} else if chk == bech32_final_constant(true) {
   149  		res_hrp = string(hrp)
   150  		res_data = data
   151  		bech32m = true
   152  	}
   153  	return
   154  }