Wallet topup allows a client to add credit to their wallet credential, revealing the credit increase (so that the issuer can check that the increase is in line with application-specific policy) but hiding the old and new balances.

  1. Client. Given the credit topup amount \(c\) as well as credential attributes \((w,n)\) and tag \((P_0,Q_0)\) for a previously-issued wallet credential, the client proceeds as follows, simultaneously preparing a presentation of the previous wallet credential and a request for blinded issuance of a new credential with balance \(w' = w + c\). The client:

    1. Uses the current time and the epoch duration to determine the current epoch index. If the existing credential's issuance parameters are not the primary issuance parameters for the current epoch, perform a rollover to the current parameters and restart the protocol.

    2. Re-randomizes the tag, choosing \(t \xleftarrow{\$} \mathbb F_p\) and computing \((P, Q) \gets (t P_0, t Q_0)\).

    3. Chooses randomness \( \widetilde w \xleftarrow{\$} \mathbb F_p \) and computes \( \operatorname{Com}(w) \gets w P + \widetilde w \widetilde B \) and \( \operatorname{Com}(w') \gets w' P + \widetilde w \widetilde B \).

    4. Commits to \(Q\) by choosing \( r_Q \xleftarrow{\$} \mathbb F_p \) and computing \( C_Q = Q + r_Q B \).

    5. Computes a correction term \( V \gets \widetilde w X_1 - rB \).

    6. Generates a random nullifier for the new credential, \( n' \xleftarrow{\$} \mathbb F_p \).

    7. Generates an ephemeral ElGamal public key \( d \xleftarrow{\$} \mathbb F_p \) and computes the ephemeral public key \( D \gets d B \).

    8. Generates randomness \( r_n, r_w \xleftarrow{\$} \mathbb F_p \) and computes \[ \operatorname{Enc}_D(w' B) \gets (r_w B, (w' + r_w d)B) \] and \[ \operatorname{Enc}_D(n' B) \gets (r_n B, (n' + r_n d)B). \]

    9. Forms the following proof, combining credential presentation and blinded issuance: \[ \begin{aligned} \pi &\gets \operatorname{PK}\{ \\ &\mathtt{wallet::topup::client}, \\ &(d, w, w', \widetilde w, n', r_Q, r_w, r_n), \\ &( D, \operatorname{Enc}_D(w' B), \operatorname{Enc}_D(n' B), P, V, \operatorname{Com}(w), \operatorname{Com}(w') ), \\ &(B, \widetilde B, \mathbf X) \; : \\ &D = d B \\ &\operatorname{Enc}_D(n' B) = (r_n B, n' B + r_n D) \\ &\operatorname{Enc}_D(w' B) = (r_w B, w' B + r_w D) \\ &\operatorname{Com}(w) = w P + \widetilde w \widetilde B \\ &\operatorname{Com}(w') = w' P + \widetilde w \widetilde B \\ & V = \widetilde w X_1 - r_Q B \\ \}. \end{aligned} \] The client retains the transcript state for the next step.

    10. Using the same transcript, forms a rangeproof \(\rho\) proving that \(\operatorname{Com}(w')\) commits to a value in range \([0,2^{64})\), and retains the transcript state.

    11. Sends the epoch index, the old nullifier \(n\), \(D\), \(\operatorname{Enc}(n'B)\), \(\operatorname{Enc}(w'B)\), \(\operatorname{Com}(w)\), \(P\), \(C_Q\), \(\pi\), and \(\rho\) to the issuer.

  2. Issuer. The issuer proceeds as follows. The issuer:

    1. Checks the requested credit amount \(c\) according to application policy.

    2. Checks that the issuance parameters for the epoch index selected by the client are in Active or Primary state.

    3. Checks whether the nullifier \(n\) is in the wallet nullifier set for the selected epoch, rejecting the request if it is present and adding it to the nullifier set if it is not present.

    4. Computes \(V\) as \[ V \gets (x_0 + x_2 n) B + x_1 \operatorname{Com}(w) - C_Q. \]

    5. Computes \( \operatorname{Com}(w') \gets \operatorname{Com}(w) + cP \).

    6. Verifies the proof \(\pi\) and retains the transcript state.

    7. Verifies the proof \(\rho\) and retains the transcript state.

    8. Selects \( b \xleftarrow{\$} \mathbb F_p \) and computes \( P \gets bB \).

    9. Selects \( r \xleftarrow{\$} \mathbb F_p \) to compute \[ \operatorname{Enc}_D(Q) \gets (rB, x_0 P + rD) + b x_1 \operatorname{Enc}_D(w'B) + b x_2 \operatorname{Enc}_D(n'B). \]

    10. The issuer forms the proof \[ \begin{aligned} \pi &\gets \operatorname{PK}\{ \\ &\mathtt{wallet::topup::issuer}, \\ &( b, r, \mathbf x, \widetilde x_0, t_1, t_2 ), \\ &( P, D, \operatorname{Enc}_D(w'B), \operatorname{Enc}_D(n'B), \operatorname{Enc}_D(Q), T_1, T_2 ), \\ &(\mathbf X, B, \widetilde B) \; : \\ & X_0 = x_0 B + \widetilde x_0 \widetilde B, \; X_1 = x_1 \widetilde B, \; X_2 = x_2 \widetilde B, \\ & P = bB, \\ & T_1 = bX_1', \; T_1 = t_1 \widetilde B, \\ & T_2 = bX_2', \; T_2 = t_2 \widetilde B, \\ & \operatorname{Enc}_D(Q) = (rB, x_0 P + rD) + t_1 \operatorname{Enc}_D(w'B) + t_2 \operatorname{Enc}_D(n'B) \\ \}. \end{aligned} \] This proof should be added to the transcript from step (2.7), chaining the issuer's proof onto the client's proofs.

    11. The issuer sends \(P\), \(\operatorname{Enc}_D(Q)\), \(T_1\), \(T_2\), and \(\pi\) to the client.

  3. Client. The client processes the response as follows:

    1. The client uses the transcript state from step (1.10) to verify \(\pi\).

    2. The client decrypts \(Q\) by computing \[ Q \gets \operatorname{Enc}_D(Q)_1 - d \operatorname{Enc}_D(Q)_0. \]