btcsuite / btcutil

Provides bitcoin-specific convenience functions and types
479 stars 409 forks source link

bech32: Encode accepts invalid uppercase HRP #152

Closed FiloSottile closed 3 years ago

FiloSottile commented 4 years ago

bech32.Encode will accept an uppercase HRP and generate an invalid bech32 encoding instead of normalizing it or returning an error.

BIP 0173 is clear that mixed case encodings are invalid, and that the lowercase encoding should be used for checksum purposes. This means there are two ways to handle an uppercase HRP in Encode:

  1. treat it as lowercase, and ideally return a lowercase encoding
  2. return an error

Instead, this library will use the uppercase values for the checksum and return a mixed case encoding. Decode will correctly reject the mixed case encoding, and will fail the checksum of the lowercase version.

https://play.golang.org/p/h0ekj8VmiPV

davecgh commented 4 years ago

I'm no longer active on this project, but for reference for the new maintainers, you guys might want to go ahead and back port the updated version from Decred at https://github.com/decred/dcrd/tree/master/bech32. We originally based it on this implementation from the LL folks, but improved it in many ways, which includes handling what this issue raises properly.

The primary improvements made are:

I've slightly modified the code provided by @FiloSottile accordingly to show the improved version works as expected:

https://play.golang.org/p/5wzMOhgiz9Y

package main

import (
    "log"
    "strings"

    "github.com/decred/dcrd/bech32"
)

func main() {
    s, err := bech32.EncodeFromBase256("UPPERCASE", []byte("xxx"))
    if err != nil {
        log.Fatal(err)
    }
    log.Print("encoded: ", s)
    log.Print(bech32.DecodeToBase256(s))
    log.Print(bech32.DecodeToBase256(strings.ToUpper(s)))
}

Output:

... encoded: uppercase10pu8sss7kmp
... uppercase[120 120 120] <nil>
... uppercase[120 120 120] <nil>