PTLCs: The Standard(?)

One major advantage of PTLCs over HTLCs for atomic swaps is that there is no direct on-chain linkage of paired PTLCs. However, as with anything related to privacy, heuristics and correlation of metadata such as timing can link txs with high degree of confidence. The privacy of a single PTLC thus depends on the existence of other PTLCs; the greater the anonymity set the better.

Here are some ideas, used together, to get full advantage of PTLCs.
(For the sake of this discussion, we will assume that the increased plasma requirements are not a problem.)

  1. Externally, only use standard sends when the desired outcome is a public payment between two known addresses. Internally, only use standard sends for organizing funds between accounts that are already correlated.

  2. If seeking to create a new on-chain identity, when sending funds to a new address, always use a PTLC. This is only effective when other metadata is not correlated. Need to have wallet features to disable auto-receiving, and to help the user collect rewards at different times. Random pillar delegation selection. With a big enough anonymity set, this is much better than say sending to a Cex and withdrawing.

  3. When sending funds to other users, send PTLCs to each other. This is similar to Bitcoin’s concept of coinjoins. If you want to send a user 5 ZNN, instead create a PTLC sending them 10 ZNN, and they will create a PTLC sending you 5. These are actually more private than coinjoins because all ptlcs contribute to the anon set of all other ptlcs within a certain timespan.

  4. Add randomness by default to timing parameters to prevent correlation.

  5. Prefer disposable BIP340 point types even for ZTS-ZTS swaps, to increase the anonyminity set of cross chain swaps with btc.

  6. I might refactor the PTLC embedded to have an account model where PTLCs can be created and unlocked within the embedded contract without needing to withdraw to a zenon address. This can enable high plasma accounts to better take advantage of the proxy unlock feature and greatly increase the number of PTLCs for greater anonymity set.

4 Likes

how do you withdrawal / access the funds from the embedded if they stay there?

just add a deposit/withdrawal method

2 Likes

@georgezgeorgez can you explain the PTLCs over here? Thank you!

In terms of understanding the work.
A single PTLC is relatively straightforward and I’ve the design and relevant decisions here.

Once that is understood, we can dive into ecc.

3 Likes

I’m ready to dive into ECC theory now.

2 Likes

watch these first

3 Likes

As with the HTLCs, I wanted to create a tutorial for PTLCs. But as I started to understand it better, it wasn’t that easy to implement directly it in CLI.

PTLCs require much more coordination between both parties, a trusted party is needed to facilitate the communication. To avoid making the entire project too complex, I created a demo instead.

It demonstrates a single chain atomic swap using PTLCs on the Zenon Network. The repository has a sequence diagram showing all the steps involved. Following the instructions one can execute it running a local devnet with PTLC support.

It’s a first working example written in Go. More research is needed to add other and alternative use cases to the repo. Such as a cross chain atomic swap between znn and btc for example.

I hope this helps the community understand PTLCs better and that it helps us getting a step closer to successfully implement PTLCs on NoM.

6 Likes

Brilliant!
IIRC, you were the first to start understanding and building off of HTLCs as well.
As you noted, collaborative PTLC constructions are a bit more involved.
Figuring out how to make this available to users will require some thought.

3 Likes

Great work sir!!

For anyone looking to test this out, these are the instructions I followed:

  1. Setup devnet on linux
  2. Run the ptlc test

Here is the expected output

App: Start
Bob: Start
Alice: Start
Bob: Hello from Alice
Bob: Receive wallet addressA
Alice: Hello from Bob
Alice: Send wallet addressA
Alice: Receive wallet addressB
Bob: Send wallet addressB
Alice: Generate key pair (a1, A1), (a2, A2), (ra, Ra) and (t, T)
Bob: Generate key pair (b1, B1), (b2, B2) and (rb, Rb)
Bob: Receive public key (A1, A2, Ra, T)
Alice: Send public key (A1, A2, Ra, T)
Bob: Send public key (B1, B2, Rb)
Alice: Receive public key (B1, B2, Rb)
Alice: Create joint public key (A1 + B1), (A2 + B2), (Ra + T) and (Rb + T)
Alice: Create PTLC1: send funds, expiration and public key (A2 + B2) as Ed25519 point lock
Bob: Create joint public key (A1 + B1), (A2 + B2), (Ra + T) and (Rb + T)
Bob: Receive PTLC1 id
Alice: Wait 2 momentums
Alice: Send ptlc1 id
Alice: Receive ptlc2 id
Bob: Verify PTLC1 funds, expiration and public key
Bob: Create PTLC2: send funds, expiration and public key (A1 + B1) as Ed25519 point lock
Bob: Wait 2 momentums
Bob: Send PTLC2 id
Bob: Create message msgA: SHA3(PTLC2 id + addressA)
Bob: Create message msgB: SHA3(PTLC1 id + addressB)
Bob: Receive challenge (c1 * a1) and (c2 * a2)
Alice: Create message msgA: SHA3(PTLC2 id + addressA)
Alice: Create message msgB: SHA3(PTLC1 id + addressB)
Alice: Generate challenge (c1 = SHA512((Rb + T) || (A1 + B1) || msgA))
Alice: Generate challenge (c2 = SHA512((Ra + T) || (A2 + B2) || msgB))
Alice: Send challenge (c1 * a1) and (c2 * a2)
Bob: Receive challenge (c1 * a1) and (c2 * a2)
Bob: Generate challenge (c1 = SHA512((Rb + T) || (A1 + B1) || msgA))
Bob: Generate challenge (c2 = SHA512((Ra + T) || (A2 + B2) || msgB))
Alice: Receive challenge ((c2a2 + c2) * b2)
Bob: Send challenge ((c2a2 + c2) * b2)
Bob: Receive adapter signature (s_adapt_b = (ra + c2a2b2))
Alice: Send adaptor signature (s_adapt_b = (ra + c2a2b2))
Alice: Receive adaptor signature (s_adapt_a = (rb + c1a1b1))
Bob: Verify adapter signature (s_adapt_b * G == (c2 * (A2 + B2) + Ra))
Bob: Send adaptor signature (s_adapt_a = (rb + c1a1b1))
Bob: Receive signature (sa)
Alice: Create signature (sa = s_adapt_a + t)
Alice: Verify signature (sa * G == c1 * (A1 + B1) + Rb + T)
Alice: Create ed25519 signature (sa64 = bytes64(Rb + T, sa))
Alice: Unlock PTLC2 with signature (sa64)
Alice: Wait 2 momentums
Alice: End
Bob: Extract (t = sa - s_adapt_a)
Bob: Create signature (sb = s_adapt_b + t)
Bob: Verify signature (sb * G == c2 * (A2 + B2) + Ra + T)
Bob: Create ed25519 signature (sb64 = bytes64(Ra + T, sb))
Bob: Unlock PTLC1 with signature (sb64)
Bob: Wait 2 momentums
Bob: End
App: End
3 Likes