Skip to main content

Implementation Details

Transparent assets to anonymous assets (AR-to-ABAR)

A zero-knowledge proof is generated, as follows, to provide that the anonymous assets are correct.

  • We assume that the verifier has already checked that 0x<2640\leq x< 2^{64}.
  • Instance:

    • AR amount xx
    • AR asset code yy
    • the commitment of ABAR cc
  • Witness:

    • the blinding factor in the commitment bb
    • the public key of the recipient kk
  • Statement:

    • Check c:=Rescue(Rescue(b,x,y,0),k,0,0)c:=\mathsf{Rescue}(\mathsf{Rescue}(b, x, y, 0), k, 0, 0).

Anonymous assets to transparent assets (ABAR-to-AR)

  • We assume that the verifier has already checked that 0x<2640\leq x< 2^{64}.

  • Instance:

    • the nullifier nn
    • the Merkle tree root rr
    • AR amount xx
    • AR asset code yy
    • transaction body hash hh
    • non-malleability tag tt
  • Witness:

    • the blinding factor in the commitment bb
    • the secret key of the owner ss
    • Merkle tree path mm
    • non-malleability randomizer zz
  • Statement:

    • Let the reconstructed public key be k:=sGk := sG, where GG is the generator for the signature scheme.
    • Let the reconstructed commitment be c:=Rescue(Rescue(b,x,y,0),k,0,0)c := \mathsf{Rescue}(\mathsf{Rescue}(b, x, y, 0), k, 0, 0).
    • Observe the Merkle tree path mm and deduce the unique ID uu.
    • Check that cc is in the tree with root rr, given the Merkle tree path mm, with the unique ID uu.
    • Check n=Rescue(Rescue(u264+x,y,0,k),s,0,0)n = \mathsf{Rescue}(\mathsf{Rescue}(u\cdot 2^{64}+x, y, 0, k), s, 0, 0).
    • Check t=Rescue(1,h,z,s)t = \mathsf{Rescue}(1, h, z, s).

Confidential assets to anonymous assets (BAR-to-ABAR)

