Skip to content

Schnorr Adaptor Signature

Table of contents

Open Table of contents

What it is

An adaptor signature is a modified signature that only verifies if it’s updated by applying a secret value. Once the signature is updated, the verification succeeds which also results in the secret value being publicly visible.

Adaptor signatures are oftentimes used in Blockchain protocols to implement ”Scriptless Scripts” which are rules that can solely be implemented and enforced with digital signatures.

One such implementation is an atomic swap in which two parties who don’t trust each other want to exchange pre-determined values of currency with one another.

We’ll be using the example of an atomic swap throughout this post to explain how adaptor signatures work. However it’s important to note that atomic swaps are just one implementation in which adaptor signatures can be used. Adaptor signatures are a generic construction which can be used to solve problems outside the Cryptocurrency realm.

Before diving straight into specifics we should briefly talk about the problem we’re trying to solve with adaptor signatures.

In our case we have two actors, Alice and Bob. Both want to transact with each other and both have agreed on the amount of currency they want to exchange. The problem is that Alice only wants to pay Bob the agreed amount if she knows for sure that Bob pays her the correct amount.

While this problem could be solved via a trusted third party (an escrow) that custodies the funds and ensures that both parties transfer the agreed on amount to each other, we can use adaptor signatures to sign transactions that enforce this contractual agreement without any dependency on a trusted entity.

How it works

Given that this post describes adaptor signatures based on Schnorr Signatures, it’s useful to have a basic understanding of those before continuing.

We’ll be working with an Elliptic Curve EE that is of order qq and has a generator GG. All calculations are done mod q\bmod\ q if not stated otherwise.

Note: If not stated otherwise, we’ll be using the subscript 1_1 for parameters generated by Alice and the subscript 2_2 for parameters generated by Bob.

Setup

The first step is the same as with a regular Schnorr Signature. Alice and Bob both generate their private keys aa and bb by sampling a random value from Zq\mathbb{Z}_q. Next up, they compute their public keys by multiplying their private keys with the generator GG.

a$Zqa \overset{{\scriptscriptstyle\$}}{\leftarrow} \mathbb{Z}_q A=aGA = aG B$ZqB \overset{{\scriptscriptstyle\$}}{\leftarrow} \mathbb{Z}_q B=bGB = bG

In addition to that, Alice and Bob both separately generate their random secret nonce value r1r_1 and r2r_2 as well as its public derivative R1R_1 and R2R_2:

r1$Zqr_1 \overset{{\scriptscriptstyle\$}}{\leftarrow} \mathbb{Z}_q R1=r1GR_1 = r_1G r2$Zqr_2 \overset{{\scriptscriptstyle\$}}{\leftarrow} \mathbb{Z}_q R2=r2GR_2 = r_2G

Both then share their public keys AA and BB as well as their public values R1R_1 and R2R_2 with each other.

Adaptor Generation (Alice)

In this example, Alice goes first and wants to send Bob a signature over a transaction m1m_1 that shows him, that Alice will transfer the correct amount of currency to him.

Remember that in a regular Schnorr Signature Alice would commit to her nonce R1R_1, her public key AA and the transaction m1m_1 by computing c1=H(R1Am1)c_1 = H(R_1 \mathbin\Vert A \mathbin\Vert m_1). She’d then calculate s1=r1+c1as_1 = r_1 + c_1a which results in the signature tuple (s1,R1)(s_1, R_1).

The problem is that this is already a valid signature which won’t just show Bob that he gets paid but will pay him if broadcasted given that s1G=?R1+c1As_1G \overset{?}{=} R_1 + c_1A is true:

s1G=R1+c1A(r1+c1a)G=R1+c1aG=R1+c1A=\begin{aligned} s_1G &= R_1 + c_1A \\ (r_1 + c_1a)G &= \\ R_1 + c_1aG &= \\ R_1 + c_1A &= \end{aligned}

Is there a way Alice can modify the signature such that it still shows Bob that he gets paid but doesn’t allow him to simply broadcast it to get paid immediately?

As it turns out, there’s a way to modify the signature such that the intent (Alice pays Bob amount XX) is preserved and visible while requiring a secret value to turn the modified signature into one that verifies successfully (and therefore pays Bob).

To do so, Alice generates a secret value tt by randomly sampling a value from Zq\mathbb{Z}_q. She also derives it’s public value TT by multiplying tt with the generator GG.

t$Zqt \overset{{\scriptscriptstyle\$}}{\leftarrow} \mathbb{Z}_q T=tGT = tG

One can think of this as just another key pair that Alice generates. Given that tt will be used as another private key, she also keeps that value to herself and doesn’t share it with Bob.

Next up, Alice follows the Schnorr Signature protocol and generates c1c_1 and s1s_1'. However she deviates slightly from the protocol by adding tt to r1r_1 and TT to R1R_1 respectively.

c1=H(R1+TAm1)c_1 = H(R_1 + T \mathbin\Vert A \mathbin\Vert m_1) s1=r1+t+c1as_1' = r_1 + t + c_1a

She also calculates s1s_1 which removes the secret value tt from s1s_1':

s1=s1t=r1+t+c1at=r1+c1a\begin{aligned} s_1 &= s_1' - t \\ &= r_1 + \cancel{t} + c_1a - \cancel{t} \\ &= r_1 + c_1a \end{aligned}

