Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

[FINAL] Management canister API for tSchnorr signatures #288

Merged
merged 10 commits into from
Jul 23, 2024

Conversation

fspreiss
Copy link
Member

@fspreiss fspreiss commented Mar 25, 2024

Proposes two new management canister APIs for the upcoming threshold Schnorr signatures feature: schnorr_public_key and sign_with_schnorr.

Dedicated vs. generic API

The proposed API is dedicated to Schnorr signatures. An possible alternative approach would have been to propose an API that is generic regarding the signature and key derivation algorithms so that it can be used for ECDSA, Schnorr, and possible future signature schemes.

However, as is currently not planned to add support for additional signature schemes in the near future, except for BLS signatures that shall be available via the vetKD API, a dedicated API seems to be the better choice because a dedicated API is cleaner, simpler to use, and harder to misuse (see, e.g., the section on message vs. message hash below).

Message vs. message hash

One notable difference to the existing sign_with_ecdsa API is that sign_with_schnorr takes the full message to sign as input, rather than a message hash. This is because in the Schnorr-BIP340 and Ed25519 signature schemes the message is hashed together with other information and thus the hashing cannot be delegated to canisters, as it is done for sign_with_ecdsa.

Message size limit

The fact that the full message is included in the signature request has implications on the size of messages that can be signed. There are two possible resource limits that could apply to the size of the signature request:

  • If the canister is not on the signing subnet, the request has to satisfy the cross-net inter-canister message payload limit, which is 2 MB.
  • If the canister is on the signing subnet, the request has to satisfy the same-subnet inter-canister message payload limit, which is currently 10 MB, to be delivered to the local management canister.

In any case, the size of the message that can be signed also depends on the derivation path, because it is submitted in the same signature request.

The above limits, however, should not be problematic when using Schnorr signatures on other chains. For example, in Bitcoin, messages are typically pre-hashed before signing. Even in the case that some messages would not be pre-hashed, standard bitcoin transactions are smaller than 400 KB. Larger transactions are typically not accepted by the bitcoin network, although they can be included in blocks directly by miners. Solana does not seem to prehash transactions, however there transactions (which include the signatures) are limited to ~ 1.2 KB.

In case future applications of Schnorr/Ed25519 signatures will require signing of larger messages, then additional APIs could be added to management canister to allow for message chunking.

Copy link
Contributor

@randombit randombit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@fspreiss fspreiss requested a review from domwoe April 5, 2024 09:37
@fspreiss fspreiss marked this pull request as ready for review April 5, 2024 09:43
@fspreiss fspreiss requested a review from a team as a code owner April 5, 2024 09:43
@Dfinity-Bjoern
Copy link
Member

Overall, looks good to me. I wonder whether we shouldn't move more formal parts from the feature docs here into the spec?

@timohanke
Copy link
Contributor

In case future applications of Schnorr/Ed25519 signatures will require signing of larger messages, then additional APIs could be added to management canister to allow for message chunking.

Wouldn't it be possible to have an API where a first call returns R (the commitment to randomness) to the caller. Then the caller does the hashing himself and in a second call the caller supplies e. The signing system has to keep some state but that's also the case with message chunking. We are limited to two calls rather than n calls for n chunks and transmit less data.

Even for short messages it can be desirable if the signing system does not the see the cleartext message to eliminate any possibilities for censorship.

@Dfinity-Bjoern
Copy link
Member

Wouldn't it be possible to have an API where a first call returns R (the commitment to randomness) to the caller. Then the caller does the hashing himself and in a second call the caller supplies e. The signing system has to keep some state but that's also the case with message chunking. We are limited to two calls rather than n calls for n chunks and transmit less data.

It's technically possible, but comes with some downsides:

  • Creating a signature takes multiple full round trips. That is a relatively low price if the encryption key is on the same subnet (basically one execution round of delay) but is really expensive when signing from a different subnet (then it is a full roundtrip).
  • The protocol would also have to reserve the pre-signature for that request, and the canister could take very long to respond. (Of course we can time out, but we cannot do this very fast either.) As keeping pre-signatures is a large cost for the system (the amount we can generate is limited by the hand-over at checkpoint time), this has a high risk of becoming a DoS vector.

