Skip to content

Commit

Permalink
Add anti nonce sidechannel protocol for schnorrsigs using nonce_funct…
Browse files Browse the repository at this point in the history
…ion_bipschnorr
  • Loading branch information
jonasnick committed Jan 29, 2019
1 parent 30c1d71 commit bcfc256
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 0 deletions.
71 changes: 71 additions & 0 deletions include/secp256k1_schnorrsig.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,77 @@ SECP256K1_API int secp256k1_schnorrsig_parse(
const unsigned char *in64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Anti Nonce Sidechannel Protocol
*
* The next functions can be used to prevent a signing device from exfiltrating the secret signing
* keys through biased signature nonces. The general idea is that a host provides additional
* randomness to the signing device client and the client commits to the randomness in the nonce
* using sign-to-contract.
* In order to make the randomness unpredictable, the host and client must engage in a
* commit-reveal protocol as follows:
* 1. The host draws the randomness, commits to it with the anti_nonce_sidechan_host_commit
* function and sends the commitment to the client.
* 2. The client commits to its sign-to-contract original nonce (which is the nonce without the
* sign-to-contract tweak) using the hosts commitment by calling the
* secp256k1_schnorrsig_anti_nonce_sidechan_client_commit function. The client gets the original
* nonce of the sign-to-contract commitment using secp256k1_s2c_commit_get_original_nonce and
* sends it to the host.
* 3. The host replies with the randomness generated in step 1.
* 4. The client uses anti_nonce_sidechan_client_setrand to check that the hosts commitment opens
* to the provided randomness. If not, it waits until the host sends the correct randomness or
* the protocol restarts. If the randomness matches the commitment, the client signs with the
* nonce_function_bipschnorr using the s2c context as nonce data and sends the signature and
* negated nonce flag to the host.
* 5. The host checks that the signature contains an sign-to-contract commitment to the randomness
* by calling verify_s2c_commit with the original nonce received in step 2 and the signature and
* negated nonce flag received in step 4. If verification does not succeed, it waits until the
* client sends a signature with a correct commitment or the protocol is restarted.
*/

/** Create a randomness commitment on the host as part of the Anti Nonce Sidechannel Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL)
* In: rand32: the 32-byte randomness to commit to (cannot be NULL)
*/
SECP256K1_API int secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(
secp256k1_context *ctx,
unsigned char *rand_commitment32,
const unsigned char *rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Compute commitment on the client as part of the Anti Nonce Sidechannel Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: s2c_ctx: pointer to an s2c context where the opening will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
* seckey32: the 32-byte secret key used for signing (cannot be NULL)
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
*/
SECP256K1_API int secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(
secp256k1_context *ctx,
secp256k1_s2c_commit_context *s2c_ctx,
const unsigned char *msg32,
const unsigned char *seckey32,
const unsigned char *rand_commitment32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);

/** Set host randomness on the client as part of the Anti Nonce Sidechannel Protocol.
*
* Returns: 1: given randomness matches randomness commitment stored in s2c_ctx
* 0: failure
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: s2c_ctx: pointer to an s2c context where the randomness will be stored (cannot be NULL)
* In: rand32: 32-byte randomness matching the previously received commitment (cannot be NULL)
*/
SECP256K1_API int secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(
secp256k1_context *ctx,
secp256k1_s2c_commit_context *s2c_ctx,
const unsigned char *rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Create a Schnorr signature.
*
* Returns 1 on success, 0 on failure.
Expand Down
44 changes: 44 additions & 0 deletions src/modules/schnorrsig/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,50 @@ int secp256k1_schnorrsig_verify_s2c_commit(const secp256k1_context* ctx, const s
return secp256k1_ec_commit_verify(ctx, &pubnonce, original_nonce, data32, 32);
}

int secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(secp256k1_context *ctx, unsigned char *rand_commitment32, const unsigned char *rand32) {
secp256k1_sha256 sha;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(rand_commitment32 != NULL);
ARG_CHECK(rand32 != NULL);

secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, rand32, 32);
secp256k1_sha256_finalize(&sha, rand_commitment32);

return 1;
}

int secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(secp256k1_context *ctx, secp256k1_s2c_commit_context *s2c_ctx, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *rand_commitment32) {
unsigned char nonce32[32];
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(s2c_ctx != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(seckey32 != NULL);
ARG_CHECK(rand_commitment32 != NULL);

memcpy(s2c_ctx->data_hash, rand_commitment32, 32);
return secp256k1_nonce_function_bipschnorr_no_s2c_tweak(ctx, nonce32, msg32, seckey32, NULL, s2c_ctx, 0);
}

int secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(secp256k1_context *ctx, secp256k1_s2c_commit_context *s2c_ctx, const unsigned char *rand32) {
secp256k1_sha256 sha;
unsigned char rand_hash[32];

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(s2c_ctx != NULL);
ARG_CHECK(rand32 != NULL);

secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, rand32, 32);
secp256k1_sha256_finalize(&sha, rand_hash);
if (memcmp(rand_hash, s2c_ctx->data_hash, 32) != 0) {
return 0;
}
memcpy(s2c_ctx->data, rand32, 32);
return 1;
}

int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) {
secp256k1_scalar x;
secp256k1_scalar e;
Expand Down
69 changes: 69 additions & 0 deletions src/modules/schnorrsig/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
unsigned char sk3[32];
unsigned char msg[32];
unsigned char data32[32];
unsigned char rand32[32];
unsigned char rand_commitment32[32];
unsigned char sig64[64];
secp256k1_pubkey pk[3];
secp256k1_schnorrsig sig;
Expand Down Expand Up @@ -116,6 +118,39 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig, data32, NULL, nonce_is_negated) == 0);
CHECK(ecount == 4);

