bitcoinjs / bech32

Bech32 encoding / decoding
MIT License
106 stars 46 forks source link

This library seems to fail some bip350 test vectors #50

Closed supertestnet closed 10 months ago

supertestnet commented 10 months ago

According to bip350:

The following list gives valid segwit addresses and the scriptPubKey that they translate to in hex. ... tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c: 5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433 bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0: 512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798

I tried these test vectors in the bech32 library and this is what I got:

var words = bech32.bech32m.decode( "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c" ).words; console.log( bytesToHex( bech32.bech32m.fromWords( words ) ) ); //08000006252e56a3110d950c3c82f29331b15cceaf48e3671268b2ed5c9f432198 var words = bech32.bech32m.decode( "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0" ).words; console.log( bytesToHex( bech32.bech32m.fromWords( words ) ) ); //0bcdf333f7cee5dd62ad0314ae7438583814dfe6d96e7146cacf940ad8b7c0bcc0

I used version 2.0.0 available for the browser here: <script src="https://bundle.run/bech32@2.0.0"></script>

junderw commented 10 months ago

You misunderstand what the test vectors are showing.

They are showing scriptPubkeys, not direct conversions of the words to bytes.

You have to take the segwit version from the first word and convert the 2nd word onward, then push that using an OP_PUSHDATA to make a valid scriptPubkey.

If the library were completely broken in this way, then wallets using taproot addresses with no issue wouldn't exist.

supertestnet commented 10 months ago

Thank you! That worked. :) I decoded the two test vectors from the second word onward and got exactly the results I expected:

var words = bech32.bech32m.decode( "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c" ).words; var segwit_version = words[ 0 ]; words.splice( 0, 1 ); var pubkey = bytesToHex( bech32.bech32m.fromWords( words ) ); console.log( "pubkey:", pubkey ); //000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433 var words = bech32.bech32m.decode( "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0" ).words; var segwit_version = words[ 0 ]; words.splice( 0, 1 ); var pubkey = bytesToHex( bech32.bech32m.fromWords( words ) ); console.log( "pubkey:", pubkey ); //79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798

All I have to do is prefix 5120 to them to represent the segwit version number (OP_PUSHNUM_1) and the pushdata opcode (OP_PUSHBYTES_32) and the result is identical to the test vector. Thank you for your help!