@@ -273,6 +273,63 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
273
273
const secp256k1_xonly_pubkey * pubkey
274
274
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (5 );
275
275
276
+ /** Schnorr Anti-Exfil Protocol
277
+ *
278
+ * The secp256k1_schnorrsig_anti_exfil_*, functions can be used to prevent a signing device from
279
+ * exfiltrating the secret signing keys through biased signature nonces. The general
280
+ * idea is that a host provides additional randomness to the signing device client
281
+ * and the client commits to the randomness in the nonce using sign-to-contract.
282
+ *
283
+ * The following scheme is described by Stepan Snigirev here:
284
+ * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-February/017655.html
285
+ * and by Pieter Wuille (as "Scheme 6") here:
286
+ * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-March/017667.html
287
+ *
288
+ * In order to ensure the host cannot trick the signing device into revealing its
289
+ * keys, or the signing device to bias the nonce despite the host's contributions,
290
+ * the host and client must engage in a commit-reveal protocol as follows:
291
+ * 1. The host draws randomness `rho` and computes a sha256 commitment to it using
292
+ * `secp256k1_schnorrsig_anti_exfil_host_commit`. It sends this to the signing device.
293
+ * 2. The signing device computes a public nonce `R` using the host's commitment
294
+ * as auxiliary randomness, using `secp256k1_schnorrsig_anti_exfil_signer_commit`.
295
+ * The signing device sends the resulting `R` to the host as a s2c_opening.
296
+ *
297
+ * If, at any point from this step onward, the hardware device fails, it is
298
+ * okay to restart the protocol using **exactly the same `rho`** and checking
299
+ * that the hardware device proposes **exactly the same** `R`. Otherwise, the
300
+ * hardware device may be selectively aborting and thereby biasing the set of
301
+ * nonces that are used in actual signatures.
302
+ *
303
+ * It takes many (>100) such aborts before there is a plausible attack, given
304
+ * current knowledge in 2024. However such aborts accumulate even across a total
305
+ * replacement of all relevant devices (but not across replacement of the actual
306
+ * signing keys with new independently random ones).
307
+ *
308
+ * In case the hardware device cannot be made to sign with the given `rho`, `R`
309
+ * pair, wallet authors should alert the user and present a very scary message
310
+ * implying that if this happens more than even a few times, say 20 or more times
311
+ * EVER, they should change hardware vendors and perhaps sweep their coins.
312
+ *
313
+ * 3. The host replies with `rho` generated in step 1.
314
+ * 4. The device signs with `secp256k1_schnorrsig_sign_custom`, using `rho` as `s2c_data32` of the
315
+ * extraparams, and sends the signature to the host.
316
+ * 5. The host verifies that the signature's public nonce matches the opening from
317
+ * step 2 and its original randomness `rho`, using `secp256k1_schnorrsig_anti_exfil_host_verify`.
318
+ *
319
+ * Rationale:
320
+ * - The reason for having a host commitment is to allow the signing device to
321
+ * deterministically derive a unique nonce even if the host restarts the protocol
322
+ * using the same message and keys. Otherwise the signer might reuse the original
323
+ * nonce in two iterations of the protocol with different `rho`, which leaks the
324
+ * the secret key.
325
+ * - The signer does not need to check that the host commitment matches the host's
326
+ * claimed `rho`. Instead it re-derives the commitment (and its original `R`) from
327
+ * the provided `rho`. If this differs from the original commitment, the result
328
+ * will be an invalid `s2c_opening`, but since `R` was unique there is no risk to
329
+ * the signer's secret keys. Because of this, the signing device does not need to
330
+ * maintain any state about the progress of the protocol.
331
+ */
332
+
276
333
/** Verify a sign-to-contract commitment.
277
334
*
278
335
* Returns: 1: the signature contains a commitment to data32
0 commit comments