secp256k1_rand256(rand32);
ecount = 0;
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(none, rand_commitment32, rand32) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(none, NULL, rand32) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(none, rand_commitment32, NULL) == 0);
CHECK(ecount == 2);

ecount = 0;
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(sign, &s2c_ctx, msg, sk1, rand_commitment32) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(none, &s2c_ctx, msg, sk1, rand_commitment32) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(sign, NULL, msg, sk1, rand_commitment32) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(sign, &s2c_ctx, NULL, sk1, rand_commitment32) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(sign, &s2c_ctx, msg, NULL, rand_commitment32) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(sign, &s2c_ctx, msg, sk1, NULL) == 0);
CHECK(ecount == 5);

ecount = 0;
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(none, &s2c_ctx, rand32) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(none, NULL, rand32) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(none, &s2c_ctx, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, sk1, NULL, &s2c_ctx) == 1);
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig, rand32, &s2c_ctx.original_pubnonce, nonce_is_negated) == 1);

ecount = 0;
CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0);
CHECK(ecount == 1);
Expand Down Expand Up @@ -780,6 +815,38 @@ void test_schnorrsig_s2c_commit_verify(void) {
}
}

void test_schnorrsig_anti_nonce_sidechannel(void) {
unsigned char msg32[32];
unsigned char key32[32];
unsigned char algo16[16];
unsigned char rand32[32];
unsigned char rand_commitment32[32];
secp256k1_s2c_commit_context s2c_ctx;
secp256k1_pubkey s2c_original_nonce;
secp256k1_schnorrsig sig;
int nonce_is_negated;

secp256k1_rand256(msg32);
secp256k1_rand256(key32);
secp256k1_rand256(rand32);
memset(algo16, 23, sizeof(algo16));

CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_host_commit(ctx, rand_commitment32, rand32) == 1);

/* Host sends rand_commitment32 to client. */
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_commit(ctx, &s2c_ctx, msg32, key32, rand_commitment32) == 1);

/* Client sends s2c original nonce. Host replies with rand32. */
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(ctx, &s2c_ctx, rand32) == 1);
/* Providing wrong data results in an error. */
CHECK(secp256k1_schnorrsig_anti_nonce_sidechan_client_setrand(ctx, &s2c_ctx, rand_commitment32) == 0);
CHECK(secp256k1_s2c_commit_get_original_nonce(ctx, &s2c_original_nonce, &s2c_ctx) == 1);
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, &nonce_is_negated, msg32, key32, NULL, &s2c_ctx) == 1);

/* Client sends signature to host. */
CHECK(secp256k1_schnorrsig_verify_s2c_commit(ctx, &sig, rand32, &s2c_original_nonce, nonce_is_negated) == 1);
}

void run_schnorrsig_tests(void) {
int i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
Expand All @@ -794,6 +861,8 @@ void run_schnorrsig_tests(void) {
* a test. */
test_schnorrsig_s2c_commit_verify();
}
test_schnorrsig_anti_nonce_sidechannel();

secp256k1_scratch_space_destroy(scratch);
}

Expand Down

0 comments on commit bcfc256

Please sign in to comment.