bech32_test.go raw

   1  package bech32
   2  
   3  import (
   4  	"encoding/hex"
   5  	"strings"
   6  	"testing"
   7  )
   8  
   9  // TestBIP173Vectors: the valid addresses from the BIP173 test vectors.
  10  //
  11  // The first is the canonical example: a 20-byte program of 0x751e... encoded for the "bc"
  12  // prefix. If the checksum or the 5-bit regrouping were wrong, this would not match.
  13  func TestBIP173Vectors(t *testing.T) {
  14  	valid := map[string]string{
  15  		"751e76e8199196d454941c45d1b3a323f1433bd6":                         "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
  16  		"1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262": "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
  17  	}
  18  
  19  	for program, want := range valid {
  20  		raw, err := hex.DecodeString(program)
  21  
  22  		if err != nil {
  23  			t.Fatal(err)
  24  		}
  25  
  26  		got, err := EncodeSegwit("bc", 0, raw)
  27  
  28  		if err != nil {
  29  			t.Fatalf("%s: %v", program, err)
  30  		}
  31  
  32  		if got != want {
  33  			t.Fatalf("program %s encoded to %q, want %q", program, got, want)
  34  		}
  35  
  36  		hrp, version, decoded, err := DecodeSegwit(want)
  37  
  38  		if err != nil {
  39  			t.Fatalf("%s: %v", want, err)
  40  		}
  41  
  42  		if hrp != "bc" || version != 0 || hex.EncodeToString(decoded) != program {
  43  			t.Fatalf("%s decoded to %q/%d/%s", want, hrp, version, hex.EncodeToString(decoded))
  44  		}
  45  	}
  46  }
  47  
  48  // TestRegtestPrefix: the chain profile's prefix is part of the address, so the same
  49  // program under bcrt is a different string.
  50  func TestRegtestPrefix(t *testing.T) {
  51  	raw, err := hex.DecodeString("751e76e8199196d454941c45d1b3a323f1433bd6")
  52  
  53  	if err != nil {
  54  		t.Fatal(err)
  55  	}
  56  
  57  	mainnet, err := EncodeSegwit("bc", 0, raw)
  58  
  59  	if err != nil {
  60  		t.Fatal(err)
  61  	}
  62  
  63  	regtest, err := EncodeSegwit("bcrt", 0, raw)
  64  
  65  	if err != nil {
  66  		t.Fatal(err)
  67  	}
  68  
  69  	if mainnet == regtest {
  70  		t.Fatal("the same program encoded identically under two prefixes")
  71  	}
  72  
  73  	if !strings.HasPrefix(regtest, "bcrt1") {
  74  		t.Fatalf("the regtest address is %q", regtest)
  75  	}
  76  
  77  	// The program survives both, which is what makes the prefix a profile fact and not a
  78  	// second encoding.
  79  	for _, address := range []string{mainnet, regtest} {
  80  		hrp, _, decoded, err := DecodeSegwit(address)
  81  
  82  		if err != nil {
  83  			t.Fatalf("%s: %v", address, err)
  84  		}
  85  
  86  		if len(hrp) == 0 || hex.EncodeToString(decoded) != hex.EncodeToString(raw) {
  87  			t.Fatalf("%s decoded to %q/%s", address, hrp, hex.EncodeToString(decoded))
  88  		}
  89  	}
  90  }
  91  
  92  // TestRefusals: the shapes that must not be accepted, each for its own reason.
  93  func TestRefusals(t *testing.T) {
  94  	raw, err := hex.DecodeString("751e76e8199196d454941c45d1b3a323f1433bd6")
  95  
  96  	if err != nil {
  97  		t.Fatal(err)
  98  	}
  99  
 100  	good, err := EncodeSegwit("bc", 0, raw)
 101  
 102  	if err != nil {
 103  		t.Fatal(err)
 104  	}
 105  
 106  	// One character changed is a different checksum.
 107  	broken := []byte(good)
 108  	broken[len(broken)-1] ^= 1
 109  
 110  	cases := map[string]string{
 111  		"a changed character": string(broken),
 112  		"mixed case":          strings.ToUpper(good[:4]) + good[4:],
 113  		"no separator":        "bcqw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
 114  		"too short":           "bc1qqqqq",
 115  		"a bad character":     good[:len(good)-1] + "b",
 116  	}
 117  
 118  	for name, address := range cases {
 119  		if _, _, _, err := DecodeSegwit(address); err == nil {
 120  			t.Errorf("%s was accepted: %q", name, address)
 121  		}
 122  	}
 123  
 124  	if _, err := EncodeSegwit("bc", 1, raw); err == nil {
 125  		t.Fatal("witness version 1 was encoded with the version 0 checksum")
 126  	}
 127  
 128  	if _, err := EncodeSegwit("bc", 0, raw[:19]); err == nil {
 129  		t.Fatal("a 19-byte program was encoded")
 130  	}
 131  
 132  	if _, err := EncodeSegwit("", 0, raw); err == nil {
 133  		t.Fatal("an empty prefix was encoded")
 134  	}
 135  
 136  	if _, err := EncodeSegwit("BC", 0, raw); err == nil {
 137  		t.Fatal("an uppercase prefix was encoded")
 138  	}
 139  }
 140  
 141  // TestRoundTrip: every program length a wallet uses survives encode and decode.
 142  func TestRoundTrip(t *testing.T) {
 143  	for _, size := range []int{20, 32} {
 144  		program := make([]byte, size)
 145  
 146  		for i := range program {
 147  			program[i] = byte(i*7 + 1)
 148  		}
 149  
 150  		for _, hrp := range []string{"bc", "tb", "bcrt"} {
 151  			address, err := EncodeSegwit(hrp, 0, program)
 152  
 153  			if err != nil {
 154  				t.Fatalf("%s/%d: %v", hrp, size, err)
 155  			}
 156  
 157  			gotHRP, _, decoded, err := DecodeSegwit(address)
 158  
 159  			if err != nil {
 160  				t.Fatalf("%s: %v", address, err)
 161  			}
 162  
 163  			if gotHRP != hrp || hex.EncodeToString(decoded) != hex.EncodeToString(program) {
 164  				t.Fatalf("%s decoded to %q/%s", address, gotHRP,
 165  					hex.EncodeToString(decoded))
 166  			}
 167  		}
 168  	}
 169  }
 170