Instead of providing a mechanism for users to opt out of randomization
we can just feature gate the call site i.e., opportunistically randomize
the global context on creation if `rand-std` feature is enabled.
Seems there is a bug in cargo, the tests in `key.rs` run successfully
but AFAICT they should fail. Here is an example, running `cargo test
--features=rand` should make this test fail but it doesn't?
```
/// Secret 256-bit key used as `x` in an ECDSA signature.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] {
/// use secp256k1::{rand, Secp256k1, SecretKey};
///
/// let secp = Secp256k1::new();
/// let secret_key = SecretKey::new(&mut rand::thread_rng());
/// # }
/// ```
Anywho, use the correct feature gate: `rand-std`.
Various combinations of features trigger lint warnings for unused code,
all warnings are caused by incorrect feature gating.
Correct feature gating to remove Clippy warnings during testing.
Currently various features fail to build when enabled without default
features. This is because many tests need feature gating.
Feature gating the import statements quickly turns into spaghetti when
trying to cover all combinations of two features correctly, instead just
allow unused imports on `tests` modules where needed.
Add correct feature requirements to the examples so they also can be run
without default features.
Improve the CI script by doing:
- Add `std` to the feature matrix.
- Add `--no-default-features` to test runs in the CI script.
aa828f01a5 Improve documentation in the key module (Tobin Harding)
9e46d6f122 Add examples to types and methods in key module (Tobin Harding)
a7f3d9bcfd Improve key module docs (Tobin Harding)
6d23614467 Improve lib.rs rustdocs (Tobin Harding)
4c4268f1ad Improve docs on method generate_keypair (Tobin Harding)
Pull request description:
This PR is an initial attempt to more thoroughly test our public API.
Add examples to various types/methods/functions in the key module.
I'm not entirely sure when is enough, do we want an example on every single public method, function, and type or is this overkill. In this PR I tried to find a balance by doing ever method/function that took an argument that is a custom type from this lib. I think this should be extended to include return values too though ...
Thanks to @thomaseizinger for the idea!
First 2 patches are docs improvements to `lib.rs`.
ACKs for top commit:
apoelstra:
ACK aa828f01a5
Tree-SHA512: 9383ad263469f98ce7e988d47edc1482a09a0ce82f43d3991bd80aabdf621430f4a3c86be4debf33232dcb1d60d3e81f2c6d930ea7de7aa0e34b037accd7bc98
We recently patched much of the docs in the `key` module, lets attempt
to attain perfection.
Improve docs by doing:
- Use full stops
- Use 100 character column width
- Use plural third person tense
- Use plural for section headings
- Fix any grammar mistakes
- Use code ticks and links as appropriate
Done in an effort to better test our public API.
Add tests in the `Examples` section as is idiomatic in the Rust
ecosystem.
Make other minor improvements to any rusdocs we touch:
- Use full stops
- Use 100 character column width
- Use plural third person tense
- Use plural for section headings
Recently we made a wee mess with the `Parity` opaque type. Let's fix it
up by doing:
- Use an enum with variants `Even` and `Odd`.
- Add explicit conversion methods to/from u8 and i32
- Implement `BitXor`
Note: This patch is an API breaking change that does _not_ follow the
deprecation guidelines. Rust does not allow deprecating `From` impl
blocks AFAICT.
We have deprecated all other functions that use the identifier
'schnorrsig' but we missed `generate_schnorrsig_keypair`.
This function is purely a helper function and serves no real purpose
other than to reduce two lines of code to a single line. Downstream
users can write this function themselves if they need it.
Also, we recently added a new public method to `KeyPair` to get the
public key in a slightly more ergonomic fashion. Use `kp.public_key()`
when replacing usage of now deprecated `generate_schnorrsig_keypair`
function.
Currently to get the `XOnlyPublicKey` from a `KeyPair` users must do
`XOnlyPublicKey::from_keypair(&kp)`. While this does the job we can make
the lib more ergonomic by providing a method directly on `KeyPair` that
calls through to `XOnlyPublicKey::from_keypair`.
Add method `KeyPair::public_key(&self)`.
Rustc can warn us when we forget to add `Copy` and `Deubg` trait
implementations to types.
Add lint directives to enable warnings for missing `Copy` and `Debug`
implementations. Use the newly emitted warnings to find types that do
not implement our 'standard' traits. These 'standard' traits are defined
as the set of attributes that it has been found beneficial to
opportunistically add to all types, these are
- Copy
- Clone
- Debug
- PartialEq and Eq
- PartialOrd and Ord
- Hash
18f74d5242 Clarify what does "less security" mean (Martin Habovstiak)
94c55b4d09 Fixed typos/grammar mistakes (Martin Habovštiak)
1bf05523f0 Documented features (Martin Habovstiak)
Pull request description:
This documents the Cargo features making sure docs.rs shows warning for
feature-gated items. They are also explicitly spelled out in the crate
documentation.
The PR is similar in spirit to https://github.com/rust-bitcoin/rust-bitcoin/pull/633
ACKs for top commit:
apoelstra:
ACK 18f74d5242
Tree-SHA512: 8aac3fc5fd8ee887d6b13606d66b3d11ce44662afb92228c4f8da6169e3f70ac6a005b328f427a91d307f8d36d091dcf24bfe4d17dfc034d02b578258719a90a
This documents the Cargo features making sure docs.rs shows warning for
feature-gated items. They are also explicitly spelled out in the crate
documentation.
It is not immediately apparent what 'err == 1' means, one must determine
that the FFI function call returns 1 for success. We can help readers of
the code by adding a 'Return' section to the method documentation.
Add trailing full stop to method docs initial line also.
Two functions in the FFI secp code return and accept a parity int.
Currently we are manually converting this to a bool. Doing so forces
readers of the code to think what the bool means even though
understanding this bool is not needed since in is just passed back down
to the FFI code. We can abstract this away by using an opaque type to
hold the original int and not converting it to a boolean value.
Add 'Return' and 'Error' sections to `tweak_add_assign` while fixing the
docs to describe the new opaque parity type.
We have two `tweak_add_assign` methods (one for keypair and one for
x-only pubkey). Both check the return value from a FFI function call.
We can make both sites uniform to _slightly_ reduce cognitive load when
reading the code.
Use C style code to make it obvious to readers that this is basically C
code.
There are currently two unit tests in the `schnorr` module that are
testing keys from the `key` module. This is possible because the tests
are only testing the public interface, none the less they are better
placed in the `key` module.
The import statements can be simplified by using an import
wildcard (`super::*`). While we are at it put them in std, external
crate, this crate order.
21aa914ad2 Change context objects for schnorr sig methods (sanket1729)
Pull request description:
- The current schnorrsig verify methods should operate on verify context
as is done throughout the bitcoin core
- Finally, and importantly the XonlyPublicKey::from_keypair now operates
without any context parameter.
ACKs for top commit:
apoelstra:
ACK 21aa914ad2
Tree-SHA512: 035338f19839805a080eb262ae7b93ab187dabb63086c8b7f6015f3a6006986604dc2c6f329a99a20ddfa78c1ee518f44cd5eee2f73810fbdc83ff8df7d12506
- The current schnorrsig verify methods should operate on verify context
as is done throughout the bitcoin core
- Scondly, and importantly the XonlyPublicKey::from_keypair now operates
without any context objects.
24d6f62603 Use explicit u8 when assigning a byte slice (junderw)
Pull request description:
Is there a way to tell the compiler to not allow `[0; 64]` and require that either the type is explicitly given to the variable, or that each member uses explicit `0u8` notation?
I noticed the usage was a mix of explicit and implicit, so I changed all to explicit.
ACKs for top commit:
apoelstra:
ACK 24d6f62603
Tree-SHA512: f7796dcc3ae240983257bef0f25bd0df741943f75d86e9bca7c45076af179d96ce213bd9c339a01f721f7dc9b96a0a4a56ef2cf44339f4c91d208103b7659d9f
This reduces the usage of real cryptography in --cfg=fuzzing,
specifically replacing the secret->public key derivation with a
simple copy and ECDH with XOR of the public and private parts
(plus a stream of 1s to make a test pass that expected non-0
output).
It leaves secret tweak addition/multiplication as-is.
It also changes the context creation to over-allocate and store
the context flags at the end of the context buffer, allowing us
to easily test context flags in each function.
While it would be nice to have something fancier (eg XOR-based),
its not immediately obvious how to accomplish this, and better to
fix the issues I have than spend too much time on it.
Fixes#271.
This partially reverts b811ec133a
In the next commit the secret->public key derivation in fuzzing cfg
is changed to be simpler, as well as the validity rules of public
keys relaxed.
This adds a new test to ensure random keys can be added, not just
the hard-coded keys test that exists today.
Currently we are misusing `map` on an iterator to loop `n` times,
additionally the assertion is pointless. Use a for loop and assert
against the length of the set.
Instead of repeating ourselves in defining one big test for the wasm
target, we can override the `test` attribute with the `wasm-bindgen-test`
one and therefore automatically run all (supported) tests in wasm.
Unfortunately, wasm doesn't support catching panics yet which means we
have to disable the `test_panic_raw_ctx` test.
The interfaces for negate should always returns 1 as mentioned secp256k1.h L574, L563.
But in the future it might return 0 if the seckey or pubkey is invalid, but our type system doesn't allow that to ever happen.
Turns out you cannot initialize constant SecretKeys in any way; these
two constants should cover most sane use cases (other good choices
are the SECG generator and the Alpha CT generator, but these will
wait for a major CT-supporting upgrade, unless demand for them appears.)
This should be a major version number since I changed public constants
in the ffi module. I'm not doing so as the invariant "will the constants
be meaningful to the underlying library" has not changed.
In general this library's version numbers do not map well to the
underlying library, which is as-yet not versioned at all, so users
need to always be running "the lastest" rust-secp256k1 anyway, and
semantic versioning can't really be used meaninfully. So this is a
bit of a judgement call.
If you try to call PublicKey::from_secret() key with an incapable context it will
now return an error. Before it would pass through to the underlying library which
would terminate the process, something we strive to never expose.
Also change the from_ffi functions on various types to impl's of From to be more
Rustic. We cannot change the from_slice functions because they have error returns.
Also add a Secp256k1::without_caps() function which creates a capability-less
context. I find myself using this in so many places downstream that it seems
appropriate.
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]