Note that its verification contains a zk-SNARK part and a non-zk-SNARK part. We first describe the zk-SNARK part, as follows.

  • Instance:

    • the commitment of ABAR cc
    • the commitment of the secrets in BAR dd
    • the non-zk-SNARK part responses β\beta, λ\lambda, βλ\beta\cdot\lambda, and w=s1+λs2w = s_1+\lambda\cdot s_2, where s1=βx+as_1 = \beta x + a and s2=βy+bs_2 = \beta y + b
  • Witness:

    • the secrets in BAR, xx, yy, aa, and bb
    • the randomizer rr used in commitment dd
    • the blinding factor in the commitment bb'
    • the public key of the recipient kk
  • Statement:

    • Check that dd is a commitment of xyabrx\parallel y\parallel a\parallel b\parallel r.
    • Check that c=Rescue(Rescue(b,x,y,0),k,0,0)c = \mathsf{Rescue}(\mathsf{Rescue}(b', x, y, 0), k, 0, 0).
    • Check βx+βλy+λb=wa\beta x + \beta\lambda y + \lambda b = w - a in field simulation.

The non-zk-SNARK part, which interacts with the Ristretto point that encodes the amount PP and the one that encodes the asset type QQ, the randomizers RR and SS, and the responses s1s_1, s2s_2, s3s_3, and s4s_4.

The non-zk-SNARK part works as follows.

  • Initialize a cryptographic sponge with group description.
  • Put (P,Q)(P, Q) into the sponge.
  • Put the commitment of ABAR cc into the sponge.
  • Put the commitment of the secrets in BAR dd into the sponge.
  • Put (R,S)(R, S) into the sponge.
  • Squeeze a random challenge, which should be equal to β\beta, from the sponge.
  • Put (s1,s2,s3,s4)(s_1, s_2, s_3, s_4) into the sponge.
  • Squeeze a random challenge, which should be equal to λ\lambda, from the sponge.
  • Check s1G+s3H=βP+Rs_1 G + s_3 H = \beta P + R.
  • Check s2G+s4H=βQ+Ss_2 G + s_4 H = \beta Q + S.

Anonymous assets to confidential assets (ABAR-to-BAR)

Similar to the BAR-to-ABAR protocol, it consists of a zk-SNARK part and a non-zk-SNARK part. We first describe the zk-SNARK part, as follows.

  • Instance:

    • the nullifier of ABAR nn
    • the Merkle tree root rr
    • the commitment of the secrets in BAR dd
    • the non-zk-SNARK part responses β\beta, λ\lambda, βλ\beta\cdot\lambda, and w=s1+λs2w=s_1+\lambda s_2 where s1=βx+as_1 = \beta x + a and s2=βy+bs_2 = \beta y+b
    • transaction body hash hh
    • non-malleability tag tt
  • Witness:

    • the secrets in BAR, xx, yy, aa, and bb
    • the randomizer rr used in commitment dd
    • the blinding factor in the commitment bb'
    • the secret key of the owner ss
    • Merkle tree path mm
    • non-malleability randomizer zz
  • Statement:

    • Let the reconstructed public key be k:=sGk := sG where GG is the generator for the signature scheme.
    • Let the reconstructed commitment be c:=Rescue(Rescue(b,x,y,0),k,0,0)c := \mathsf{Rescue}(\mathsf{Rescue}(b', x, y, 0), k, 0, 0).
    • Observe the Merkle tree path mm and deduce the unique ID uu.
    • Check that cc is in the tree with root rr, given the Merkle tree path mm, with the unique ID uu.
    • Check that dd is a commitment of xyabrx\parallel y\parallel a\parallel b\parallel r.
    • Check βx+βλy+λb=wa\beta x + \beta \lambda y + \lambda b = w - a in field simulation.
    • Check n=Rescue(Rescue(u264+x,y,0,k),s,0,0)n = \mathsf{Rescue}(\mathsf{Rescue}(u\cdot 2^{64} + x, y, 0, k), s, 0, 0).
    • Check t=Rescue(1,h,z,s)t = \mathsf{Rescue}(1, h, z, s).

The non-zk-SNARK part, which interacts with the Ristretto point that encodes the amount PP and the one that encodes the asset type QQ, the randomizers RR and SS, and the responses s1s_1, s2s_2, s3s_3, and s4s_4.

The non-zk-SNARK part works as follows.

  • Initialize a cryptographic sponge with group description.
  • Put (P,Q)(P, Q) into the sponge.
  • Put the nullifier nn into the sponge.
  • Put the commitment of the secrets in BAR dd into the sponge.
  • Put (R,S)(R, S) into the sponge.
  • Squeeze a random challenge, which should be equal to β\beta, from the sponge.
  • Put (s1,s2,s3,s4)(s_1, s_2, s_3, s_4) into the sponge.
  • Squeeze a random challenge, which should be equal to λ\lambda, from the sponge.
  • Check s1G+s3H=βP+Rs_1 G+ s_3 H = \beta P+ R.
  • Check s2G+s4H=βQ+Ss_2 G + s_4 H = \beta Q + S.

Anonymous transfer

We now define the statement for different combinations of the number of inputs and outputs. Consider that we have NinN_\mathsf{in} ABAR inputs and NoutN_\mathsf{out} ABAR outputs.

  • Instance:

    • NinN_\mathsf{in} nullifiers [ni]i=1Nin[n_i]_{i=1}^{N_\mathsf{in}}
    • the Merkle tree root rr
    • NoutN_\mathsf{out} ABAR commitments [ci]i=1Nout[c'_i]_{i=1}^{N_\mathsf{out}}
    • the fee ff
    • transaction body hash hh
    • non-malleability tag tt
  • Witness:

    • the blinding factors in the input commitments [bi]i=1Nin[b_i]_{i=1}^{N_\mathsf{in}}
    • the blinding factors in the output commitments [bi]i=1Nout[b'_i]_{i=1}^{N_\mathsf{out}}
    • the amounts in the input commitments [xi]i=1Nin[x_i]_{i=1}^{N_\mathsf{in}}
    • the asset types in the input commitments [yi]i=1Nin[y_i]_{i=1}^{N_\mathsf{in}}
    • the amounts in the output commitments [xi]i=1Nout[x'_i]_{i=1}^{N_\mathsf{out}}
    • the asset types in the output commitments [yi]i=1Nout[y'_i]_{i=1}^{N_\mathsf{out}}
    • the secret keys of the input commitments' owners [si]i=1Nin[s_i]_{i=1}^{N_\mathsf{in}}
    • the Merkle tree paths for all the input commitments [mi]1Nin[m_i]_1^{N_\mathsf{in}}
    • the public keys of the output commitments' recipients [ki]i=1Nout[k'_i]_{i=1}^{N_\mathsf{out}}
    • non-malleability randomizer zz
  • Statement:

    • Let the reconstructed public keys be ki=siGk_i = s_i G where GG is the generator for the signature scheme, for i=1,2,...,Nini=1, 2, ..., N_\mathsf{in}.
    • Let the reconstructed input commitments be ci=Rescue(Rescue(bi,xi,yi,0),ki,0,0)c_i = \mathsf{Rescue}(\mathsf{Rescue}(b_i, x_i, y_i, 0), k_i, 0, 0), for i=1,2,...,Nini=1, 2, ..., N_\mathsf{in}.
    • Let the reconstructed output commitments be ci=Rescue(Rescue(bi,xi,yi,0),ki,0,0)c'_i = \mathsf{Rescue}(\mathsf{Rescue}(b'_i, x'_i, y'_i, 0), k'_i, 0, 0), for i=1,2,...,Nouti=1, 2, ..., N_\mathsf{out}.
    • Observe the Merkle tree path mim_i and deduce its corresponding unique ID uiu_i, for i=1,2,...,Nini = 1, 2, ..., N_\mathsf{in}.
    • Check that cic_i is in the tree with root rr, given the Merkle tree path mim_i, with the unique ID uiu_i, for i=1,2,...,Nini=1, 2, ..., N_\mathsf{in}.
    • Check ni=Rescue(Rescue(ui264+xi,yi,0,ki),si,0,0)n_i = \mathsf{Rescue}(\mathsf{Rescue}(u_i\cdot 2^{64} + x_i, y_i, 0, k_i), s_i, 0, 0).
    • Check if (xi,yi)(x'_i, y'_i) is a correct mixing of (xi,yi)(x_i, y_i) after paying the fee ff over the asset for transaction fees.
    • Check amounts of the output commitments xix'_i are within 6464 bit, for i=1,2,...,Nouti = 1, 2, ..., N_\mathsf{out}.
    • Construct an array H=(Nin,h,z,s1,s2,...,sNin)H=({N}_\mathsf{in}, h, z, s_1, s_2, ..., s_{N_\mathsf{in}}).
    • Pad this array with 00 so that its length =4+3n\ell = 4 + 3n for some nonnegative integer nn.
    • cur:=Rescue(H1,H2,H3,H4)\mathsf{cur} := \mathsf{Rescue}(H_1, H_2, H_3, H_4).
    • For j=1,2,...,nj = 1, 2, ..., n: cur:=Rescue(cur,H3n+2,H3n+3,H3n+4)\mathsf{cur} := \mathsf{Rescue}(\mathsf{cur}, H_{3n + 2}, H_{3n + 3}, H_{3n + 4}).
    • Check t=curt = \mathsf{cur}.

Asset mixing gadget

The asset mixing gadget is defined for different combinations of the number of inputs and outputs, and is hardcoded with the asset type used to pay for transaction fees.

  • Gadget input:

    • NinN_\mathsf{in} input pairs of amount and asset type: [(xi,yi)]i=1Nin[(x_i, y_i)]_{i=1}^{N_\mathsf{in}}
    • NoutN_\mathsf{out} output pairs of amount and asset type: [(xi,yi)]i=1Nout[(x'_i, y'_i)]_{i=1}^{N_\mathsf{out}}
    • The fee ff
  • Statement:

    • Compute the sum σi\sigma_i for each input. For i=1,2,...,Nini = 1, 2, ..., N_\mathsf{in}:

      • σi=j=1Nin(yi=?yj)xj\sigma_i = \sum_{j=1}^{N_\mathsf{in}} (y_i \stackrel{?}{=} y_j)\cdot x_j, where (yi=?yj)=1(y_i \stackrel{?}{=} y_j) = 1 if yi=yjy_i = y_j and 00 otherwise.
    • Compute the sum σi\sigma'_i for each output. For i=1,2,...,Nouti = 1, 2, ..., N_\mathsf{out}:

      • σi=j=1Nout(yi=?yj)xj\sigma'_i = \sum_{j=1}^{N_\mathsf{out}} (y'_i \stackrel{?}{=} y'_j)\cdot x'_j, where (yi=?yj)=1(y'_i \stackrel{?}{=} y'_j) = 1 if yi=yjy'_i = y'_j and 00 otherwise.
    • Require at least one of the yiy_i is the fee type.

    • For each accumulated input pair (σi,yi)(\sigma_i, y_i) for i=1,2,...,Nini = 1, 2, ..., N_\mathsf{in}:

      • For each accumulated output pair (σj,yj)(\sigma'_j, y'_j) for i=1,2,...,Nini = 1, 2, ..., N_\mathsf{in}:

        • If yiy_i is not the fee type, require (σiσj)(yi=?yj)=0(\sigma_i - \sigma'_j)\cdot (y_i \stackrel{?}{=}y'_j) = 0.
        • Else, if yiy_i is the fee type, require (σiσjf)(yi=?yj)=0(\sigma_i - \sigma'_j-f)\cdot (y_i \stackrel{?}{=}y'_j) = 0
      • If yiy_i is not the fee type, then there must exist some jj such that yi=yjy_i = y'_j.

      • If yiy_i is the fee type, and if there is no jj such that yi=yjy_i = y'_j, then we require σi=f\sigma_i = f.

    • Require that all the output asset types appear among the input asset types. For each output asset type yjy'_j, j=1,2,...,Noutj=1, 2, ..., N_\mathsf{out}, require i=1Nin(yiyj)=0\prod_{i=1}^{N_\mathsf{in}} (y_i - y'_j) = 0.