github.com/turingchain2020/turingchain@v1.1.21/wallet/bipwallet/basen/basen.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Copyright (c) 2014 Casey Marshall. See LICENSE file for details.
     6  
     7  // Package basen basen (base-N) is a simple Go encoding package for representing bytes as big integers in arbitrary base-N encoding.
     8  package basen
     9  
    10  import (
    11  	"crypto/rand"
    12  	"fmt"
    13  	"math/big"
    14  	"unicode/utf8"
    15  )
    16  
    17  var zero = big.NewInt(int64(0))
    18  
    19  // Encoding represents a given base-N encoding.
    20  type Encoding struct {
    21  	alphabet string
    22  	index    map[byte]*big.Int
    23  	base     *big.Int
    24  }
    25  
    26  const base62Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    27  
    28  // Base62 represents bytes as a base-62 number [0-9A-Za-z].
    29  var Base62 = NewEncoding(base62Alphabet)
    30  
    31  const base58Alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
    32  
    33  // Base58 represents bytes as a base-58 number [1-9A-GHJ-LM-Za-z].
    34  var Base58 = NewEncoding(base58Alphabet)
    35  
    36  // NewEncoding creates a new base-N representation from the given alphabet.
    37  // Panics if the alphabet is not unique. Only ASCII characters are supported.
    38  func NewEncoding(alphabet string) *Encoding {
    39  	return &Encoding{
    40  		alphabet: alphabet,
    41  		index:    newAlphabetMap(alphabet),
    42  		base:     big.NewInt(int64(len(alphabet))),
    43  	}
    44  }
    45  
    46  func newAlphabetMap(s string) map[byte]*big.Int {
    47  	if utf8.RuneCountInString(s) != len(s) {
    48  		panic("multi-byte characters not supported")
    49  	}
    50  	result := make(map[byte]*big.Int)
    51  	for i := range s {
    52  		result[s[i]] = big.NewInt(int64(i))
    53  	}
    54  	if len(result) != len(s) {
    55  		panic("alphabet contains non-unique characters")
    56  	}
    57  	return result
    58  }
    59  
    60  // Random returns the base-encoded representation of n random bytes.
    61  func (enc *Encoding) Random(n int) (string, error) {
    62  	buf := make([]byte, n)
    63  	_, err := rand.Reader.Read(buf)
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  	return enc.EncodeToString(buf), nil
    68  }
    69  
    70  // MustRandom returns the base-encoded representation of n random bytes,
    71  // panicking in the unlikely event of a read error from the random source.
    72  func (enc *Encoding) MustRandom(n int) string {
    73  	s, err := enc.Random(n)
    74  	if err != nil {
    75  		panic(err)
    76  	}
    77  	return s
    78  }
    79  
    80  // Base returns the number base of the encoding.
    81  func (enc *Encoding) Base() int {
    82  	return len(enc.alphabet)
    83  }
    84  
    85  // EncodeToString returns the base-encoded string representation
    86  // of the given bytes.
    87  func (enc *Encoding) EncodeToString(b []byte) string {
    88  	n := new(big.Int)
    89  	r := new(big.Int)
    90  	n.SetBytes(b)
    91  	var result []byte
    92  	for n.Cmp(zero) > 0 {
    93  		n, r = n.DivMod(n, enc.base, r)
    94  		result = append([]byte{enc.alphabet[r.Int64()]}, result...)
    95  	}
    96  	return string(result)
    97  }
    98  
    99  // DecodeString returns the bytes for the given base-encoded string.
   100  func (enc *Encoding) DecodeString(s string) ([]byte, error) {
   101  	result := new(big.Int)
   102  	for i := range s {
   103  		n, ok := enc.index[s[i]]
   104  		if !ok {
   105  			return nil, fmt.Errorf("invalid character %q at index %d", s[i], i)
   106  		}
   107  		result = result.Add(result.Mul(result, enc.base), n)
   108  	}
   109  	return result.Bytes(), nil
   110  }
   111  
   112  // DecodeStringN returns N bytes for the given base-encoded string.
   113  // Use this method to ensure the value is left-padded with zeroes.
   114  func (enc *Encoding) DecodeStringN(s string, n int) ([]byte, error) {
   115  	value, err := enc.DecodeString(s)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	if len(value) > n {
   120  		return nil, fmt.Errorf("value is too large")
   121  	}
   122  	pad := make([]byte, n-len(value))
   123  	return append(pad, value...), nil
   124  }