Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rare case when Schnorr's signature can't be verified #56

Open
StackOverflowExcept1on opened this issue Jan 3, 2025 · 1 comment
Open

Comments

@StackOverflowExcept1on
Copy link

StackOverflowExcept1on commented Jan 3, 2025

this case occurs with probability $\approx \frac{1}{ 2^{128} }$
ecrecover(e, v, r, s) accepts any e, 27/28 for v and r, s in [1, Secp256k1.N), where N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

suppose public key has pubKey.x >= N and in that case ecrecover will return address(0). so the protocol can't verify the signature. which means you lose control of the smart contract.

// Set r = Pₓ
uint r = pubKey.x;

r, s range:

fix: if (!(pubKey.isOnCurve() && pubKey.x < LibSecp256k1.Q())) {

also need to reject pubKey.x >= Secp256k1.N for group public key on backend and at constructor?

if (!pubKey.isOnCurve()) {
return false;
}

@max-wickham max-wickham mentioned this issue Jan 6, 2025
Closed
@pmerkleplant
Copy link
Member

Thank you very much for raising the issue, this is an incredible finding!

Context

While the issue in essence is valid, ie there exist valid public keys with x >= N whose Schnorr signatures are not verifiable with LibSchnorr, it is important to note that this does not lead to "losing control of the smart contract". The poke will just not be accepted, leading to an at most delayed oracle update. The auth functionality is not impaired by this in any way. Further, the issue does not lead to a possibility of invalid pokes being accepted.

I agree that the probability of such a public key to occur is roughly $\frac{1}{2^{128}}$. Note that secp256k1's security in general is 128 bit due to birthday paradox and baby-step giant-step algorithm. Therefore, we determine this issue to be of negligible practical relevance.

Fix

I disagree with the recommended fix though. Instead of disallowing a valid subset of public keys to participate I would rather want to fix LibSchnorr itself by performing the necessary modulo operation on the x coordinate, ie:

- // Set r = Pₓ
- uint r = pubKey.x;
+ // Set r = Pₓ mod Q
+ uint r = pubKey.x % LibSecp256k1.Q();

Note that ecrecover internally will use r = Pₓ inside (mod Q) operations and, as modulo operations respect addition, its fine to reduce r = Pₓ beforehand.

This also nicely showcases that, indeed, the fundamental issue lies in the unintuitive constrains when (ab)using ecrecover for ecmul operations.

Next Steps

While we will prepare a new release candidate, it is important to note that we cannot release a new version without conducting external security reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants