Confidential assets on Aptos

 

tl;dr: Confidential assets are in town! But first, a moment of silence for veiled coins.

$ $

$ % % Field operations % % #1 is the number of field additions \def\Fadd#1{#1\ \green{\F^+}} % #1 is the number of field multiplications \def\Fmul#1{#1\ \red{\F}^\red{\times}} % % Abstract group % % #1 is the group % #2 is the # of group additions \def\Gadd#1#2{#2\ \green{#1}^\green{+}} % #2 is the # of scalar muls \def\Gmul#1#2{#2\ \orange{#1}^\orange{\times}} % #2 is the MSM size \def\msm#1#2{\red{#1}^{#2}} % do not use directly use either \fmsm or \vmsm \def\vmsm#1#2{\red{\mathsf{var}}\text{-}\msm{#1}{#2}} \def\fmsm#1#2{\msm{#1}{#2}} \def\fmsmSmall#1#2#3{\fmsm{#1}{#2}/{#3}} % ...#3 is the max scalar size \def\vmsmSmall#1#2#3{\vmsm{#1}{#2}/{#3}} % % \mathbb{G} group % \def\GaddG#1{\Gadd{\Gr}{#1}} \def\GmulG#1{\Gmul{\Gr}{#1}} \def\msmG#1{\msm{\Gr}{#1}} \def\vmsmG#1{\vmsm{\Gr}{#1}} \def\fmsmG#1{\fmsm{\Gr}{#1}} \def\fmsmGSmall#1#2{\fmsmSmall{\Gr}{#1}/{#2}} \def\vmsmGSmall#1#2{\vmsmSmall{\Gr}{#1}/{#2}} % % G_1 group % % Note: replicating the colors here because cannot get subscript to align with superscript (e.g., $\msmOne{n}$ would render akwardly) \def\GaddOne#1{\Gadd{\Gr}{#1}_\green{1}} \def\GmulOne#1{\Gmul{\Gr}{#1}_\orange{1}} \def\msmOne#1{\msm{\Gr}{#1}_\red{1}} \def\vmsmOne#1{\vmsm{\Gr}{#1}_\red{1}} \def\fmsmOne#1{\fmsm{\Gr}{#1}_\red{1}} \def\fmsmOneSmall#1#2{\fmsmSmall{\Gr}{#1}_\red{1}/{#2}} \def\vmsmOneSmall#1#2{\vmsmSmall{\Gr}{#1}_\red{1}/{#2}} % % G_2 group % % Note: same replication as for G_1 \def\GaddTwo#1{\Gadd{\Gr}{#1}_\green{2}} \def\GmulTwo#1{\Gmul{\Gr}{#1}_\orange{2}} \def\msmTwo#1{\msm{\Gr}{#1}_\red{2}} \def\vmsmTwo#1{\vmsm{\Gr}{#1}_\red{2}} \def\fmsmTwo#1{\fmsm{\Gr}{#1}_\red{2}} \def\fmsmTwoSmall#1#2{\fmsmSmall{\Gr}{#1}_\red{2}/{#2}} \def\vmsmTwoSmall#1#2{\vmsmSmall{\Gr}{#1}_\red{2}/{#2}} % % Target group % % Note: same replication as for G_1 \def\GaddTarget#1{\Gadd{\Gr}{#1}_\green{T}} \def\GmulTarget#1{\Gmul{\Gr}{#1}_\orange{T}} \def\msmTarget#1{\msm{\Gr}{#1}_\red{T}} \def\vmsmTarget#1{\vmsm{\Gr}{#1}_\red{T}} \def\fmsmTarget#1{\fmsm{\Gr}{#1}_\red{T}} \def\fmsmTargetSmall#1#2{\fmsmSmall{\Gr}{#1}_\red{T}/{#2}} \def\vmsmTargetSmall#1#2{\vmsmSmall{\Gr}{#1}_\red{T}/{#2}} % % A single pairing \def\pairing{\mathbb{P}} % #1 is the # of pairings \def\multipair#1{\mathbb{P}^{#1}} $

Notation

  • For time complexities, we use:
    • $\Fadd{n}$ for $n$ field additions in $\F$
    • $\Fmul{n}$ for $n$ field multiplications in $\F$

    • $\Gadd{\Gr}{n}$ for $n$ additions in $\Gr$
    • $\Gmul{\Gr}{n}$ for $n$ individual scalar multiplications in $\Gr$
    • $\fmsm{\Gr}{n}$ for a size-$n$ MSM in $\Gr$ where the group element bases are known ahead of time (i.e., fixed-base)
      • when the scalars are always from a set $S$, then we use $\fmsmSmall{\Gr}{n}{S}$
    • $\vmsm{\Gr}{n}$ for a size-$n$ MSM in $\Gr$ where the group element bases are not known ahead of time (i.e., variable-base)
      • when the scalars are always from a set $S$, then we use $\vmsmSmall{\Gr}{n}{S}$

