bitcoin-core / secp256k1

Optimized C library for EC operations on curve secp256k1
MIT License
2.02k stars 978 forks source link

feature request: `with_randomized_context` method #1567

Open apoelstra opened 1 week ago

apoelstra commented 1 week ago

In rust-secp256k1 we're exploring how we can best support a signing API for systems which potentially have no allocator, may be operating multiple threads, but which have very limited threading primitives (e.g. we have atomics with acquire/release semantics but no stdlib with prepackaged mutexes or other locks).

I think a useful function would be something like

int secp256k1_with_randomized_context(const unsigned char* seed32, cb callback, void* callback_data) {
    /* create context object on the stack, which can't be done from the public API */
    secp256k1_context_rerandomize(&ctx, seed32);
    return callback(&ctx, callback_data);
}

(where cb is a type alias for a callback that takes a context and void pointer and returns an int).

Our usage here would be to implement a signing function that used a freshly randomized context but which did not require the user pass context objects through every API function, nor would it require us to maintain a global mutable context object, which is really hard to do without mutexes. The resulting function would be ~twice as slow as normal signing function but for many usecases this is acceptable since signing is not a frequent operation.

On the other hand, maintaining a global mutable 32-byte random seed would be super easy because we don't need any synchronization beyond the use of atomics to avoid UB.

cc https://github.com/bitcoin-core/secp256k1/issues/780 which is closely related to this but more general.

Kixunil commented 1 week ago

It'd be also extra nice if it was possible to guarantee that callback will be called (abort if it can't).

real-or-random commented 1 week ago
    /* create context object on the stack, which can't be done from the public API */

Couldn't you create a context on the stack using secp256k1_context_preallocated_create? I'm not saying it's elegant, and you'll need to take care of alignment, but it should be doable.

Kixunil commented 1 week ago

@real-or-random Rust doesn't have alloca so it wouldn't work for dynamically-linked system libraries without going through C. We could in principle do that but to my knowledge alloca has some problems (I don't remember the details). Calling into the library code which knows the exact size of its context sounds much more appealing.

real-or-random commented 1 week ago

without going through C. We could in principle do that but to my knowledge alloca has some problems (I don't remember the details).

alloca is simply obsolete and nonstandard, but there's nothing wrong with it. Well, except that it allocates on the stack, but this is precisely what you want to do here. The "modern" (available since C99) version are variable-length arrays.

Calling into the library code which knows the exact size of its context sounds much more appealing.

I see that, I'm just trying to understand the nature of the problem and its urgency.

real-or-random commented 1 week ago

Concept ACK

I think that's a simple way to give users the ability to rerandomize every operation, and it works without breaking our context API. We could even provide convenience wrappers for key generation and signing.

Contexts are pretty small now after we've removed all the dynamic tables. One caveat is that we need to get the stack allocation right in C89... But that's doable, we know the size of the context at compilation time of the library, and we have BIGGEST_ALIGNMENT.

Would one of you be willing to work on a PR?

apoelstra commented 1 week ago

Yes, I can take this on.