feat: Add type secpCtx for Wallet#1049
Conversation
There was a problem hiding this comment.
Secp context is only really useful if you need to keep one around and not have to re-create it every time you need it, but in this case we can't actually pass ownership of it to the bindings side and instead do a full copy of it, defeating the purpose.
My take on this is that we should create a new secp context inside the Psbt::sign wrapper instead, and not require it as an argument. Note that this is also what we do with all our other APIs that require a secp context; we just create one on the fly.
Asking Claude to dig into this a bit here is what I get:
The secp parameter in Psbt::sign is a Rust-ergonomics affordance (letting callers amortize context creation across many calls in hot loops), not a semantic input: any Signing-capable context produces identical signatures, and there is nothing about the wallet's context that Psbt::sign needs — it doesn't even have to come from a wallet.
The rationale was that it was easier to keep one context around because they were costly to create. This is largely historical now.
Why it used to matter: in older versions of libsecp256k1, creating a context computed large precomputed multiplication tables (on the order of a megabyte of table generation work) used to accelerate the elliptic-curve operations. Doing that per signature would have dwarfed the cost of the signature itself, so the library was designed around "create one context at startup, pass it everywhere" — and every API downstream (rust-secp256k1, rust-bitcoin, BDK) inherited that shape.
What changed: around libsecp256k1 v0.5.0 (rust-secp256k1 ~0.22, 2022), the precomputed tables were moved into the library binary as static data. A new context is now a small heap allocation plus initialization — cheap enough that creating one per operation is fine for anything that isn't a tight loop signing thousands of times.
Yes this is true and something I also considered. Secp does not need to be passed as a param and can be handled and used under the hood. The only reason I did this is trying to make the sign method as close to the rust API as possible. Because I assumed that there can be a custom secp256k1 instances user might want to pass. This is possible in rust. I can also see there are different context that Secp256k1 can have. i.e just signing or just verifying or all. But I think in our context we sticking to a default which is
True. Only thing is that the way psbt sign has been presented seemed like, now a user has full control of how they want to sign even down to the sepCtx.
I agree as from my tests it spits out the same sepcCtx value every time. Makes me wonder why we have this method in Wallet. I should ask Since we will not pass this as param for psbt.sign, I assume we do not want to expose this on wallet too ? |
Description
Addresses #1048
Notes to the reviewers
This exposes Secp256k1 for the purposes of using this in our psbt sign. Especially if we want the API to be as close to bdk-wallet as possible.
Documentation
bdk_walletbitcoinuniffiChangelog
Checklists
All Submissions:
cargo fmtandcargo clippybefore committingchangelog:*labelNew Features: