Writing

Tulipa signaturianumleg. cstef, 3.xii.2024

Adaptor Signatures FtW

A simple and neat way to "lock" your Schnorr signatures, enabling atomic swaps and more!

6 min readcrypto

[!NOTE] I am not a cryptographer, nor a mathematician. This article is the result of my own research and understanding of the subject. If you find any mistakes, please let me know!

The vast majority of what is written here is taken from various sources, which are listed at the end of this article. I highly recommend you to read them if you want to dive deeper into the subject.

When we compute and share a Schnorr signature, anyone can directly verify if it is valid for the attached message and signer. But what if we wanted to defer revealing the full signature while already emitting it to other people? We can produce such a signature by encrypting the nonce it contains with an additional scalar 𝑦.

This scalar will be published β€œalong” with the signature in its public form π‘Œ=𝑦⋅𝐺. The basic signing process is the following:

  1. Sample the random nonce π‘ŸΜ‚β†π”½π‘ž, along with the locking scalar π‘¦β†π”½π‘ž
  2. Compute their public versions 𝑅̂=π‘ŸΜ‚β‹…πΊ and π‘Œ=𝑦⋅𝐺
  3. Compute the aggregated public nonce 𝑅=𝑅̂+π‘Œ.
  4. Hash the challenge 𝑒=𝐻(π‘…β€–π‘ƒβ€–π‘š) using the aggregated nonce 𝑅 and 𝑃=𝑝⋅𝐺, where 𝑝 is the private key of the signer.
  5. Compute and publish the (encrypted) locked signature 𝑠̂=π‘ŸΜ‚+𝑒𝑝

[!NOTE] You may notice that we’re never actually using 𝑦 in the signing process. This is a feature, not a bug! We can also generate this locked signature only knowing π‘Œ.

The final published data should be (𝑅,𝑠̂,π‘Œ) (along with the message π‘š of course).

Anyone with 𝑦 will now be able to get the β€œdecrypted” signature 𝑠, which is behind the locking point π‘Œ.

With π‘Ÿ=π‘ŸΜ‚+𝑦, we will define 𝑠 as follows:

𝑠=π‘Ÿ+𝑒𝑝=(π‘ŸΜ‚+𝑦)+𝑒𝑝=(π‘ŸΜ‚+𝑒𝑝)+𝑦=𝑠̂+𝑦

Likewise, if someone had both 𝑠 and 𝑠̂, they would also be able to recover 𝑦:

𝑠=𝑠̂+π‘¦βŸΊπ‘¦=π‘ βˆ’π‘ Μ‚

While 𝑠̂ isn’t a valid Schnorr signature by itself:

𝑒=𝐻(π‘…β€–π‘ƒβ€–π‘š)
𝑠̂⋅𝐺=?𝑅+𝑒𝑃=(𝑅̂+π‘Œ)+𝑒𝑃=(π‘ŸΜ‚+𝑦)⋅𝐺+𝑒𝑝⋅𝐺=(π‘ŸΜ‚+𝑦+𝑒𝑝)⋅𝐺=(π‘ŸΜ‚+𝑒𝑝)⋅𝐺+π‘Œ=𝑠̂⋅𝐺+π‘Œβ‰ π‘ Μ‚β‹…πΊ

We notice we can make the verification equation work if we add the public locking point π‘Œ:

𝑠̂⋅𝐺+π‘Œ=?𝑅+𝑒𝑃

While this doesn’t give us 𝑠, we can confirm that by adding 𝑦 to 𝑠̂, the resulting signature will be the one we’re expecting!

(𝑠̂+𝑦)⋅𝐺=?𝑅+𝑒𝑃=(𝑅+π‘Œ)+𝑒𝑃=(π‘Ÿ+𝑦)⋅𝐺+𝑒𝑝⋅𝐺=((π‘Ÿ+𝑒𝑝)+𝑦)⋅𝐺=(𝑠̂+𝑦)⋅𝐺 βœ“

Atomic Swaps

Exchanging cryptocurrencies between different blockchains is hard. Typically, you’d need a trusted third party to act as a middleman, which would obviously need to be compensated financially for his work. Doing things this way is costly and pretty inefficient. Instead, we can leverage Adaptor Signatures to ensure that either both parties get what they expected, either both get nothing.

We have Alice, holder of 1β™£οΈŽ, and Bob, holder of 1β™₯︎. They want to exchange both their balances, and we assume they already know each other’s addresses on both chains.

Alice starts by sampling π‘ŸΜ‚π΄,π‘¦β†π”½π‘ž, and computes an adaptor signature as usual, on a message π‘š that attests the transaction of her 1β™£οΈŽ to Bob’s address:

𝑅̂𝐴=π‘ŸΜ‚π΄β‹…πΊ, π‘Œ=𝑦⋅𝐺𝑅𝐴=𝑅̂𝐴+π‘Œπ‘’π΄=𝐻(π‘…π΄β€–π‘ƒπ΄β€–π‘š)𝑠̂𝐴=π‘ŸΜ‚π΄+𝑒𝐴𝑝𝐴

The BIP340 standard expects to receive a signature pair in the form (𝑂,𝜎), on which the following check is performed:

πœŽβ‹…πΊ=?𝑂+𝐻(π‘‚β€–π‘ƒβ€–π‘š)𝑃

If Bob was to try to give in 𝑂=𝑅̂𝐴 and 𝜎=𝑠̂𝐴:

