-
Notifications
You must be signed in to change notification settings - Fork 229
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
Ed25519 malleability vs libsodium #20
Comments
Hi @aep! Thanks for asking about this! So the malleability in question is due to the fact that curve25519 does not have prime order (meaning that the number of points on the curve is not prime). Instead, the order is And then imagine that to produce a point on the curve, it depends on how each cog is (independently) rotated. This means that every time any cryptographic primitive depends upon something being within a prime-order group, there are potentially eight "equal" things in curve25519. This comes into play w.r.t. signatures in two ways:
In implementation, scalars are generally not guaranteed to be less than The above two things produce the following potentials for malleability, respectively:
That code has since been removed from libsodium, presumably because it breaks compatibility with legacy (read: "reference, not implemented by people in industry") implementations, the original paper, and its subsequent specification. (An interesting thing of note is that some ed25519 libraries included the check for batch signature verification and not for single signature verification, and vice versa, which produced differences in which libraries said which things were valid in which context.) Finally, to answer your question, to my knowledge it should not be possible to produce a signature with ed25519-dalek which will be rejected by libsodium. However, (I'm not entirely 100% certain, so perhaps @jedisct1 would be kind enough to comment) but I believe it might be possible to handcraft a signature which will be rejected by ed25519-dalek which would be accepted by libsodium (a malicious case of 2b above), but I've not looked into libsodium's treatment of scalars in the last year or so. |
Wow thank you so much for this long and thorough explanation. Maybe it should be added in the README for everyone to see? I still lack the background to understand why this is a problem in the first place. If all that an adversary could do is find a different valid signature for the same content, then why is there so much discussion about it? I would be really grateful if you could explain (in the readme too, not just for me) in which cases malleability is actually an issue. One thing I could image is if someone used the signature as a message id. |
The check was re-added shortly after ( |
Hi @jedisct1!
Did you mean the check that
|
@isislovecruft The check that |
This issue is clearly a design flaw in Ed25519/EdDSA. I can't imagine any good reason to have a signature scheme that is underspecified to the extent that there are signatures for which the spec doesn't say whether they should pass or fail verification. (Well, perhaps if there were a significant performance impact, but there isn't.) For blockchain consensus, for instance, that's obviously a severe problem. More generally, whenever you have multiple parties verifying signatures (including different pieces of software on behalf of the same user), it introduces complexities that we shouldn't have to think about. Protocol security analysis is hard enough as it is. This isn't by itself enough to justify changing the definition of existing signature schemes (IMHO). But it should be a design criterion for new signature schemes [insert plug for RedDSA (section 5.4.6 here), or Schnorr-over-Ristretto], and it needs to be considered every time an existing signature scheme that fails this criterion is included in a new protocol. |
Also note that this criterion isn't quite the same thing as malleability. You can have a signature scheme for which it is well-specified whether a given signature passes or fails verification, but that is still malleable (meaning that an adversary, in a chosen message attack, can produce a fresh signature on a previously signed message). You can also have a nonmalleable signature scheme for which there are "nonstandard" signatures (meaning that they're not produced by the specified signing algorithm), for which it is not well-specified whether they pass or fail verification. Nonmalleability here would require that only the private key holder can produce such signatures. Arguably, both well-specified verification (including for batch verification) and nonmalleability are useful design goals for new signature schemes. |
As an update to the forms of malleability: Signature
|
Hi Isis, I spent half a day looking at this, but I failed to see how this is possible. A signature (s, R) on a public key A and message M is considered valid as long as [8][s]B = [8]R + [8][h]A, where h = SHA-512(R, A, M) If either R or A is modified, h would change unpredictably. Did I miss anything? |
Just out of curiosity, I took a closer look at the verify_strict() function. Unlike the verify function verify_strict checks that R (and -A) does not have small order. I'm not sure how this check can help prevent the malleability issue. If R = P + Q where P has larger order and Q has small order, R has larger order. Also, it seems that all verify functions:
This seems contradicted by what is claimed in the documentation. FWIW, Tink verifies that 0 <= s < L, and [s]B = R + [h]A. We don't multiply by the co-factor. This is conformant to RFC8032 which requires that R and A are selected from the subgroup generated by B, making the multiplication by 8 moot. Thoughts? Edit: typos |
Hi @isislovecruft, thanks for including the malleability check to the library! I have some comments regarding the forms of malleability, mostly concerning the documentation. The malleability check seems to happen on deserialization of the signature and not in the
Regarding "point malleability":
However this is clearly not sufficient, as it does not guarantee
|
Hi,
i'm still confused if malleability is a problem or not.
"A signature scheme is malleable if, given a signature σ on a message m, one can
efficiently derive a signature σ' on a message m' = T(m) for an allowed transformation T."
The m' = T(m) is where i get lost. If there isn't any additional MAC, doesnt that mean any T is valid and therefor the signature schema is broken?
Even if not, libsodium has added this change
jedisct1/libsodium#125
And as far as i my limited understanding goes this may lead to ed25519-dalek producing signatures rejected by libsodium. Would it be worth following libsodium here, since it's very popular and incompatibilities may be rather unexpected?
The text was updated successfully, but these errors were encountered: