Skip to content

Instantly share code, notes, and snippets.

@NicolasDorier
Last active September 1, 2020 01:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NicolasDorier/2d585db8e8561c66fa928b4b99a8cad1 to your computer and use it in GitHub Desktop.
Save NicolasDorier/2d585db8e8561c66fa928b4b99a8cad1 to your computer and use it in GitHub Desktop.
Adaptor signatures

All started with a wish to make a bet over Trump victory. Most betting website would not work for me. Some betting website are using chain analysis, which is an instant no for me. Others are asking for KYC. Other only works with wire transfer or cards (both I can't use easily outside of Japan).

Anyway @Chris_Stewart_5, accepted. The odd were 0.4/0.6 in Biden favor, so he proposed me a bet: 0.4 BTC to him if Biden win and 0.6 BTC to me if Trump win. The caveat? Need to be a DLC. Challenge accepted. We will reevaluate the odds with the one of the market when we make the bet. (I think Trump's odds have increased by now)

So first, I wanted to use Crypto Garage tools for DLC. There is several problem yet:

  1. This is still a proof of concept,
  2. Their tool is meant to bet on prices rather than events
  3. Their coordinator and Oracle are the same entity, and is for now only on testnet, and the work to decouple them is still ongoing.

Then I checked suredbit's Bitcoin-S tool. Problems are:

  1. It relies on their own Bitcoin-S wallet
  2. The wallet expect a node that is unpruned and support client side filtering at P2P level.

Now I don't like this, because I don't have any unpruned node, and nor does 99% of BTCPayServer users. And I don't like running non Core nodes.

So I decided instead that I will do my own tool. Suredbits have documented their protocol, and with the help of the Bitcoin-S source code, I discovered several cryptographic primitives were needed for implementing DLC:

  • Adaptor Signatures
  • Some bits of BIP340 Schnorr sigs

NBitcoin.Secp256k1 is a C# port of secp256k1, this make it easy for me to monkey port code from the crypto wizards. As long as their code is using secp256k1 and have tests, I can monkey port.

Having done my monkey port, all tests green, came the time for me to understand how does those things connect with my Bet on Trump.

Adaptor signature sounds cool, but I had no idea if it tastes like a sushi or like a potato. Some quick google search bring me explanations, but most of those explanations came from crypto wizards for crypto wizards and made no sense to me.

Every sentence from those crypto wizards, I had questions like "What the fuck do they mean by the Point of the Signature?". I am a developer, and I don't understand math. The first link that really helped for me to understand was from Ruben Somsen https://twitter.com/SomsenRuben/status/1299349955597959168?s=20 But this is because I worked on atomic swap scheme based on hash locks, so how he explained made lot's of sense to me. I finally understood "Why adaptor signatures".

But, if you, dear reader don't understand what it is about, fear not let me try to explain. Lot's of applications (lightning network, atomic swap) on top of bitcoin are built on the concept of "locks".

Locking schemes

By "Lock" we mean "You can't move money unless something has been revealed". There is several way to do this.

If Alice and Bob wanted to swap two coins on two different chain (or just same chain for privacy via a coin swap), how that would work? Let's say Alice has BTC and Bob has LTC and they want to swap them without trusting each other.

Point locks

For cryptographers in Bitcoin, the terms "Points" and "Pubkey" are interchangeable, if some sentences confuse you, just replace "point" by "pubkey". The simplest of all locks is widespread "point locks". If Alice owns a coin of 1 BTC, Bob can't move the money until either Alice reveals him her private key, or a signature.

Alice, already owning 1 BTC, has her own point lock: If Bob knows her private key or know a signature of a specific message, he can take the money. Imagine if Bob could create a lock on 10 LTC, where the condition are "Reveal the private key or the signature for the 1 BTC to get the LTC". Alice could take the LTC right away. But by doing so, she reveal the private key or the signature that Bob can use to get the 1 BTC. The coins just swapped hands.

I don't want to cover the blockchain specific attack vectors like Alice taking the BTC out before Bob could take them, or what happen if Alice is unresponsive. While important implementation details, the subject of this post is about locks.

The problem in the scenario above the that there is no way to create such lock for Bob:

  1. There is no script construction in Bitcoin to do this kind of lock. (this might happen later though)
  2. Even if it existed, such script would stand out, which is bad for privacy

Hash locks

But there is a trick! We can solve the previous issue. Another type of lock is "hash locks". If Alice use a hash lock for her 1 BTC, Bob can't move the money until Alice reveals a specific secret.

We use hashes for this. Alice creates a hash lock with H=Hash(RandomStuff). Now Bob can use the same lock H to secure the LTC.

Bob uses the same "hash lock" on his 10 LTC. Alice can open Bob's lock for the 10 LTC, only by revealing RandomStuff. If she does, then Bob will see RandomStuff and use it to open the hash lock of Alice.

Hash locks are used internally by the Lightning network.

Remaining problem is:

  1. Because the same hash lock is used for the 1 BTC and for the 10 LTC, this is bad for privacy, as anybody looking the blockchain can clearly see the swap.

Point locks revisited

Remember: The problem of point locks was that there is no way for Bob to construct script which obliges Alice to reveal her private key or a signature to open her point lock.

OK now imagine if there was a way to reveal a secret at the same time of making a signature! No need of special bitcoin script.

Alice use a normal "point lock" on her 1 BTC. Bob also use a normal "point lock" on his 10 LTC. And Bob gives some information to Alice so she can open his locks. BUT there is a caveat: If Alice uses this information, the signature to open the lock of Bob will also reveal to Bob her own private key.

Then Bob can see her private key and open her lock to take the money.

Adaptor signatures

Adaptor signatures are the magic sauce to create those point locks!

Bob knows the pubkey of Alice and he knows what message need to be signed to open his own 10 LTC "point lock": Combining AliceLock.PubKey + BobLock.PrivateKey + BobLock.MessageToSignToOpen gives him Adaptor signature + Adaptor proof

Alice makes sure the Adaptor signature and Adaptor proof are signing BobLock.MessageToSignToOpen. With Adaptor signature + Adaptor proof + BobLock.MessageToSignToOpen in hands, she can be sure of it!

Now she can take the 10 LTC!

Alice: Adaptor signature + AliceLock.PrivateKey => BobLock.Signature

But remember! By using the signature for BobLock, Alice also reveals her own private key!

Bob: BobLock.Signature => AliceLock.PrivateKey

That's neat isn't it? In other words, Bob produced an "Adaptor signature" for his locks with Alice key. Alice can "decrypt" this "Adaptor signature" to a signature which will open Bob's lock, BUT this signature will also revealing her own private key.

DLC with adaptor signatures

** Tape rewind sounds ** so I want to make a bet over Trump victory with @Chris_Stewart_5. I don't trust him (actually I do, but he does not trust me!), but we trust an oracle to give us the result. The oracle just does not want us to bother him. He wants to broadcast the result on twitter and don't even want to know that we use his announcement to unlock money.

The oracle, in their infinite wisdom told us:

Shall Trump wins, I shall reveal the private key of "1bd3f7..."
Shall he loses, I shall reveal the private key of "cbaede..."

So Chris and me decide to send our collateral (0.4 BTC for me, 0.6 BTC for him) to a 2-2 multisig address. (we create the "funding transaction") But before signing and broadcasting, we make sure first that we can get our money if the oracle is honest.

So we can create two transactions spending the 1 BTC of the funding, each representing one of the two possible outcomes: (Those transactions are called "Contract Execution Transaction" or CET)

  • If Trump win, I should get all the money.
  • If Trump lose, Chris should get all the money.

But we can't just sign those two CET transactions with valid signatures! If we did, Chris could just take the money without the oracle permission.

So instead we create adaptor signatures. Those adaptor signatures can be considered as an "encrypted" signature, that we can open with oracle's outcome's private keys.

  • All the signatures we create for the first outcome (Trump wins) are using "1bd3f7..." as the adaptor's key.
  • All the signatures we create for the second outcome (Trump loses) are using "cbaede..." as the adaptor's key.

Now both of us are sure we can't cheat each other, we can broadcast our funding transaction on the network, and wait for the oracle's key to decrypt the outcome of our bet! And so do you, if another want to take a bet with you.

** Note I took several simplification of how actual DLC works to focus on the adaptor signature part rather than on the protocol.

Conclusion

An adaptor signature can be seen as an encrypted signature, whose decrypted version also reveals the decryption key to those who knows the adaptor signature. Another way of thinking about it from Somsen Ruben "An adaptor signature is like an incomplete signature which when completed reveals a secret to those knowing the incomplete signature".

In the case of atomic swap this is useful: When one party take coin A, the party also reveal a secret for the other party to take coin B.

In case of DLC, we can create a chain of unbroadcasted transaction which will become suddenly valid only when the oracle gives us the key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment