|
| 1 | +#ifndef SECP256K1_DLEQ_IMPL_H |
| 2 | +#define SECP256K1_DLEQ_IMPL_H |
| 3 | + |
| 4 | +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying |
| 5 | + * SHA256 to SHA256("BIP0374/aux")||SHA256("BIP0374/aux"). */ |
| 6 | +static void secp256k1_nonce_function_bip374_sha256_tagged_aux(secp256k1_sha256 *sha) { |
| 7 | + secp256k1_sha256_initialize(sha); |
| 8 | + sha->s[0] = 0x48479343ul; |
| 9 | + sha->s[1] = 0xa9eb648cul; |
| 10 | + sha->s[2] = 0x58952fe4ul; |
| 11 | + sha->s[3] = 0x4772d3b2ul; |
| 12 | + sha->s[4] = 0x977ab0a0ul; |
| 13 | + sha->s[5] = 0xcb8e2740ul; |
| 14 | + sha->s[6] = 0x60bb4b81ul; |
| 15 | + sha->s[7] = 0x68a41b66ul; |
| 16 | + |
| 17 | + sha->bytes = 64; |
| 18 | +} |
| 19 | + |
| 20 | +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying |
| 21 | + * SHA256 to SHA256("BIP0374/nonce")||SHA256("BIP0374/nonce"). */ |
| 22 | +static void secp256k1_nonce_function_bip374_sha256_tagged(secp256k1_sha256 *sha) { |
| 23 | + secp256k1_sha256_initialize(sha); |
| 24 | + sha->s[0] = 0xa810fc87ul; |
| 25 | + sha->s[1] = 0x3b4a4d2aul; |
| 26 | + sha->s[2] = 0xe302cfb4ul; |
| 27 | + sha->s[3] = 0x322df1a0ul; |
| 28 | + sha->s[4] = 0xd2e7fb82ul; |
| 29 | + sha->s[5] = 0x7808570dul; |
| 30 | + sha->s[6] = 0x9c33e0cdul; |
| 31 | + sha->s[7] = 0x2dfbf7f6ul; |
| 32 | + |
| 33 | + sha->bytes = 64; |
| 34 | +} |
| 35 | + |
| 36 | +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying |
| 37 | + * SHA256 to SHA256("BIP0374/challenge")||SHA256("BIP0374/challenge"). */ |
| 38 | +static void secp256k1_dleq_sha256_tagged(secp256k1_sha256 *sha) { |
| 39 | + secp256k1_sha256_initialize(sha); |
| 40 | + sha->s[0] = 0x24f1c9c7ul; |
| 41 | + sha->s[1] = 0xd1538c75ul; |
| 42 | + sha->s[2] = 0xc9874ae8ul; |
| 43 | + sha->s[3] = 0x6566de76ul; |
| 44 | + sha->s[4] = 0x487843c9ul; |
| 45 | + sha->s[5] = 0xc13d8026ul; |
| 46 | + sha->s[6] = 0x39a2f3eful; |
| 47 | + sha->s[7] = 0x2ad0fcb3ul; |
| 48 | + |
| 49 | + sha->bytes = 64; |
| 50 | +} |
| 51 | + |
| 52 | +static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) { |
| 53 | + unsigned char buf[33]; |
| 54 | + size_t size = 33; |
| 55 | + if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) { |
| 56 | + return 0; |
| 57 | + } |
| 58 | + secp256k1_sha256_write(sha, buf, size); |
| 59 | + return 1; |
| 60 | +} |
| 61 | + |
| 62 | +static void secp256k1_nonce_function_dleq(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *aux_rand32) { |
| 63 | + secp256k1_sha256 sha; |
| 64 | + unsigned char masked_key[32]; |
| 65 | + int i; |
| 66 | + |
| 67 | + if (aux_rand32 != NULL) { |
| 68 | + secp256k1_nonce_function_bip374_sha256_tagged_aux(&sha); |
| 69 | + secp256k1_sha256_write(&sha, aux_rand32, 32); |
| 70 | + secp256k1_sha256_finalize(&sha, masked_key); |
| 71 | + for (i = 0; i < 32; i++) { |
| 72 | + masked_key[i] ^= key32[i]; |
| 73 | + } |
| 74 | + } else { |
| 75 | + /* Precomputed TaggedHash("BIP0374/aux", 0x0000...00); */ |
| 76 | + static const unsigned char ZERO_MASK[32] = { |
| 77 | + 38, 255, 199, 133, 21, 94, 75, 99, |
| 78 | + 18, 166, 0, 53, 197, 146, 253, 84, |
| 79 | + 197, 228, 235, 145, 124, 59, 203, 21, |
| 80 | + 66, 88, 250, 253, 207, 123, 43, 55 |
| 81 | + }; |
| 82 | + for (i = 0; i < 32; i++) { |
| 83 | + masked_key[i] = key32[i] ^ ZERO_MASK[i]; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + secp256k1_nonce_function_bip374_sha256_tagged(&sha); |
| 88 | + /* Hash masked-key||msg using the tagged hash as per the spec */ |
| 89 | + secp256k1_sha256_write(&sha, masked_key, 32); |
| 90 | + secp256k1_sha256_write(&sha, msg, msglen); |
| 91 | + secp256k1_sha256_finalize(&sha, nonce32); |
| 92 | +} |
| 93 | + |
| 94 | +/* Generates a nonce as defined in BIP0374 */ |
| 95 | +static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *a32, const unsigned char *A_33, const unsigned char *C_33, const unsigned char *aux_rand32) { |
| 96 | + unsigned char buf[66]; |
| 97 | + unsigned char nonce[32]; |
| 98 | + |
| 99 | + memcpy(buf, A_33, 33); |
| 100 | + memcpy(buf + 33, C_33, 33); |
| 101 | + secp256k1_nonce_function_dleq(nonce, buf, 66, a32, aux_rand32); |
| 102 | + |
| 103 | + secp256k1_scalar_set_b32(k, nonce, NULL); |
| 104 | + if (secp256k1_scalar_is_zero(k)) { |
| 105 | + return 0; |
| 106 | + } |
| 107 | + |
| 108 | + return 1; |
| 109 | +} |
| 110 | + |
| 111 | +/* Generates a challenge as defined in BIP0374 */ |
| 112 | +static void secp256k1_dleq_challenge(secp256k1_scalar *e, secp256k1_ge *B, secp256k1_ge *R1, secp256k1_ge *R2, secp256k1_ge *A, secp256k1_ge *C, const unsigned char *m) { |
| 113 | + unsigned char buf[32]; |
| 114 | + secp256k1_sha256 sha; |
| 115 | + secp256k1_ge generator_point = secp256k1_ge_const_g; |
| 116 | + |
| 117 | + secp256k1_dleq_sha256_tagged(&sha); |
| 118 | + secp256k1_dleq_hash_point(&sha, A); |
| 119 | + secp256k1_dleq_hash_point(&sha, B); |
| 120 | + secp256k1_dleq_hash_point(&sha, C); |
| 121 | + secp256k1_dleq_hash_point(&sha, &generator_point); |
| 122 | + secp256k1_dleq_hash_point(&sha, R1); |
| 123 | + secp256k1_dleq_hash_point(&sha, R2); |
| 124 | + if (m) secp256k1_sha256_write(&sha, m, 32); |
| 125 | + secp256k1_sha256_finalize(&sha, buf); |
| 126 | + |
| 127 | + secp256k1_scalar_set_b32(e, buf, NULL); |
| 128 | +} |
| 129 | + |
| 130 | +/* Generate points from scalar a such that A = a*G and C = a*B */ |
| 131 | +static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *A, secp256k1_ge *C, const secp256k1_scalar *a, const secp256k1_ge *B) { |
| 132 | + secp256k1_gej Aj, Cj; |
| 133 | + |
| 134 | + secp256k1_ecmult_gen(ecmult_gen_ctx, &Aj, a); |
| 135 | + secp256k1_ge_set_gej(A, &Aj); |
| 136 | + secp256k1_ecmult_const(&Cj, B, a); |
| 137 | + secp256k1_ge_set_gej(C, &Cj); |
| 138 | +} |
| 139 | + |
| 140 | +/* DLEQ Proof Generation |
| 141 | + * |
| 142 | + * For given elliptic curve points A, B, C, and G, the prover generates a proof to prove knowledge of a scalar a such |
| 143 | + * that A = a⋅G and C = a⋅B without revealing anything about a. |
| 144 | + * |
| 145 | + * Returns: 1 if proof creation was successful. 0 if an error occurred. |
| 146 | + * Out: scalar e: part of proof = bytes(32, e) || bytes(32, s). |
| 147 | + * scalar s: other part of proof = bytes(32, e) || bytes(32, s). |
| 148 | + * In: a : scalar a to be proven that both A and C were generated from |
| 149 | + * B : point on the curve |
| 150 | + * A : point on the curve(a⋅G) generated from a |
| 151 | + * C : point on the curve(a⋅B) generated from a |
| 152 | + * aux_rand32 : pointer to 32-byte auxiliary randomness used to generate the nonce in secp256k1_nonce_function_dleq. |
| 153 | + * m : an optional message |
| 154 | + * */ |
| 155 | +static int secp256k1_dleq_prove(const secp256k1_context *ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *a, secp256k1_ge *B, secp256k1_ge *A, secp256k1_ge *C, const unsigned char *aux_rand32, const unsigned char *m) { |
| 156 | + secp256k1_ge R1, R2; |
| 157 | + secp256k1_scalar k = { 0 }; |
| 158 | + unsigned char a32[32]; |
| 159 | + unsigned char A_33[33]; |
| 160 | + unsigned char B_33[33]; |
| 161 | + unsigned char C_33[33]; |
| 162 | + int ret = 1; |
| 163 | + size_t pubkey_size = 33; |
| 164 | + |
| 165 | + secp256k1_scalar_get_b32(a32, a); |
| 166 | + if (!secp256k1_eckey_pubkey_serialize(B, B_33, &pubkey_size, 1)) { |
| 167 | + return 0; |
| 168 | + } |
| 169 | + if (!secp256k1_eckey_pubkey_serialize(A, A_33, &pubkey_size, 1)) { |
| 170 | + return 0; |
| 171 | + } |
| 172 | + if (!secp256k1_eckey_pubkey_serialize(C, C_33, &pubkey_size, 1)) { |
| 173 | + return 0; |
| 174 | + } |
| 175 | + ret &= secp256k1_dleq_nonce(&k, a32, A_33, C_33, aux_rand32); |
| 176 | + |
| 177 | + /* R1 = k*G, R2 = k*B */ |
| 178 | + secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &R1, &R2, &k, B); |
| 179 | + /* We declassify the non-secret values R1 and R2 to allow using them as |
| 180 | + * branch points. */ |
| 181 | + secp256k1_declassify(ctx, &R1, sizeof(R1)); |
| 182 | + secp256k1_declassify(ctx, &R2, sizeof(R2)); |
| 183 | + |
| 184 | + /* e = tagged hash(A, B, C, R1, R2) */ |
| 185 | + /* s = k + e * a */ |
| 186 | + secp256k1_dleq_challenge(e, B, &R1, &R2, A, C, m); |
| 187 | + secp256k1_scalar_mul(s, e, a); |
| 188 | + secp256k1_scalar_add(s, s, &k); |
| 189 | + |
| 190 | + secp256k1_scalar_clear(&k); |
| 191 | + return ret; |
| 192 | +} |
| 193 | + |
| 194 | +/* DLEQ Proof Verification |
| 195 | + * |
| 196 | + * Verifies the proof. If the following algorithm succeeds, the points A and C were both generated from the same scalar. |
| 197 | + * The former from multiplying by G, and the latter from multiplying by B. |
| 198 | + * |
| 199 | + * Returns: 1 if proof verification was successful. 0 if an error occurred. |
| 200 | + * In: proof : proof bytes(32, e) || bytes(32, s) consists of scalar e and scalar s |
| 201 | + * A : point on the curve(a⋅G) computed from a |
| 202 | + * B : point on the curve |
| 203 | + * C : point on the curve(a⋅B) computed from a |
| 204 | + * m : optional message |
| 205 | + * */ |
| 206 | +static int secp256k1_dleq_verify(secp256k1_scalar *s, secp256k1_scalar *e, secp256k1_ge *A, secp256k1_ge *B, secp256k1_ge *C, const unsigned char *m) { |
| 207 | + secp256k1_scalar e_neg; |
| 208 | + secp256k1_scalar e_expected; |
| 209 | + secp256k1_gej Bj; |
| 210 | + secp256k1_gej Aj, Cj; |
| 211 | + secp256k1_gej R1j, R2j; |
| 212 | + secp256k1_ge R1, R2; |
| 213 | + secp256k1_gej tmpj; |
| 214 | + |
| 215 | + secp256k1_gej_set_ge(&Aj, A); |
| 216 | + secp256k1_gej_set_ge(&Cj, C); |
| 217 | + |
| 218 | + secp256k1_scalar_negate(&e_neg, e); |
| 219 | + /* R1 = s*G - e*A */ |
| 220 | + secp256k1_ecmult(&R1j, &Aj, &e_neg, s); |
| 221 | + /* R2 = s*B - e*C */ |
| 222 | + secp256k1_ecmult(&tmpj, &Cj, &e_neg, &secp256k1_scalar_zero); |
| 223 | + secp256k1_gej_set_ge(&Bj, B); |
| 224 | + secp256k1_ecmult(&R2j, &Bj, s, &secp256k1_scalar_zero); |
| 225 | + secp256k1_gej_add_var(&R2j, &R2j, &tmpj, NULL); |
| 226 | + |
| 227 | + secp256k1_ge_set_gej(&R1, &R1j); |
| 228 | + secp256k1_ge_set_gej(&R2, &R2j); |
| 229 | + secp256k1_dleq_challenge(&e_expected, B, &R1, &R2, A, C, m); |
| 230 | + |
| 231 | + secp256k1_scalar_add(&e_expected, &e_expected, &e_neg); |
| 232 | + return secp256k1_scalar_is_zero(&e_expected); |
| 233 | +} |
| 234 | + |
| 235 | +#endif |
0 commit comments