Skip to content

Commit ea0a9ea

Browse files
committed
Add MuSig2 adaptor signatures
1 parent a04c58a commit ea0a9ea

File tree

2 files changed

+233
-1
lines changed

2 files changed

+233
-1
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Scriptless scripts is an approach to designing cryptographic protocol on top of
1111
* **[Atomic Pedersen Swap Using Adaptor Signatures](md/pedersen-swap.md)**
1212
* An atomic Pedersen swap exchanges a coin with the opening `(r, x)` of a Pedersen commitment `r*G + x*H`.
1313
* **[Multi-Hop Locks from Scriptless Scripts](md/multi-hop-locks.md)**
14-
* Multi-hop locks are protocols that allow two parties to exchange coins and proof of payment without requiring a mutual funding multisig output (also known as "Lightning with Scriptless Scripts").
14+
* Multi-hop locks are protocols that allow two parties to exchange coins and proof of payment without requiring a mutual funding multisig output (also known as "Lightning with Scriptless Scripts").
1515
* **[Non-Interactive Threshold Escrow (NITE)](md/NITE.md)**
1616
* NITE allows non-interactively setting up certain threshold policies on-chain, as well as off-chain if it is combined with [multi-hop locks](md/multi-hop-locks.md).
17+
* **[MuSig2 Adaptor Signatures](md/musig2-adaptorsig.md)**
18+
* As opposed to MuSig1, MuSig2 supports non-interactive signing. This document outlines how to achieve the same when adaptors come into play.

