|
| 1 | +# Schnorr Wizardry |
| 2 | + |
| 3 | +Bitcoin added support for schnorr signatures with the Taproot update, which activated at block 709 632. |
| 4 | +In this article, we dive into how it works and some of the advanced schemes it unlocks. |
| 5 | + |
| 6 | +## Table of Contents |
| 7 | + |
| 8 | +* [Schnorr signatures](#schnorr-signatures) |
| 9 | +* [Linearity of Schnorr signatures](#linearity-of-schnorr-signatures) |
| 10 | +* [Adaptor signatures](#adaptor-signatures) |
| 11 | +* [Musig2](#musig2) |
| 12 | +* [Musig2 adaptor signatures](#musig2-adaptor-signatures) |
| 13 | + |
| 14 | +## Schnorr signatures |
| 15 | + |
| 16 | +Schnorr signatures are specified in [BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). |
| 17 | +Ignoring many details described in the BIP, at a high level the signing algorithm works as follows: |
| 18 | + |
| 19 | +```text |
| 20 | +P = k*G -> signer's public key |
| 21 | +m -> message to sign |
| 22 | +
|
| 23 | +Sign: |
| 24 | + r = {0;1}^256 -> random nonce |
| 25 | + R = r*G |
| 26 | + e = H(R || P || m) |
| 27 | + s = r + e*k |
| 28 | + (s, R) -> message signature |
| 29 | +
|
| 30 | +Verify: |
| 31 | + e = H(R || P || m) |
| 32 | + R' = s*G - e*P |
| 33 | + If R = R', the signature is valid |
| 34 | +``` |
| 35 | + |
| 36 | +## Linearity of Schnorr signatures |
| 37 | + |
| 38 | +A very interesting property of schnorr signatures compared to ECDSA signatures is that they make it easy to combine signatures for a given message if we slightly change the signing algorithm. |
| 39 | + |
| 40 | +```text |
| 41 | +A = a*G -> Alice's public key |
| 42 | +B = b*G -> Bob's public key |
| 43 | +P = A + B -> combined public key |
| 44 | +m -> message to sign |
| 45 | +
|
| 46 | +Sign: |
| 47 | + ra = {0;1}^256 -> random nonce generated by Alice |
| 48 | + RA = ra*G -> public partial nonce sent by Alice to Bob |
| 49 | + rb = {0;1}^256 -> random nonce generated by Bob |
| 50 | + RB = rb*G -> public partial nonce sent by Bob to Alice |
| 51 | + R = RA + RB -> public nonce |
| 52 | + e = H(R || P || m) |
| 53 | + sA = ra + e*a -> partial signature produced by Alice |
| 54 | + sB = rb + e*b -> partial signature produced by Bob |
| 55 | + s = sA + sB |
| 56 | + (s, R) -> combined message signature |
| 57 | +
|
| 58 | +Verify: |
| 59 | + e = H(R || P || m) |
| 60 | + R' = s*G - e*P |
| 61 | + If R = R', the signature is valid |
| 62 | +``` |
| 63 | + |
| 64 | +You should notice that the verification algorithm hasn't changed. |
| 65 | +This means that the verifier doesn't even know that multiple signers were involved: the signature looks like it comes from a standard single signer. |
| 66 | + |
| 67 | +:warning: This signing scheme is not secure when Alice or Bob is malicious. We will describe a secure signing scheme in the Musig2 section below. |
| 68 | + |
| 69 | +## Adaptor signatures |
| 70 | + |
| 71 | +The linearity of schnorr signatures also allows revealing a secret through a signature. |
| 72 | + |
| 73 | +```text |
| 74 | +P = k*G -> signer's public key |
| 75 | +T = t*G -> tweak (t is the secret that will be revealed) |
| 76 | +m -> message to sign |
| 77 | +
|
| 78 | +Sign: |
| 79 | + r = {0;1}^256 |
| 80 | + R = r*G |
| 81 | + e = H(R + T || P || m) -> notice that we tweak the nonce here with T |
| 82 | + s = r + e*k -> but we don't tweak it here with t |
| 83 | + (s, R, T) -> adaptor signature: will automatically reveal t when a valid signature for nonce R + T is produced |
| 84 | +
|
| 85 | +Verify: |
| 86 | + e = H(R + T || P || m) |
| 87 | + R' = s*G - e*P |
| 88 | + If R = R', the adaptor signature is valid |
| 89 | + Note that (s, R) or (s, R + T) are not valid schnorr signatures |
| 90 | +
|
| 91 | +Complete: |
| 92 | + s' = s + t |
| 93 | + R' = R + T |
| 94 | + (s', R') -> valid schnorr signature |
| 95 | +
|
| 96 | +Extract: |
| 97 | + e' = H(R' || P || m) |
| 98 | + R'' = s'*G - e'*P |
| 99 | + If R'' = R', the signature is valid |
| 100 | + t = s' - s |
| 101 | + The verifier has learnt t through the schnorr signature |
| 102 | +``` |
| 103 | + |
| 104 | +NB: for this to work, the verifier must ensure that the nonce `R + T` is fixed beforehand. |
| 105 | +Otherwise the signer may create a valid signature for an unrelated nonce, which would not reveal the secret `t`. |
| 106 | +This is most useful when combined with Musig2, where participants commit to the nonce before signing. |
| 107 | + |
| 108 | +Adaptor signatures can also be used in the opposite way. |
| 109 | +If the signer doesn't know the secret `t`, it can produce an adaptor signature. |
| 110 | +Then another participant that knows `t` can convert that adaptor signature to a valid signature. |
| 111 | + |
| 112 | +## Musig2 |
| 113 | + |
| 114 | +[Musig2](https://eprint.iacr.org/2020/1261.pdf) is a secure scheme for combining multiple signatures into a single schnorr signature. |
| 115 | +It only needs two rounds of communications between participants, and the first round can be done ahead of time (independently of the message to sign). |
| 116 | +The novel idea in that scheme is to use multiple nonces for each participant and combine them in a smart way to produce the final nonce. |
| 117 | +This results in an elegant scheme that looks very similar to standard schnorr signing. |
| 118 | + |
| 119 | +```text |
| 120 | +PA = pa*G -> public key of participant A |
| 121 | +PB = pb*G -> public key of participant B |
| 122 | +L = sorted(PA, PB) -> sorted list of participants public keys |
| 123 | +P = H(H(L) || PA)*PA + PB -> combined public key |
| 124 | +
|
| 125 | +NonceGenA (run by participant A): |
| 126 | + ra1 = {0;1}^256 |
| 127 | + ra2 = {0;1}^256 |
| 128 | + RA1 = ra1*G |
| 129 | + RA2 = ra2*G |
| 130 | +
|
| 131 | +NonceGenB (run by participant B): |
| 132 | + rb1 = {0;1}^256 |
| 133 | + rb2 = {0;1}^256 |
| 134 | + RB1 = rb1*G |
| 135 | + RB2 = rb2*G |
| 136 | +
|
| 137 | +NonceExchange (communication round 1): |
| 138 | + Participant A sends RA1, RA2 to participant B |
| 139 | + Participant B sends RB1, RB2 to participant A |
| 140 | +
|
| 141 | +SignA (run by participant A): |
| 142 | + x = H(P || RA1 + RB1 || RA2 + RB2 || m) |
| 143 | + R = RA1 + RB1 + x*(RA2 + RB2) |
| 144 | + ra = ra1 + x*ra2 |
| 145 | + e = H(R || P || m) |
| 146 | + sa = ra + e*H(L || PA)*pa |
| 147 | + (sa, R) -> participant A's partial signature |
| 148 | +
|
| 149 | +SignB (run by participant B): |
| 150 | + x = H(P || RA1 + RB1 || RA2 + RB2 || m) |
| 151 | + R = RA1 + RB1 + x*(RA2 + RB2) |
| 152 | + rb = rb1 + x*rb2 |
| 153 | + e = H(R || P || m) |
| 154 | + sb = rb + e*H(L || PB)*pb |
| 155 | + (sb, R) -> participant B's partial signature |
| 156 | +
|
| 157 | +Combine (communication round 2): |
| 158 | + s = sa + sb |
| 159 | + (s, R) -> valid schnorr signature for public key P |
| 160 | +
|
| 161 | +Verify: |
| 162 | + e = H(R || P || m) |
| 163 | + R' = s*G - e*P |
| 164 | + = (sa + sb)*G - e*P |
| 165 | + = (ra + e*H(L || PA)*pa)*G + (rb + e*H(L || PB)*pb)*G - e*P |
| 166 | + = (ra + rb)*G + e*(H(L || PA)*pa + H(L || PB)*pb)*G - e*P |
| 167 | + = R + e*P - e*P |
| 168 | + = R |
| 169 | + -> this is a valid schnorr signature |
| 170 | +``` |
| 171 | + |
| 172 | +NB: we used only two participants to simplify the example, but Musig2 works with any number of participants. |
| 173 | + |
| 174 | +## Musig2 adaptor signatures |
| 175 | + |
| 176 | +Musig2 can be combined with adaptor signatures: |
| 177 | + |
| 178 | +```text |
| 179 | +# The first round (pre-computing nonces) is vanilla Musig2 |
| 180 | +
|
| 181 | +PA = pa*G -> public key of participant A |
| 182 | +PB = pb*G -> public key of participant B |
| 183 | +L = sorted(PA, PB) -> sorted list of participants public keys |
| 184 | +P = H(H(L) || PA)*PA + PB -> combined public key |
| 185 | +
|
| 186 | +NonceGenA (run by participant A): |
| 187 | + ra1 = {0;1}^256 |
| 188 | + ra2 = {0;1}^256 |
| 189 | + RA1 = ra1*G |
| 190 | + RA2 = ra2*G |
| 191 | +
|
| 192 | +NonceGenB (run by participant B): |
| 193 | + rb1 = {0;1}^256 |
| 194 | + rb2 = {0;1}^256 |
| 195 | + RB1 = rb1*G |
| 196 | + RB2 = rb2*G |
| 197 | +
|
| 198 | +NonceExchange (communication round 1): |
| 199 | + Participant A sends RA1, RA2 to participant B |
| 200 | + Participant B sends RB1, RB2 to participant A |
| 201 | +
|
| 202 | +# The second round simply tweaks the combined nonce with the secret |
| 203 | +
|
| 204 | +T = t*G -> secret t known only by B |
| 205 | +
|
| 206 | +SignA (run by participant A): |
| 207 | + x = H(P || RA1 + RB1 + T || RA2 + RB2 || m) |
| 208 | + R = RA1 + RB1 + x*(RA2 + RB2) |
| 209 | + ra = ra1 + x*ra2 |
| 210 | + e = H(R + T || P || m) |
| 211 | + sa = ra + e*H(L || PA)*pa |
| 212 | + (sa, R + T) -> participant A's partial signature |
| 213 | +
|
| 214 | +SignB (run by participant B): |
| 215 | + x = H(P || RA1 + RB1 + T || RA2 + RB2 || m) |
| 216 | + R = RA1 + RB1 + x*(RA2 + RB2) |
| 217 | + rb = rb1 + x*rb2 |
| 218 | + e = H(R + T || P || m) |
| 219 | + sb = rb + e*H(L || PB)*pb |
| 220 | + (sb, R, T) -> participant B's adaptor signature |
| 221 | +
|
| 222 | +Participant A can verify participant B's adaptor signature before sending its partial signature: |
| 223 | + (sa + sb)*G must be equal to R + H(R + T || P || m)*P |
| 224 | + -> NB: it's not a valid schnorr signature, notice the mismatch between R (outside of the hash) and R + T (inside the hash) |
| 225 | +
|
| 226 | +Complete (run by participant B): |
| 227 | + s = sa + sb + t |
| 228 | + R' = R + T |
| 229 | + (s, R') -> valid schnorr signature for public key P and nonce R + T |
| 230 | +
|
| 231 | +Extract (run by participant A): |
| 232 | + t = s - sa - sb |
| 233 | +``` |
0 commit comments