Although this should not be a security issue since e would correspond to the challenge that can be freely chosen by a dishonest verifier in the interactive protocol, we would also have check whether our security proof for the threshold Schnorr protocol makes any additional assumption about e.

Concluding from the above, I don't think we should have this as the only API because of the delays. We could consider extending the API so that in the future this may become an option (if we manage to mitigate the DoS problems)?

@randombit
Copy link
Contributor

randombit commented Apr 16, 2024

@timohanke Unfortunately your proposal does not work as if the Schnorr presignature is revealed before the message is committed to, the scheme is compromised. Quoting Victor's paper https://eprint.iacr.org/2023/1019.pdf

Indeed, the usual proof of security of ordinary, non-distributed Schnorr signatures relies in an essential way on the fact that the randomly generated group element R is not revealed before the request to sign m is given. Moreover, this is not just an artifact of the proof: there are actual subexponential attacks on signing protocols that use presignatures in this way

This issue is one reason that rerandomization of the presignature is required, and the input to the random oracle that computes this rerandomization value includes both the message being signed and the random beacon.

@timohanke
Copy link
Contributor

if the Schnorr presignature is revealed before the message is committed to, the scheme is compromised

That breaks the approach then, ok.

Too bad that some applications decided to use cleartext m instead of h(m).

@timohanke
Copy link
Contributor

timohanke commented Apr 17, 2024

@randombit I don't see how the attack described in the paper you cited applies here. The attack roughly goes like this: attacker obtains k pre-signatures, attacker crafts k benign-looking messages and asks the signer to sign them, from the signatures the attacker derives a signature on a new message that wasn't presented to the signer.

In our application the canister asks the subnet to sign messages. Conversely, the subnet only signs what the canister asks it to sign and nothing else. The canister already can get anything signed that it wants so it does not benefit from this attack. In other words, the canister is not the attacker here.

The attacker would have to be someone outside of the canister and would have to run the attack against the canister. The attacker would have to obtain presignatures before the canister has committed to the messages that it wants to sign. That can be easily prevented by the canister code. If the canister code knows the message to be signed before requesting the presignature and if it is programmed not to change the message after having obtained the presignature, then the canister is safe.

Moreover, if the canister controls the messages that it signs (as opposed to taking in messages generated by an untrusted party) then it is also safe.

Moreover, if the canister operates in a sequential fashion, i.e. obtains one presignature, then uses it before requesting the next one (as opposed to requesting k presignatures at once before using them), then it is also safe.

In summary, the attack described is an attack against the user of the signing oracle, not against the signing oracle. And is easy to prevent.

If the security proof does not go through anymore that's of course another issue. At least the described attack does not seem to be a real problem.

@Dfinity-Bjoern
Copy link
Member

One additional aspect that adds a bit of complexity is key derivation for different canisters. So the outstanding signatures may not only apply to a single canister as in the case you described, but cover outstanding signatures from multiple canisters. That may actually not be a problem, but the "just another signature for the same canister" argument does not trivially apply since the signatures of all canisters depend on the same master key. At least we would have to cover that explicitly in the analysis.

There is also a risk in exposing APIs that may not be safe depending on the use case, and I think it's fair to say that the two-step API may fail in ways that canister developers that are not proficient in the intricacies of threshold signing protocols would not expect. So an unsafe use of the API may actually make a canister vulnerable, if the canister does not explicitly protect against the vulnerability.

That said, if we can rule out or minimize potential security issues, including the denial of service issues laid out above, we could consider offering a two-step API in the future. But due to the inherently increased latency, I think we would in either case still offer the single step API, and thus I would suggest that we for now proceed with the plans laid out in the PR, and look into a possible extension independently.

@Dfinity-Bjoern Dfinity-Bjoern changed the title Management canister API for tSchnorr signatures [FINAL] Management canister API for tSchnorr signatures Apr 23, 2024
spec/index.md Outdated Show resolved Hide resolved
@mraszyk mraszyk merged commit 99bc27c into master Jul 23, 2024
4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants