|
| 1 | +/*********************************************************************** |
| 2 | + * Copyright (c) 2015 Pieter Wuille * |
| 3 | + * Distributed under the MIT software license, see the accompanying * |
| 4 | + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * |
| 5 | + ***********************************************************************/ |
| 6 | + |
| 7 | +#ifndef _SECP256K1_SCHNORR_IMPL_H_ |
| 8 | +#define _SECP256K1_SCHNORR_IMPL_H_ |
| 9 | + |
| 10 | +#include <string.h> |
| 11 | + |
| 12 | +#include "schnorr.h" |
| 13 | +#include "num.h" |
| 14 | +#include "field.h" |
| 15 | +#include "group.h" |
| 16 | +#include "ecmult.h" |
| 17 | +#include "ecmult_gen.h" |
| 18 | + |
| 19 | +/** |
| 20 | + * Custom Schnorr-based signature scheme: |
| 21 | + * |
| 22 | + * Signing: |
| 23 | + * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) |
| 24 | + * |
| 25 | + * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). |
| 26 | + * Compute 32-byte r, the serialization of R's x coordinate. |
| 27 | + * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. |
| 28 | + * Compute scalar s = k - h * x. |
| 29 | + * The signature is (r, s). |
| 30 | + * |
| 31 | + * |
| 32 | + * Verification: |
| 33 | + * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) |
| 34 | + * |
| 35 | + * Signature is invalid if s >= order. |
| 36 | + * Signature is invalid if r >= p. |
| 37 | + * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. |
| 38 | + * Option 1 (faster for single verification): |
| 39 | + * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. |
| 40 | + * Signature is valid if the serialization of R's x coordinate equals r. |
| 41 | + * Option 2 (allows batch validation and pubkey recovery): |
| 42 | + * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. |
| 43 | + * Signature is valid if R + h * Q + s * G == 0. |
| 44 | + */ |
| 45 | + |
| 46 | +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context_t* ctx, unsigned char *sig64, const secp256k1_scalar_t *key, secp256k1_scalar_t *nonce, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { |
| 47 | + secp256k1_gej_t Rj; |
| 48 | + secp256k1_ge_t Ra; |
| 49 | + unsigned char h32[32]; |
| 50 | + secp256k1_scalar_t h, s; |
| 51 | + int overflow; |
| 52 | + |
| 53 | + if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { |
| 54 | + return 0; |
| 55 | + } |
| 56 | + |
| 57 | + secp256k1_ecmult_gen(ctx, &Rj, nonce); |
| 58 | + secp256k1_ge_set_gej(&Ra, &Rj); |
| 59 | + secp256k1_fe_normalize(&Ra.y); |
| 60 | + if (secp256k1_fe_is_odd(&Ra.y)) { |
| 61 | + secp256k1_scalar_negate(nonce, nonce); |
| 62 | + } |
| 63 | + secp256k1_fe_normalize(&Ra.x); |
| 64 | + secp256k1_fe_get_b32(sig64, &Ra.x); |
| 65 | + hash(h32, sig64, msg32); |
| 66 | + overflow = 0; |
| 67 | + secp256k1_scalar_set_b32(&h, h32, &overflow); |
| 68 | + if (overflow || secp256k1_scalar_is_zero(&h)) { |
| 69 | + return 0; |
| 70 | + } |
| 71 | + secp256k1_scalar_mul(&s, &h, key); |
| 72 | + secp256k1_scalar_negate(&s, &s); |
| 73 | + secp256k1_scalar_add(&s, &s, nonce); |
| 74 | + secp256k1_scalar_get_b32(sig64 + 32, &s); |
| 75 | + return 1; |
| 76 | +} |
| 77 | + |
| 78 | +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, const secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { |
| 79 | + secp256k1_gej_t Qj, Rj; |
| 80 | + secp256k1_ge_t Ra; |
| 81 | + secp256k1_fe_t Rx; |
| 82 | + secp256k1_scalar_t h, s; |
| 83 | + unsigned char hh[32]; |
| 84 | + int overflow; |
| 85 | + |
| 86 | + if (secp256k1_ge_is_infinity(pubkey)) { |
| 87 | + return 0; |
| 88 | + } |
| 89 | + hash(hh, sig64, msg32); |
| 90 | + overflow = 0; |
| 91 | + secp256k1_scalar_set_b32(&h, hh, &overflow); |
| 92 | + if (overflow || secp256k1_scalar_is_zero(&h)) { |
| 93 | + return 0; |
| 94 | + } |
| 95 | + overflow = 0; |
| 96 | + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); |
| 97 | + if (overflow) { |
| 98 | + return 0; |
| 99 | + } |
| 100 | + if (!secp256k1_fe_set_b32(&Rx, sig64)) { |
| 101 | + return 0; |
| 102 | + } |
| 103 | + secp256k1_gej_set_ge(&Qj, pubkey); |
| 104 | + secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); |
| 105 | + if (secp256k1_gej_is_infinity(&Rj)) { |
| 106 | + return 0; |
| 107 | + } |
| 108 | + secp256k1_ge_set_gej_var(&Ra, &Rj); |
| 109 | + secp256k1_fe_normalize_var(&Ra.y); |
| 110 | + if (secp256k1_fe_is_odd(&Ra.y)) { |
| 111 | + return 0; |
| 112 | + } |
| 113 | + return secp256k1_fe_equal_var(&Rx, &Ra.x); |
| 114 | +} |
| 115 | + |
| 116 | +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { |
| 117 | + secp256k1_gej_t Qj, Rj; |
| 118 | + secp256k1_ge_t Ra; |
| 119 | + secp256k1_fe_t Rx; |
| 120 | + secp256k1_scalar_t h, s; |
| 121 | + unsigned char hh[32]; |
| 122 | + int overflow; |
| 123 | + |
| 124 | + hash(hh, sig64, msg32); |
| 125 | + overflow = 0; |
| 126 | + secp256k1_scalar_set_b32(&h, hh, &overflow); |
| 127 | + if (overflow || secp256k1_scalar_is_zero(&h)) { |
| 128 | + return 0; |
| 129 | + } |
| 130 | + overflow = 0; |
| 131 | + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); |
| 132 | + if (overflow) { |
| 133 | + return 0; |
| 134 | + } |
| 135 | + if (!secp256k1_fe_set_b32(&Rx, sig64)) { |
| 136 | + return 0; |
| 137 | + } |
| 138 | + if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { |
| 139 | + return 0; |
| 140 | + } |
| 141 | + secp256k1_gej_set_ge(&Rj, &Ra); |
| 142 | + secp256k1_scalar_inverse_var(&h, &h); |
| 143 | + secp256k1_scalar_negate(&s, &s); |
| 144 | + secp256k1_scalar_mul(&s, &s, &h); |
| 145 | + secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); |
| 146 | + if (secp256k1_gej_is_infinity(&Qj)) { |
| 147 | + return 0; |
| 148 | + } |
| 149 | + secp256k1_ge_set_gej(pubkey, &Qj); |
| 150 | + return 1; |
| 151 | +} |
| 152 | + |
| 153 | +#endif |
0 commit comments