github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/address_oec.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/tendermint/go-amino"
     7  )
     8  
     9  const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
    10  
    11  const (
    12  	gen0 = 0x3b6a57b2
    13  	gen1 = 0x26508e6d
    14  	gen2 = 0x1ea119fa
    15  	gen3 = 0x3d4233dd
    16  	gen4 = 0x2a1462b3
    17  )
    18  
    19  var gen = []int{gen0, gen1, gen2, gen3, gen4}
    20  
    21  func (aa AccAddress) Bech32StringOptimized(bech32PrefixAccAddr string) string {
    22  	convertedLen := len(aa.Bytes())*8/5 + 1
    23  	resultLen := len(bech32PrefixAccAddr) + 1 + convertedLen + 6
    24  	var result = make([]byte, resultLen)
    25  
    26  	copy(result, bech32PrefixAccAddr)
    27  	result[len(bech32PrefixAccAddr)] = '1'
    28  
    29  	var err error
    30  	prefixLen := len(bech32PrefixAccAddr) + 1
    31  	converted := result[prefixLen:prefixLen]
    32  	converted, err = convertBitsTo(aa.Bytes(), 8, 5, true, converted)
    33  	if err != nil {
    34  		panic(fmt.Errorf("encoding bech32 failed %w", err))
    35  	}
    36  	if len(converted) > convertedLen {
    37  		panic("returned unexpected length")
    38  	}
    39  	if len(converted) < convertedLen {
    40  		result = result[0 : len(result)-(convertedLen-len(converted))]
    41  	}
    42  
    43  	bech32ChecksumTo(bech32PrefixAccAddr, converted, result[prefixLen+len(converted):])
    44  
    45  	err = toChars(result[prefixLen:])
    46  	if err != nil {
    47  		panic(fmt.Errorf("unable to convert data bytes to chars: "+
    48  			"%v", err))
    49  	}
    50  	return amino.BytesToStr(result)
    51  }
    52  
    53  // Encode encodes a byte slice into a bech32 string with the
    54  // human-readable part hrb. Note that the bytes must each encode 5 bits
    55  // (base32).
    56  func encode(hrp string, data []byte) (string, error) {
    57  	// Calculate the checksum of the data and append it at the end.
    58  	resultLen := len(hrp) + 1 + len(data) + 6
    59  	var result = make([]byte, resultLen)
    60  	copy(result, hrp)
    61  	result[len(hrp)] = '1'
    62  	copy(result[len(hrp)+1:], data)
    63  
    64  	bech32ChecksumTo(hrp, data, result[len(hrp)+1+len(data):])
    65  
    66  	err := toChars(result[len(hrp)+1:])
    67  	if err != nil {
    68  		return "", fmt.Errorf("unable to convert data bytes to chars: "+
    69  			"%v", err)
    70  	}
    71  	return amino.BytesToStr(result), nil
    72  }
    73  
    74  func convertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
    75  	var regrouped = make([]byte, 0, len(data)*int(fromBits)/int(toBits)+1)
    76  	return convertBitsTo(data, fromBits, toBits, pad, regrouped)
    77  }
    78  
    79  func convertBitsTo(data []byte, fromBits, toBits uint8, pad bool, target []byte) ([]byte, error) {
    80  	if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
    81  		return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
    82  	}
    83  
    84  	// The final bytes, each byte encoding toBits bits.
    85  	var regrouped []byte
    86  	if target != nil {
    87  		regrouped = target[0:]
    88  	} else {
    89  		regrouped = make([]byte, 0, len(data)*int(fromBits)/int(toBits)+1)
    90  	}
    91  
    92  	// Keep track of the next byte we create and how many bits we have
    93  	// added to it out of the toBits goal.
    94  	nextByte := byte(0)
    95  	filledBits := uint8(0)
    96  
    97  	for _, b := range data {
    98  
    99  		// Discard unused bits.
   100  		b = b << (8 - fromBits)
   101  
   102  		// How many bits remaining to extract from the input data.
   103  		remFromBits := fromBits
   104  		for remFromBits > 0 {
   105  			// How many bits remaining to be added to the next byte.
   106  			remToBits := toBits - filledBits
   107  
   108  			// The number of bytes to next extract is the minimum of
   109  			// remFromBits and remToBits.
   110  			toExtract := remFromBits
   111  			if remToBits < toExtract {
   112  				toExtract = remToBits
   113  			}
   114  
   115  			// Add the next bits to nextByte, shifting the already
   116  			// added bits to the left.
   117  			nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
   118  
   119  			// Discard the bits we just extracted and get ready for
   120  			// next iteration.
   121  			b = b << toExtract
   122  			remFromBits -= toExtract
   123  			filledBits += toExtract
   124  
   125  			// If the nextByte is completely filled, we add it to
   126  			// our regrouped bytes and start on the next byte.
   127  			if filledBits == toBits {
   128  				regrouped = append(regrouped, nextByte)
   129  				filledBits = 0
   130  				nextByte = 0
   131  			}
   132  		}
   133  	}
   134  
   135  	// We pad any unfinished group if specified.
   136  	if pad && filledBits > 0 {
   137  		nextByte = nextByte << (toBits - filledBits)
   138  		regrouped = append(regrouped, nextByte)
   139  		filledBits = 0
   140  		nextByte = 0
   141  	}
   142  
   143  	// Any incomplete group must be <= 4 bits, and all zeroes.
   144  	if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
   145  		return nil, fmt.Errorf("invalid incomplete group")
   146  	}
   147  
   148  	return regrouped, nil
   149  }
   150  
   151  func bech32Polymod(values []int) int {
   152  	chk := 1
   153  	for _, v := range values {
   154  		b := chk >> 25
   155  		chk = (chk&0x1ffffff)<<5 ^ v
   156  		for i := 0; i < 5; i++ {
   157  			if (b>>uint(i))&1 == 1 {
   158  				chk ^= gen[i]
   159  			}
   160  		}
   161  	}
   162  	return chk
   163  }
   164  
   165  func bech32PolymodInternal(chk int, v int) int {
   166  	b := chk >> 25
   167  	chk = (chk&0x1ffffff)<<5 ^ v
   168  
   169  	if (b>>uint(0))&1 == 1 {
   170  		chk ^= gen0
   171  	}
   172  	if (b>>uint(1))&1 == 1 {
   173  		chk ^= gen1
   174  	}
   175  	if (b>>uint(2))&1 == 1 {
   176  		chk ^= gen2
   177  	}
   178  	if (b>>uint(3))&1 == 1 {
   179  		chk ^= gen3
   180  	}
   181  	if (b>>uint(4))&1 == 1 {
   182  		chk ^= gen4
   183  	}
   184  
   185  	return chk
   186  }
   187  
   188  // For more details on HRP expansion, please refer to BIP 173.
   189  func bech32HrpExpand(hrp string) []int {
   190  	v := make([]int, 0, len(hrp)*2+1)
   191  	for i := 0; i < len(hrp); i++ {
   192  		v = append(v, int(hrp[i]>>5))
   193  	}
   194  	v = append(v, 0)
   195  	for i := 0; i < len(hrp); i++ {
   196  		v = append(v, int(hrp[i]&31))
   197  	}
   198  	return v
   199  }
   200  
   201  func bech32ChecksumTo(hrp string, data []byte, result []byte) {
   202  	chk := 1
   203  
   204  	// hrpExpand
   205  	for i := 0; i < len(hrp); i++ {
   206  		chk = bech32PolymodInternal(chk, int(hrp[i]>>5))
   207  	}
   208  	chk = bech32PolymodInternal(chk, 0)
   209  	for i := 0; i < len(hrp); i++ {
   210  		chk = bech32PolymodInternal(chk, int(hrp[i]&31))
   211  	}
   212  
   213  	// Convert the bytes to list of integers, as this is needed for the
   214  	// checksum calculation.
   215  	for i := 0; i < len(data); i++ {
   216  		chk = bech32PolymodInternal(chk, int(data[i]))
   217  	}
   218  
   219  	for i := 0; i < 6; i++ {
   220  		chk = bech32PolymodInternal(chk, 0)
   221  	}
   222  
   223  	polymod := chk ^ 1
   224  	if len(result) != 6 {
   225  		panic("need more space")
   226  	}
   227  	for i := 0; i < 6; i++ {
   228  		result[i] = byte((polymod >> uint(5*(5-i))) & 31)
   229  	}
   230  }
   231  
   232  // toChars converts the byte slice 'data' to a string where each byte in 'data'
   233  // encodes the index of a character in 'charset'.
   234  func toChars(data []byte) error {
   235  	for i := 0; i < len(data); i++ {
   236  		if int(data[i]) >= len(charset) {
   237  			return fmt.Errorf("invalid data byte: %v", data[i])
   238  		}
   239  		data[i] = charset[data[i]]
   240  	}
   241  	return nil
   242  }