𝑠̂𝐴⋅𝐺=?𝑅̂𝐴+𝐻(π‘…Μ‚π΄β€–π‘ƒπ΄β€–π‘š)𝑃𝐴≠𝑅̂𝐴+𝐻(π‘…π΄β€–π‘ƒπ΄β€–π‘š)π‘ƒπ΄βŸπ‘ Μ‚π΄β‹…πΊ

Or 𝑂=𝑅𝐴 and 𝜎=𝑠̂𝐴:

𝑠̂𝐴⋅𝐺=?𝑅𝐴+𝐻(π‘…π΄β€–π‘ƒπ΄β€–π‘š)𝑃𝐴≠𝑅̂𝐴+𝐻(π‘…π΄β€–π‘ƒπ΄β€–π‘š)π‘ƒπ΄βŸπ‘ Μ‚π΄β‹…πΊ

You could say that he cannot satisfy both the challenge 𝑒 and the nonce 𝑂. To do so, he needs to know 𝑦 to compute 𝑠𝐴=𝑠̂𝐴+𝑦 so that when he gives in 𝑂=𝑅𝐴 and 𝜎=𝑠𝐴:

(𝑠̂𝐴+𝑦)⋅𝐺=?𝑅𝐴+𝐻(π‘…π΄β€–π‘ƒπ΄β€–π‘š)𝑃𝐴=(π‘Ÿπ΄+𝑒𝐴𝑝𝐴)⋅𝐺=𝑠𝐴⋅𝐺 βœ“

Back to our stuff, when Bob receives the adaptor signature (𝑅,𝑠̂,π‘Œ) from Alice, after having carefully verified that the given data is correct, he can also generate his own adaptor signature 𝑠𝐡 on Alice’s 𝑦 by using π‘Œ:

π‘ŸΜ‚π΅β†π”½π‘žπ‘…π΅=π‘ŸΜ‚π΅β‹…πΊ+π‘Œπ‘ Μ‚π΅=π‘ŸΜ‚π΅+𝐻(π‘…π΅β€–π‘ƒπ΅β€–π‘š)𝑝𝐡

After he sends it to Alice, she can claim the transaction linked to the signature 𝑠̂𝐡 by unlocking it with her 𝑦 and publishing it to the blockchain. By doing so, everyone will be able to see the transaction and the associated decrypted signature 𝑠𝐡=𝑠̂𝐡+𝑦.

After this publication, Bob will also be able to compute 𝑦 and unlock Alice’s 𝑠̂𝐴:

𝑦=π‘ π΅βˆ’π‘ Μ‚π΅π‘ π΄=𝑠̂𝐴+𝑦

Nullifying Adaptor Signatures

In the previous case, we saw how two parties could jointly sign a transaction without the need for a trusted third party. But what if one of the parties wanted to cancel the transaction?

If Alice wants to cancel the transaction, she can simply discard her 𝑦 and never publish it. Bob will then be unable to unlock the signature 𝑠̂𝐴 and claim the transaction.

However, if Bob wants to cancel the transaction, how can Alice confirm that she will never publish 𝑠𝐡? There needs to be some sort of threat against Alice to ensure that she will not publish 𝑠𝐡.

Private Key Exposure Threat

By publishing her random nonce π‘ŸΜ‚π΄, Alice guarantees that she will never publish 𝑠𝐡. Otherwise, Bob will be able to recover 𝑦=π‘ π΅βˆ’π‘ Μ‚π΅ and thus compute Alice’s private key 𝑝𝐴:

𝑠𝐴=𝑠̂𝐴+𝑦=π‘ŸΜ‚π΄+𝑦+π‘’βŸknownβ‹…π‘π΄βŸΊπ‘π΄=π‘’βˆ’1(π‘ π΄βˆ’(π‘ŸΜ‚+𝑦))

Bob can also verify that the nonce π‘ŸΜ‚π΄ published by Alice is authentic:

𝑅𝐴=π‘ŸΜ‚π΄β‹…πΊ+π‘Œ

Secret Sharing + Adaptor Signatures = ?

One cool feature of π‘˜-of-𝑛 treshold schemes, such as Shamir’s Secret Sharing, is that they can be integrated into pretty much anything that has a secret in it. This includes Adaptor signatures locking scalars!

By defining our polynomial 𝑓(π‘₯) as follows:

𝑓(π‘₯)=𝑦+π‘Ž1π‘₯+π‘Ž2π‘₯2+…+π‘Žπ‘˜βˆ’1π‘₯π‘˜βˆ’1

We can split our locking scalar 𝑦 into 𝑛 shares 𝑦𝑖|1≀𝑖≀𝑛:

𝑦𝑖=𝑓(𝑖)

With π‘˜ shareholders forming the recovery group 𝑅, we can then collectively reconstruct 𝑦 with Lagrange interpolation (or any other similar interpolation method):

𝑦=𝑓(0)=βˆ‘π‘–βˆˆπ‘…π‘¦π‘–β‹…βˆπ‘—βˆˆπ‘…,𝑗≠𝑖0βˆ’π‘—π‘–βˆ’π‘—

And unlock the adaptor signature!

𝑠=𝑠̂+𝑦

References and Suggested readings

  • The Riddles of Adaptor Signatures
    conduition.io

  • Bitcoin Optech - Adaptor Signatures
    bitcoinops.org

  • Adaptor Signatures: New Security Definition and A Generic Construction for NP Relations⋆
    Xiangyu Liu, Ioannis Tzannetos, and Vassilis Zikas
    eprint.iacr.org [PDF]