Skip to content

Commit fd76376

Browse files
authored
Add Schnorr wizardry cheat sheet (#15)
* Schnorr signatures * Adaptor signatures * Musig2
1 parent fe37e8e commit fd76376

File tree

2 files changed

+234
-0
lines changed

2 files changed

+234
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ A collection of some in-depth articles about the Lightning Network:
55
* [Lightning transactions: from Zero to Hero](./lightning-txs.md)
66
* [Pinning attacks](./pinning-attacks.md)
77
* [Sphinx onion encryption: from Zero to Hero](./sphinx.md)
8+
* [Schnorr Wizardry](./schnorr.md)
89
* [Spamming the Lightning Network](./spam-prevention.md)
910
* [Feature flags: from Zero to Hero](./feature-flags.md)

Diff for: schnorr.md

+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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

Comments
 (0)