The value-balance mechanism
Penumbra uses additively homomorphic commitments in the style of Zcash Sapling to ensure that the balances contributed by actions within a transaction sum to zero, with the capability to hide intermediate amounts. The IsAction
trait, which all actions implement, contains a function fn balance_commitment(&self) -> balance::Commitment;
, which determines the value (potentially of multiple assets) that each action credits or debits from the transaction balance and whether that value is transparent or hidden. Balance commitments are group elements in the Decaf377 elliptic curve, whose order is slightly less than , and are of the form , where
is a random blinding value (which is zero for transparent commitments)
is a generator that is the Elligator encoding of the Blake2b hash of the string
decaf377-rdsa-binding
is the (possibly negative) value associated with asset
i
in commitmentj
is a generator depending on asset
i
's ID (the Elligator encoding of the Poseidon hash of the Blake2b hash of the stringpenumbra.value.generator
and the asset's numeric ID)
These commitments have several important properties:
Summing them as curve points produces a commitment to the sum of the balances.
If is random, knowledge of does not reveal anything about .
If all of are zero, can be used as an ECDSA public key to check signatures signed with knowledge of
If some of are nonzero, a malicious signer can only produce a signature for by finding some such that and signing with , but finding such a requires solving the discrete logarithm problem.
Statements involving their components can be efficiently proved in zero knowledge by providing and as witnesses to the circuits.
The first property is used by Transaction::binding_verification_key
to produce a commitment to the sum of the transaction's actions' balances. The third property is used by Transaction::check_stateless
's valid_binding_signature
check to ensure that the transaction's balance sums to zero by checking the signature produced in TransactionPlanner::apply_auth_data
, where the synthetic_blinding_factor
used to construct the binding_signing_key
corresponds to .
In order for this to correctly represent value, each action's implementation must ensure that no unconstrained attacker-controlled values are included in the determination of the balance commitment and that overflow modulo the order of the group is not possible. Each action must ensure that the amounts contributed to the value balance are accurately tracked, whether that be through external state (like the nullifier set/state commitment tree) or by having a mix of negative and positive of different assets within the action's balance commitment.
For a more detailed treatment of the single-asset case, see section 4.13, "Balance and Binding Signature (Sapling)", of the Zcash protocol specification (https://zips.z.cash/protocol/protocol.pdf↗).