md/musig2-adaptorsig.md

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# MuSig2 Adaptor Signatures
2+
3+
## Motivation
4+
Since [MuSig2](https://eprint.iacr.org/2020/1261) is very similar to its predecessor, it is straightforward to create adaptor signatures similar to MuSig1.
5+
The version of adaptor signatures as used in the multi-hop locks (aka PTLCs) [writeup](https://github.com/ElementsProject/scriptless-scripts/blob/master/md/multi-hop-locks.md) is
6+
7+
```
8+
s'G = RA + hash(P, R + T, m)P
9+
```
10+
11+
where `s'` is a partial signature for aggregated pubkey `P` with partial nonce `RA`, aggregated nonce `R` and adaptor point `T`.
12+
13+
Note that this means that the adaptor point `T` must be determined before opening the commitments in MuSig1 (i.e. before round 2)
14+
Otherwise, an attacker can apply Wagner's algorithm by grinding `T` similar to how the attacker [can grind `m`](https://medium.com/blockstream/insecure-shortcuts-in-musig) if it's not determined before the nonce exchange
15+
MuSig2 solves the latter problem by using two nonces per participant
16+
More specifically, let `RA1, RA2` be Alice's and `RB1, RB2` be Bob's nonces
17+
Then `b = hash(P, RA1 + RB1, RA2 + RB2, m)` and Alice's "effective nonce" becomes `RA = RA1 + b*RA2`.
18+
19+
## MuSig2 Adaptor Signatures
20+
The main idea is to include the adaptor point `T` into the hash function used to compute `b`
21+
Then the nonce exchange round is purely a preprocessing step that can happen before `T` is known
22+
More precisely, `T` is added to `RA1 + RB1` before hashing.
23+
24+
We use the notation from [Generalized Bitcoin-Compatible Channels](https://eprint.iacr.org/2020/476) adjusted for multi-signature schemes and without loss of generality restricted to two parties.
25+
26+
```
27+
keyAgg(A, B):
28+
# compute the MuSig coefficients muA and muB, the
29+
# aggregated key P = muA*A + muB*B and return the
30+
# tuple (muA, P).
31+
32+
setupSession():
33+
r1, r2 <-$ rand()
34+
R1 := r1*G, R2 := r2*G
35+
return (state := (r1, R1, r2, R2), R1, R2)
36+
37+
# Create pre-signature with signing key x and a state as output by setupSession().
38+
# Takes other signer's public key B and other signer's nonces from setupSession()
39+
# RB1, RB2 and message m and adaptor T.
40+
preSign_{x,state}((B, RB1, RB2), m, T):
41+
# Similar to regular MuSig signing, the same state must never be
42+
# reused for different preSign calls
43+
(muA, P) := keyAgg(x*G, B)
44+
(rA1, RA1, rA2, RA2) := state
45+
R1 := RA1 + RB1, R2 := RB1 + RB2
46+
b := hash(P, T + R1, R2, m)
47+
R := R1 + b*R2
48+
rA := rA1 + b*rA2
49+
pre_s := rA + hash(P, R + T, m)*muA*x
50+
return pre_s
51+
52+
# Verify pre-signature pre_s for public key B, nonces RB1, RB2 and the
53+
# signer's public key A, the signer's nonces RA1 and RA2, message m
54+
# and adaptor T.
55+
preVerify_{B,RB1,RB2}((A, RA1, RA2), m, T, pre_s):
56+
(muA, P) := keyAgg(A, B)
57+
R1 := RA1 + RB1, R2 := RB1 + RB2
58+
b := hash(P, T + R1, R2, m)
59+
R := R1 + b*R2
60+
RA := RA1 + b*RA2
61+
return pre_s*G ?= RA + hash(P, R + T, m)*muA*A
62+
63+
Adapt(pre_s, t):
64+
s := pre_s + t
65+
return s
66+
67+
Ext(s, pre_s):
68+
return s - pre_s
69+
```
70+
71+
Note that another option would be to compute `b` by concatenating the adaptor `T` to the string that is hashed instead of adding it to the nonces: `b = hash(P, R1, R2, m, T)`
72+
But this has the downside of revealing to every participant in the multisig that an adaptor signature protocol is being executed
73+
For example, if there is a MuSig setup with three signers and only two of them are making use of adaptor signatures, then this option would require the third signer to know about the adaptor to compute `b`.
74+
75+
### Correctness
76+
```
77+
let
78+
# Alice sets up session
79+
(state, RA1, RA2) := setupSession()
80+
# Bob sets up session
81+
(_, RB1, RB2) := setupSession()
82+
# Alice may obtain RB1, RB2 before generating A
83+
(x, A) := KeyGen()
84+
(_, B) := KeyGen()
85+
# Alice creates a pre-signature for Bob
86+
pre_s := preSign_{x,state}((B, RB1, RB2), m, T)
87+
s := Adapt(pre_s, t)
88+
t' := Ext(s, pre_s)
89+
Verify_{B,RB1,RB2}((A, RA1, RA2), m, s):
90+
# MuSig2 partial sig verification. If passing, Bob can complete it to
91+
# a Schnorr signature.
92+
preVerify_{B,RB1,RB2}((A, RA1, RA2), m, 0, s):
93+
94+
then
95+
preVerify_{B,RB1,RB2}((A, RA1, RA2), m, T, pre_s) = true
96+
Verify_{B,RB1,RB2}((A,RA1+T,RA2), m, s) = true
97+
t'*G = T
98+
```
99+
100+
## Security
101+
102+
What follows are security definition and proof sketches for adaptor signatures following [Generalized Bitcoin-Compatible Channels](https://eprint.iacr.org/2020/476)
103+
They are not too different to the proof for Schnorr adaptor signatures in that publication, but does not require strong unforgeability of the underlying signature scheme
104+
The sketches are intended to test above definition of the scheme, give some intuition about what adaptor signatures tries to achieve and should give a bit more confidence as long as there exists no complete proof.
105+
106+
### aExistential Unforgeability under Chosen Message Attack
107+
108+
Loosely speaking, this means that an forger F shouldn't be able to forge a signature even after obtaining a pre-signature
109+
This is formalized with the following game:
110+
111+
```
112+
Q := empty
113+
(x, A) := KeyGen()
114+
(state, RA1, RA2) := setupSession()
115+
116+
(B, RB1, RB2, m) <- F(O_S, O_pS, A, RA1, RA2)
117+
t <-$ rand(), T := t*G
118+
pre_s := preSign_{x,state}((B, RB1, RB2), m, T)
119+
(RA1', RA2', s') <- F(O_S, O_pS, pre_s, T)
120+
return m notin Q
121+
and Verify_{B,RB1,RB2}((A, RA1', RA2'), m, s)
122+
```
123+
124+
where `F(O_S, O_pS, ...)` means running the forger with access to signing oracle `O_S` and `O_pS` and additional inputs
125+
`O_S` consists of two sub-oracles
126+
The first runs `setupSession()` and returns `R1` and `R2` to the caller and the second accepts an arbitrary nonces, public key and message and returns partial signature for the session that passes `Verify`
127+
Likewise, `O_pS` consists of a session-setup sub-oracle and a sub-oracle that returns a pre-signature for arbitrary nonces, public key, message and adaptor that passes `preVerify`
128+
Both `O_S` and `O_pS` insert `m` in `Q`.
129+
130+
Thus, the game starts by running the forger with the public key and generated public nonces until it provides a public key, nonces and message
131+
The game responds with a pre-signature on the message with a fresh adaptor and the forger wins if it produces a signature for a message that hasn't appeared in a (pre-)signature query.
132+
133+
We will now describe an algorithm that transforms a winner of the aEUF-CMA into a winner against a EUF-CMA for multisignatures (as defined in the MuSig2 paper) which is simplified for brevity
134+
This variant is restricted to two, and considers forgeries of _partial_ signatures, i.e
135+
signatures that pass `Verify` as defined above
136+
First we note that queries to the signing oracle `O_S` can be directly relayed to the EUF-CMA game (or so it seems, see below)
137+
In order to answer queries to the pre-signing oracle `O_pS` with nonces `(RB1, RB2)` we query the EUF-CMA signing oracle with `(RB1 + T, RB2)`.
138+
139+
Instead of running `KeyGen()` and `setupSession()` we obtain `A`, `RA1` and `RA2` from the MuSig2 EUF-CMA game.
140+
To produce a pre-signature on the forger's chosen message, we proceed in the same way as with answering `O_pS` queries.
141+
Crucially, if the forger succeeds in producing a signature, this does not constitute a forgery in the EUF-CMA game, because we've just used its signing oracle on the same message `m`.
142+
Therefore, we distinguish two cases:
143+
144+
1. `s' = Adapt(pre_s, t)`
145+
The attacker would have broken the hardness of the discrete logarithm of `T` which we assume to be hard.
146+
2. `s' != Adapt(pre_s, t)`.
147+
Then we have
148+
```
149+
let
150+
s := Adapt(pre_s, t)
151+
RA := RA1 + b*RA2
152+
RA' := RA1' + b'*RA2'
153+
(muA, P) := keyAgg(A, B)
154+
155+
s*G != pre_s*G
156+
<=>
157+
RA + T + hash(P, R, m)*muA*A != RA' + hash(P, R', m)*muA*A
158+
<=>
159+
RA + T != RA' or R != R'
160+
<=>
161+
R != R' (since absent collisions, RA + T != RA' => R != R')
162+
```
163+
We can use this fact in order to program the random oracle of the forger to ensure that from the point of view of the EUF-CMA game, `s'` is a forgery not on `m`, but on some `m' != m`
164+
Let's call the random oracle provided by the EUF-CMA game `hash^G` and define the random oracle provided to the forger for signature hash queries:
165+
```
166+
hash^F(P, R, m):
167+
if T[R, m] undefined:
168+
m' <-$ rand()
169+
M[R, m] := m'
170+
T[R, m] := hash^G(P, R, m')
171+
return T[R, m]
172+
```
173+
where `M` and `T` are tables that are initialized empty
174+
Thus, instead of relaying `O_S` and `O_pS` queries directly, we compute the combined `R`, query `hash^F(P, R, m)` to make sure that `m' = M[R,m]` is defined and pass the query to the EUF-CMA game after replacing `m` with `m'`.
175+
Similarly, in order to produce a pre-signature on the forgery message `m`, we replace it with `M[R,m]`.
176+
Then we have
177+
```
178+
s*G = RA + hash^F(P, R, m)A = RA + hash^G(P, R, M[P,R])*muA*A
179+
and
180+
pre_s*G = RA' + hash^F(P, R', m)A = RA + hash^G(P, R', M[P,R'])*muA*A
181+
```
182+
Since `R != R'` we have with overwhelming probability that `M[P,R] != M[P,R']` and therefore `s'` counts as a forgery in the EUF-CMA game.
183+
184+
### Pre-signature adaptability
185+
186+
This property captures that any pre-signature passing `preVerify` with adaptor `T = t*G` passes `Verify` after adapting with `t`
187+
In the case of MuSig2 adaptors this can be easily checked by applying the definitions of `preVerify`, `Adapt` and `Verify`.
188+
189+
### Witness extractability
190+
191+
This property holds if one can always extract a witness from a pre-signature and a signature passing `Verify`
192+
This is formalized as a game similar to the aEUF-CMA game, but here the forger returns also the adaptor `T` in its first execution
193+
The game creates a pre-signature `pre_s` and the forger wins if it produces a forgery `s'` and `Ext(s', pre_s)` does not return the adaptor secret `T`.
194+
195+
```
196+
Q := empty
197+
(x, A) := KeyGen()
198+
(state, RA1, RA2) := setupSession()
199+
200+
(B, RB1, RB2, m, T) <- F(O_S, O_pS, A, RA1, RA2)
201+
pre_s := preSign_{x,state}((B, RB1, RB2), m, T)
202+
(RA1', RA2', s') <- F(O_S, O_pS, pre_s)
203+
t' := Ext(s', pre_s)
204+
return m notin Q
205+
and t'*G != T
206+
and Verify_{B,RB1,RB2}((A, RA1', RA2'), m, s')
207+
```
208+
209+
The proof is almost identical to the proof or aEUF-CMA under the EUF-CMA of MuSig2 partial signatures.
210+
Again, we distinguish between `hash^G` and `hash^G` and relay signing and pre-signing queries to `O_S` and `O_pS` accordingly.
211+
Instead of generating the key and session state, we request `RA1` and `RA2` from the EUF-CMA signing oracle and run the forger.
212+
To pre-sign the forger's chosen message, we compute the sessions combined `R` and query the EUF-CMA signing oracle with `RB1 + T, RB2, M[R,m]`.
213+
Since `Ext(s', pre_s)*G != T` we have
214+
215+
```
216+
let
217+
RA := RA1 + b*RA2
218+
RA' := RA1' + b'*RA2'
219+
(muA, P) := keyAgg(A, B)
220+
221+
pre_s*G + T != s'*G
222+
<=>
223+
RA + T + hash(P, R, m)A != RA' + hash(P, R', m)A
224+
<=>
225+
RA + T != RA' or R != R'
226+
<=>
227+
R != R'
228+
```
229+
230+
Thus, `M[R,m] != M[R',m]` with overwhelming probability which means that from the point of view of the EUF-CMA game, the message in the signing query for `pre_s` is different to the forgery message and results in a win against the game.

0 commit comments

Comments
 (0)