Note that given this modification, a valid signature tuple would be (s1+t,R1+T)(s_1 + t, R_1 + T).

Alice now shares s1s_1 and TT with Bob.

Adaptor Verification

Upon receiving s1s_1 and TT Bob can check that Alice generated a modified signature that will pay him.

To do so he calculates c1=H(R1+TAm1)c_1 = H(R_1 + T \mathbin\Vert A \mathbin\Vert m_1) and checks s1G=?R1+c1As_1G \overset{?}{=} R_1 + c_1A:

s1G=R1+c1A(r1+c1a)G=R1+c1aG=R1+c1A=\begin{aligned} s_1G &= R_1 + c_1A \\ (r_1 + c_1a)G &= \\ R_1 + c_1aG &= \\ R_1 + c_1A &= \end{aligned}

Adaptor Generation (Bob)

Note that while Bob can verify that the adapted signature he received from Alice is correct, he can’t publish it to get paid as the s1s_1 value he got from Alice doesn’t include her secret value tt which is necessary to turn the adapted signature into a valid one (tt is necessary because Alice committed to both R1R_1 and TT in c1c_1 by calculating R1+TR_1 + T. More on that later).

Given that Bob has access to the public value TT that is linked to the secret tt that only Alice knows, he can create another, adapted signature with the help of TT over a transaction m2m_2 that pays Alice.

To do so, Bob calculates c2c_2 and s2s_2:

c2=H(R2+TBm2)c_2 = H(R_2 + T \mathbin\Vert B \mathbin\Vert m_2) s2=r2+c2bs_2 = r_2 + c_2b

Bob then sends s2s_2 to Alice.

Signature Generation (Alice)

For Alice to get paid, she now needs to use Bob’s adapted signature and her secret value tt to turn it into a signature that ensures that (s2+t)G=?R2+T+c2B(s_2 + t)G \overset{?}{=} R_2 + T + c_2B.

(s2+t)G=R2+T+c2B(r2+c2b+t)G=R2+c2bG+tG=R2+c2B+T=R2+T+c2B=\begin{aligned} (s_2 + t)G &= R_2 + T + c_2B \\ (r_2 + c_2b + t)G &= \\ R_2 + c_2bG + tG &= \\ R_2 + c_2B + T &= \\ R_2 + T + c_2B &= \end{aligned}

Once the signature is validated on-chain Bob can learn tt.

Signature Generation (Bob)

By observing the Blockchain and therefore learning Alice’s published signature s2+ts_2 + t that pays her, Bob can extract the secret value tt by calculating t=(s2+t)s2t = (\cancel{s_2} + t) - \cancel{s_2}.

Equipped with the value tt, Bob can now update the adapted signature he got from Alice to turn it into one that verifies by doing the same Alice did:

(s1+t)G=R1+T+c1A(r1+c1a+t)G=R1+c1aG+tG=R1+c1A+T=R1+T+c1A=\begin{aligned} (s_1 + t)G &= R_1 + T + c_1A \\ (r_1 + c_1a + t)G &= \\ R_1 + c_1aG + tG &= \\ R_1 + c_1A + T &= \\ R_1 + T + c_1A &= \end{aligned}

That way Bob get’s paid by Alice as well.

Schnorr Adaptor Signature

Why it works

The key ingredient that turns a regular Schnorr Signature into an adaptor signature is the usage of the secret tt and its public value TT in the calculation of cc and ss.

To see the difference, let’s quickly recap how a regular Schnorr Signature works.

Given a secret key xx with its corresponding public key XX, a random nonce rr with its corresponding value RR and a message mm we can generate a signature by calculating cc and ss as follows:

c=H(RXm)c = H(R \mathbin\Vert X \mathbin\Vert m) s=r+cxs = r + cx

Verification is done by checking if sG=?R+cXsG \overset{?}{=} R + cX:

sG=R+cX(r+cx)G=R+cxG=R+cX=\begin{aligned} sG &= R + cX \\ (r + cx)G &= \\ R + cxG &= \\ R + cX &= \end{aligned}

To turn a regular Schnorr Signature into an adaptor signature one needs to include the secret tt and its public value TT in a way that the signature is only valid if both values are known.

To do so, the calculation of cc is updated to add TT to RR:

c=H(R+TXm)c = H(R + T \mathbin\Vert X \mathbin\Vert m)

Trying to verify the signature as before would fail because we haven’t used the secret value tt yet:

sG=?R+T+cX(r+cx)G=?R+cxG=?R+cX\begin{aligned} sG &\overset{?}{=} R + T + cX \\ (r + cx)G &\overset{?}{=} \\ R + cxG &\overset{?}{=} \\ R + cX &\ne \end{aligned}

However by knowing tt we can add it to ss to ensure that the signature verification succeeds:

(s+t)G=R+T+cX(r+cx+t)G=R+cxG+tG=R+cX+T=R+T+cX=\begin{aligned} (s + t)G &= R + T + cX \\ (r + cx + t)G &= \\ R + cxG + tG &= \\ R + cX + T &= \\ R + T + cX &= \end{aligned}

References

The following resources have been invaluable for me to learn the concepts discussed in this article.

You should definitely give them a read if you want to dive deeper into the topic.