Repository navigation
v1.15.0 release
This release fixes two SLIP-39 bugs, one of which affects compatibility with other implementations, and makes BIP-322 message signing reject a key the address does not commit to. Both SLIP-39 fixes change what this gem writes, so please read the Upgrade notes if you hold shares generated by an earlier version.
Bug Fixes
SLIP-39
- Fix
Bitcoin::SLIP39::SSSencoding the identifier of the PBKDF2 salt with the minimum number of bytes, while SLIP-39 requires two bytes. An identifier below 256 produced a one byte salt, so the shares written for about 1 in 128 master secrets could not be recovered by the reference implementation, and shares written by another implementation with such an identifier recovered to a wrong master secret here. The salt now always carries two bytes, which is verified against vectors generated with the reference implementation (python shamir-mnemonic 0.3.0).recover_secrettakes alegacy_salt:option to recover the shares this gem used to write. - Fix
Bitcoin::SLIP39::Sharedropping the leading zero bytes of the share value.#from_wordsstripped them when it read the value back, and#to_wordssized the value by its bit length, so a value starting with a zero byte was written with fewer words than a value of the same length and did not survive a round trip.#to_wordsnow writes the value at its byte length, and rejects a value whose byte length is odd since the padding#from_wordsderives from the word count only matches an even one.
Message signing
- Fix
Bitcoin::MessageSign.sign_messageproducing a signature for a BIP-322 address the key does not correspond to. A P2WPKH address of another key, or a P2TR address which is not the tweaked output key of the given key, used to return a signature which verifies against no one, and BIP-322 carries nothing that would report it. It now raisesArgumentErrorfor such a key. A P2WSH address is also rejected, since the witness script it commits to cannot be derived from a key alone. - Add regression specs confirming that
Bitcoin::MessageSign.verify_messagerejects a signature made by an unrelated key for a P2PKH, P2WPKH, P2SH-P2WPKH, P2WSH and P2TR address, including a signature valid for the sighash of the address itself where only the binding between the key and the address rejects it.
Improvements
- Add an
as_internal:keyword argument toBitcoin::Key#to_p2tr. The default keeps returning the address whose output key is the x-only public key of this key as it is, which is what therawtr()descriptor does. Withas_internal: truethis key is the internal key and the output key is tweaked with an empty merkle root, which is what thetr()descriptor and BIP-86 define for a single key address.
Upgrade notes
- SLIP-39 shares written by bitcoinrb 1.14.0 and earlier whose identifier is below 256 can no longer be recovered with the default salt. Pass
legacy_salt: truetoBitcoin::SLIP39::SSS.recover_secretfor those, and consider regenerating them so other implementations can read them. Shares with an identifier of 256 or above are unaffected, since both encodings produce the same two bytes. Bitcoin::SLIP39::Share#to_wordsraisesArgumentErrorfor a share value whose byte length is odd, which used to be written as a different value rather than rejected.Bitcoin::MessageSign.sign_messageraisesArgumentErrorwhere it used to return an unverifiable signature, when theaddress:given does not correspond tokey, and for a P2WSH address. Note that the P2TR address it expects is the tweaked one, whichBitcoin::Key#to_p2tr(as_internal: true)returns.
Full Changelog: v1.14.0...v1.15.0