taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit bf5979fb35fc50a0e94764cc0b73f1e440dea4b9
parent 7739f02be1cfe8bb15bcc4df8b39ac0776b00f00
Author: Florian Dold <dold@taler.net>
Date:   Tue, 21 Jul 2026 10:54:36 +0200

util: verify the bech32 checksum and the segwit version consistency

The checksum was only verified when the caller passed the expected
encoding, and the version guards used === where the reference uses !==, so
they rejected exactly the combinations they are meant to accept.

Diffstat:
Mpackages/taler-util/src/bech32.ts | 20++++++++++++++++++--
Mpackages/taler-util/src/segwit_addr.ts | 6++++--
2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/packages/taler-util/src/bech32.ts b/packages/taler-util/src/bech32.ts @@ -129,6 +129,14 @@ export namespace BitcoinBech32 { WRONG_CHECKSUM, } + /** + * Decode a bech32 string and verify its checksum. + * + * When @param enc is given, the checksum must match that encoding. When it + * is omitted, either encoding is accepted and the one that verified is + * reported back, so that callers such as the segwit address parser can check + * it against the witness version. + */ export function decode( bechString: string, enc?: Encodings, @@ -136,6 +144,7 @@ export namespace BitcoinBech32 { { hrp: string; data: number[]; + enc: Encodings; }, BitcoinParseError > { @@ -176,9 +185,16 @@ export namespace BitcoinBech32 { } data.push(d); } - if (enc && !verifyChecksum(hrp, data, enc)) { + const candidates = + enc !== undefined ? [enc] : [Encodings.BECH32, Encodings.BECH32M]; + const actualEnc = candidates.find((c) => verifyChecksum(hrp, data, c)); + if (actualEnc === undefined) { return Result.error(BitcoinParseError.WRONG_CHECKSUM); } - return Result.of({ hrp, data: data.slice(0, data.length - 6) }); + return Result.of({ + hrp, + data: data.slice(0, data.length - 6), + enc: actualEnc, + }); } } diff --git a/packages/taler-util/src/segwit_addr.ts b/packages/taler-util/src/segwit_addr.ts @@ -90,10 +90,12 @@ export namespace BitcoinSewgit { if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { return Result.error(BitcoinSewgitParseError.DECODING_PROBLEM); } - if (dec.data[0] === 0 && enc === BitcoinBech32.Encodings.BECH32) { + // Version 0 programs are checksummed with bech32, later versions with + // bech32m (BIP-350). + if (dec.data[0] === 0 && dec.enc !== BitcoinBech32.Encodings.BECH32) { return Result.error(BitcoinSewgitParseError.DECODING_PROBLEM); } - if (dec.data[0] !== 0 && enc === BitcoinBech32.Encodings.BECH32M) { + if (dec.data[0] !== 0 && dec.enc !== BitcoinBech32.Encodings.BECH32M) { return Result.error(BitcoinSewgitParseError.DECODING_PROBLEM); } return Result.of({ version: dec.data[0], program: res });