Given account1 owned by
// The sender wallet generates the withdraw_proof by first retrieving the receiver account public key
let withdraw_proof = global!["withdraw_proof"];
let confidential_resource_addr = global!["confidential_resource_addr"];
let bucket = account1.withdraw(confidential_resource_addr, withdraw_proof);
account2.deposit(bucket); // No authorisation required to deposit
- A withdraw will require a proof object that shows a balanced withdraw
-
$k_1.G + 100.H - (k_2.G + 10.H) - (k_3.G + 90.H) =? (0)$ , an encrypted value (via stealth key), fields <public_stealth_nonce
,public_stealth_key
> ($K_s = H(r.P_2).G + P_2 = H(p_2.R).G + P_2$ ) - The first commitment term is the input, the second the withdraw, and the third the change.
- To facilitate the stealth key, we should consider adding a mandatory public key to the Account component
- Once a
ConfidentialProof
is validated, a bucket is created containing the withdrawn commitment - The de/inflation invariant holds because a bucket cannot be created without a correct proof.
- The bucket commitment is added to the resource contained in a vault.
- The receiver wallet would need to come online to validate the received funds
- The receiver wallet could submit a transaction that aggregates the commitments. They update their mask for the resource
- Alternatively, we could hold incoming commitments separately and have the receiver "claim" incoming commitments by aggregating them into the single liquid commitment.
pub struct WithdrawProof {
// Output commitment put in bucket
output_commitment: Commitment,
// Change commitment returned to the sender vault
change_commitment: ConfidentialProof,
// Proof of knowledge of input, output and change commitments and balance proof
excess_signature: Signature,
// Batch range proof for commitments
rangeproof: Vec<u8>,
// Value contained in output commitment, encrypted using the stealth key K_s
encrypted_value: Vec<u8>,
// R
public_stealth_nonce: PublicKey,
// K_s
public_stealth_key: PublicKey,
}