Release notes¶
Notable changes are documented here. CHANGELOG.md is the record behind them: this file says what a user has to act on, that one says what changed.
Versions are calendar versions, YYYY.M.D: the
number says when a release was cut, and promises nothing about
compatibility, so a breaking change is announced in this file — read it
before upgrading, rather than a digit.
v2026.11 (work in progress, not released yet)¶
v2026.10.2 fixed GHSA-r5pw-9wrg-m3mj: on a curve of cofactor above 1 (secp112r2, secp128r2),
ssarefuses a public key outside the subgroup generated by G, and batch verification refuses anrwhose point is outside it. Before, a forged signature verified under such a key, which nobody holds. secp256k1 is unchanged.Act on it if you verified
ssasignatures on one of these curves with an earlier release: verify them again. One under a key outside the subgroup now fails.The attestation bundle is attached as
v<version>.intoto.jsonlfrom v2026.10.2 on, where earlier releases attachv<version>.attestation.jsonl. A script that downloads it by name, or passes it togh attestation verify --bundle, uses the new name.
v2026.10.2¶
mult_pub_key,ecies.derive_keys,dsa.assert_as_valid,dsa.assert_as_valid_anddsa.sign_’spub_keyrefuse a hybrid public key (prefix0x06or0x07) asnot a public key(closes #75). Withbtclib-secp256k1installed they accepted it, and without it they refused it.Act on it if you pass such a key: convert it first, with
point_from_octets(key, hybrid=True), and pass the point.pedersen.verifyraisesBTClibEccValueErrorfor a generator off the curve, at infinity or, on a cofactor curve, outside the subgroup generated by G (closes #76). Before, it answered False for an off-curve generator and True for an opening under INF, which opens to every value. On a cofactor curvesecond_generatorreturns a different H where its old H was outside the subgroup, as at sha256 on secp112r2 and secp128r2.Act on it if you pass a generator of your own: pass one from
second_generatororgenerator_from_seed, or catchBTClibEccValueError. Commitments made under that old H no longer verify.Verifying a release’s attestation names a new signer and the tag.
gh attestation verifytakes--signer-workflow btclib-org/.github/.github/workflows/reusable-build.yml@refs/heads/mainand--source-ref refs/tags/v<version>; SECURITY.md has the command. Earlier releases keepreusable-attest.ymland take the same--source-ref.ssasigns with a different nonce on a curve whose order is longer than the hash’s output, such as sha256 on secp384r1 or secp521r1 (GHSA-m38m-987v-j55h). Every other pair, secp256k1 with sha256 included, signs as before, and old signatures still verify.Act on it if you signed with
ssaon such a pair: rotate the key, and re-pin any deterministic signature you stored.musig2.partial_sig_verifyraisesBTClibEccValueErrorfor a signer index outside0..len(pub_keys)-1(closes #78). A negative index used to select a signer from the end.Act on it if you pass one: pass the index counted from the front.
FROST takes only an int where it takes an integer (closes #77, closes #79).
n,t, an id and the signer index raiseBTClibEccTypeErrorfor anything else, a bool, a float or a str included, whereint()convertedn,tand the ids.partial_sig_verify_raises for an id not inids.Act on it if you pass such a value: pass an int.
v2026.9.30¶
No breaking changes. An installed btclib-secp256k1 older than the floor
the secp256k1 extra names still fails the import, and its ImportError
now names the installed version and that floor: upgrade btclib-secp256k1,
or install btclib-ecc[secp256k1].
v2026.9.28¶
Breaking changes¶
_utils.int_from_integerandhex_stringrefuse a0xstring whose digits are not ASCII hex, asinvalid hex integer: what follows 0x is not ASCII hex digits(closes #21). Before,int(i, 16)alone read0x1_0, and0xfollowed by fullwidth or Arabic-Indic digits, as 16, and quoted the string in its refusal. Only ASCII whitespace is stripped now: a0xstring padded with U+00A0, U+3000 or another characterstr.isspacecounts, ahead of the prefix or after its digits, is refused too — by the message above, or bybytes.fromhex’s own where the padding leaves neither a0xspelling nor valid hex. EveryIntegerparameter reads through here,curve.mult’s private keymamong them.Act on it if you pass such a string, or match this refusal’s text: pass ASCII hex digits, and match
invalid hex integeralone rather than the string it used to quote.
v2026.9.26¶
The first release of btclib-ecc: there is no earlier version of it
to upgrade from.