Conversation
| try: | ||
| if len(data) == 65 and data[:1] != b"\x04": | ||
| raise ecc.InvalidECPointException() # reject hybrid keys, as Core does | ||
| ecc.ECPubkey(data) # 33-byte compressed or 65-byte uncompressed point | ||
| except ecc.InvalidECPointException: | ||
| if is_taproot and len(data) == 32: | ||
| try: | ||
| ecc.ECPubkey(b"\x02" + data) # even-y x-only point per BIP340 | ||
| return | ||
| except ecc.InvalidECPointException: | ||
| pass | ||
| raise ValueError(f"invalid public key in descriptor: {self.pubkey!r}") |
There was a problem hiding this comment.
untested but this looks needlessly verbose.
| try: | |
| if len(data) == 65 and data[:1] != b"\x04": | |
| raise ecc.InvalidECPointException() # reject hybrid keys, as Core does | |
| ecc.ECPubkey(data) # 33-byte compressed or 65-byte uncompressed point | |
| except ecc.InvalidECPointException: | |
| if is_taproot and len(data) == 32: | |
| try: | |
| ecc.ECPubkey(b"\x02" + data) # even-y x-only point per BIP340 | |
| return | |
| except ecc.InvalidECPointException: | |
| pass | |
| raise ValueError(f"invalid public key in descriptor: {self.pubkey!r}") | |
| if len(data) in (33, 65) and ecc.ECPubkey.is_pubkey_bytes(data): | |
| pass | |
| elif len(data) == 32 and is_taproot and ecc.ECPubkey.is_pubkey_bytes(b"\x02" + data): | |
| pass | |
| else: | |
| raise ValueError(f"invalid public key in descriptor: {self.pubkey!r}") |
There was a problem hiding this comment.
Applied, with one addition to the suggestion: a prefix check (data[0] in (2, 3, 4)) so hybrid keys (0x06/0x07) are still rejected. is_pubkey_bytes accepts them, since libsecp256k1 parses hybrid encodings, while Core's descriptor parser rejects them; without the check a hybrid key would also get past has_uncompressed_pubkey() in wpkh()/wsh(). The existing test covers that case.
|
note: checking if a bytevector is a valid public key is relatively expensive, so would be good to know if this is used in any hot code path |
|
Not a hot path: |
fed1751 to
5141e87
Compare
A raw-hex pubkey in a descriptor was not checked against the curve, so an expression like pkh(<hex that is not a point>) parsed successfully. Validate the key where it is parsed: inside tr() accept a 32-byte x-only point or a compressed point, elsewhere a compressed or uncompressed point, and reject anything off-curve, of the wrong length, or of a form its context does not allow. Keys derived from an extended key are valid by construction and are left alone.
5141e87 to
02148e1
Compare
|
These three PRs are waiting on workflow approval: #10948, #10951 and #10952. All three were rebased onto master 39cab57 yesterday with no content change, so the Locally on 3.14.6, Could a maintainer approve the workflow runs so CI can confirm this? |
A raw-hex public key in a descriptor is never checked to be a valid point, so
pkh(<64 hex chars that are not a curve point>)parses. Bitcoin Core rejects an invalid key at parse time.This validates a raw-hex key against the acceptance set Core uses in
ParsePubkeyInner, context-aware:tr(): a 32-byte x-only key or a 33-byte compressed key;wpkh()/wsh(), per BIP141);0x06/0x07) and off-curve or wrong-length keys are rejected.Validation uses
electrum_ecc. Thetr()internal key is now parsed in P2TR context so a 32-byte x-only key is recognised there. Extended-key (xpub) expressions are unaffected. Tests cover the acceptance and rejection cases.The equivalent change for Bitcoin Core's HWI, which shares this code, is bitcoin-core/HWI#859.