Preliminaries

We assume familiarity with:

Baby-step giant step (BSGS) discrete log algorithm

Naively, computing the discrete log $a$ on $a \cdot G$, when $a\in[2^\ell)$ could be done in constant-time via a single lookup in a $2^\ell$-sized pre-computed table.

The BSGS algorithm allows for reducing the table size to $\sqrt{2^\ell} = 2^{\ell/2}$ while increasing the time to $\GaddG{2^{\ell/2}}$.

Explain the algorithm.

FAQ

Why not go for a general-purpose zkSNARK-based design?

Question: Why did Aptos go for a special-purpose design based on the Bulletproofs ZK range proof and $\Sigma$-protocols, rather than a design based on a general-purpose zkSNARK (e.g., Groth16, PLONK, or even Bulletproofs itself)?

Short answer: Our special-purpose design best addresses the tension between efficiency and security.

Long answer: General-purpose zkSNARKs are not a panacea:

  1. They remain slow when computing proofs
    • This makes it slow to transact confidentially on your browser or phone.
  2. They may require complicated multi-party computation (MPC) setup ceremonies to bootstrap securely
    • This makes it difficult and risky to upgrade confidential assets if there are bugs discovered, or new features are desired
  3. Implementing any functionality, including confidential assets, as a general-purpose “ZK circuit” is a dangerous minefield (e.g., circom)
    • It is very difficult to do both correctly & efficiently2
    • To make matters worse, getting it wrong means user funds would be stolen.

Still, general-purpose zkSNARK approaches, if done right, do have advantages:

  1. Smaller TXN sizes
  2. Cheaper verification costs.

So why opt for a special-purpose design like ours?

Because we can nonetheless achieve competitively-small TXN sizes and cheap verification, while also ensuring:

  1. Computing proofs is fast
    • This makes it easy to transact on the browser, phone or even on a hardware wallet
  2. There is no MPC setup ceremony required
    • This makes upgrades easily possible
  3. The implementation is much easier to get right
    • We can sleep well at night knowing our users’ funds are safe

Construction

Chunk sizes

We chose 16-bit chunks to ensure that the max pending balance chunks never exceed $2^{32}$ after around $2^{16}$ incoming transfers. This, in turn, ensures fast decryption times.

Why so many incoming transfers? There could be use cases, such as payment processors, where seamlessly receiving many transfers is necessary.

Resources

Appendix

BL DL benchmarks for Ristretto255

These were run on a Macbook M3.

Chunk size Algorithm Lowest time Average time Highest time
16-bit Bernstein-Lange3 1.67 ms 2.01 ms 2.96 ms
32-bit Bernstein-Lange3 7.38 ms 30.86 ms 77.00 ms
48-bit Bernstein-Lange3 0.72 s 4.03 s 12.78 s

Something is off here: BL should be much faster than BSGS. e.g., on 32 bit values, BL takes $30.86$ ms on average, while BSGS similarly takes $2^{16}$ group operations $\Rightarrow$ 0.5 microseconds $\times 2^{16} \approx 32$ ms.

There is a long line of work on confidential asset-like protocols, both in Bitcoin’s UTXO model, and in Ethereum’s account model. Our work builds-and-improves upon these works:

References

For cited works, see below 👇👇

  1. Bulletproofs: Short Proofs for Confidential Transactions and More, by B. Bünz and J. Bootle and D. Boneh and A. Poelstra and P. Wuille and G. Maxwell, in 2018 IEEE Symposium on Security and Privacy (SP), 2018 

  2. Writing efficient and secure ZK circuits is extremely difficult. I quote from a recent survey paper7 on implementing general-purpose zkSNARK-based systems: “We find that developers seem to struggle in correctly implementing arithmetic circuits that are free of vulnerabilities, especially due to most tools exposing a low-level programming interface that can easily lead to misuse without extensive domain knowledge in cryptography.” 

  3. Computing small discrete logarithms faster, by Daniel Bernstein and Tanja Lange, 2012, [URL]  2 3

  4. Confidential transactions, by Gregory Maxwell, 2015, [URL] 

  5. Zether: Towards Privacy in a Smart Contract World, by Bünz, Benedikt and Agrawal, Shashank and Zamani, Mahdi and Boneh, Dan, in Financial Cryptography and Data Security, 2020 

  6. PGC: Pretty Good Decentralized Confidential Payment System with Auditability, by Yu Chen and Xuecheng Ma and Cong Tang and Man Ho Au, in Cryptology ePrint Archive, Report 2019/319, 2019, [URL] 

  7. SoK: What don’t we know? Understanding Security Vulnerabilities in SNARKs, by Stefanos Chaliasos and Jens Ernstberger and David Theodore and David Wong and Mohammad Jahanara and Benjamin Livshits, 2024