There are a lot of cases in rust-bitcoin where we need a `Secp256k1`
which doesn't need any signing or verification capabilities, only
checking the validity of various objects. We can get away with a bare
context (i.e. no precomputation) which can be cheaply created on demand,
avoiding the need to pass around references to Secp256k1 objects everywhere.
API break because the following functions can now fail (given an insufficiently
capable context) and therefore now return a Result:
Secp256k1::generate_keypair
Secp256k1::sign
Secp256k1::sign_compact
The Rng was only used for key generation, and for BIP32 users not even then;
thus hauling around a Rng is a waste of space in addition to causing a
massive amount of syntactic noise. For example rust-bitcoin almost always
uses `()` as the Rng; having `Secp256k1` default to a `Secp256k1<Fortuna>`
then means even more syntactic noise, rather than less.
Now key generation functions take a Rng as a parameter, and the rest can
forget about having a Rng. This also means that the Secp256k1 context
never needs a mutable reference and can be easily put into an Arc if so
desired.
This comes with a couple bugfixes and the following API changes:
- Secp256k1::sign and ::sign_compact no longer return Result;
it is impossible to trigger their failure modes with safe
code since the `Message` and `SecretKey` types validate when
they are created.
- constants::MAX_COMPACT_SIGNATURE_SIZE loses the MAX_; signatures
are always constant size
- the Debug output for everything is now hex-encoded rather than
being a list of base-10 ints. It's just easier to read this way.
kcov v26 now reports 100% test coverage; however, this does not
guarantee that test coverage is actually complete. Patches are
always welcome for improved unit tests.
Now that you can't create secret keys by directly passing a Rng to
`SecretKey::new`, we need a way to allow user-chosed randomness.
We add it to the `Secp256k1`.
Rather than have global initialization functions, which required
expensive synchronization on the part of the Rust library,
libsecp256k1 now carries its context in thread-local data which
must be passed to every function.
What this means for the rust-secp256k1 API is:
- Most functions on `PublicKey` and `SecretKey` now require a
`Secp256k1` to be given to them.
- `Secp256k1::verify` and `::verify_raw` now take a `&self`
- `SecretKey::new` now takes a `Secp256k1` rather than a Rng; a
future commit will allow specifying the Rng in the `Secp256k1`
so that functionality is not lost.
- The FFI functions have all changed to take a context argument
- `secp256k1::init()` is gone, as is the dependency on std::sync
- There is a `ffi::Context` type which must be handled carefully
by anyone using it directly (hopefully nobody :))
Y'know, I can't for the life of me think what this was supposed to
be used for. Given that the library did not compile for several
months until last week, I assume there are no users, let alone
users of such a weird feature.
rust-secp256k1 was based off of https://github.com/sipa/secp256k1,
which has been inactive nearly as long as this repository (prior to
a couple days ago anyway). The correct repository is
https://github.com/bitcoin/secp256k1
This is a major breaking change to the library for one reason: there
are no longer any Nonce types in the safe interface. The signing functions
do not take a nonce; this is generated internally.
This also means that I was able to drop all my RFC6979 code, since
libsecp256k1 has its own implementation.
If you need to generate your own nonces, you need to create an unsafe
function of type `ffi::NonceFn`, then pass it to the appropriate
functions in the `ffi` module. There is no safe interface for doing
this, deliberately: there is basically no need to directly fiddle
with nonces ever.
This reverts commit 9889090784.
This is not ready for primetime -- the move prevention also prevents
reborrowing, which makes secret keys nearly unusable.
Using the `secretdata` library, we can store SecretKeys in such a way
that they cannot be moved or copied, and their memory is zeroed out on
drop. This gives us some assurance that in the case of memory unsafety,
there is not secret key data lying around anywhere that we don't expect.
Unfortunately, it means that we cannot construct secret keys and then
return them, which forces the interface to change a fair bit. I removed
the `generate_keypair` function from Secp256k1, then `generate_nonce`
for symmetry, then dropped the `Secp256k1` struct entirely because it
turned out that none of the remaining functions used the `self` param.
So here we are. I bumped the version number. Sorry about this.
When creating a Secp256k1, we attach a Fortuna CSRNG seeded from the
OS RNG, rather than using the OS RNG all the time. This moves the
potential RNG failure to the creation of the object, rather than at
every single place that keys are generated. It also reduces trust
in the operating system RNG.
This does mean that Secp256k1::new() now returns an IoResult while
the generate_* methods no longer return Results, so this is a breaking
change.
Also add a benchmark for key generation. On my system I get:
test tests::generate_compressed ... bench: 492990 ns/iter (+/- 27981)
test tests::generate_uncompressed ... bench: 495148 ns/iter (+/- 29829)
Contrast the numbers with OsRng:
test tests::generate_compressed ... bench: 66691 ns/iter (+/- 3640)
test tests::generate_uncompressed ... bench: 67148 ns/iter (+/- 3806)
Not too shabby :)
[breaking-change]
It turns out I need to run `init` before pretty-much every FFI function,
which means that most everything would have to be marked unsafe if I'm
expecting the Rust user to do this. This is unacceptable -- users who
need to sacrifice safety for speed can just use the `ffi::` functions
instead.
Also, I noticed that I was locking up in `PublicKey::from_secret_key`.
Fix to return an error value -- unfortunately a breaking change since
it changes the function signature.
[breaking-change]
Verifying signatures does not require any randomness, but requires the user
to create a `Secp256k1` object nonetheless (this is just a way to guarantee
that `init` is called --- an alternate API would be to have an independent
unsafe `verify` function). If a Rng can't be created, rather than failing
the `Secp256k1` initialization, fail the functions that actually try to use
the Rng.
This way signing and verifying, which require no randomness beyond that input
to them, will work correctly.
To avoid checking for a working Rng on each call to `generate_keypair` and
`generate_nonce` (which is probably trivial next to the cost of actually
generating the randomness, but w/e, user knows best), the user should use
the generation functions in the `key` module, which take an Rng as input.