Skip to main content

Value Commitments & Binding Signature

A private transaction must balance: total input value = total output value + net public flow. Platus proves this without revealing any amount, using Pedersen value commitments and one aggregate binding signature per bundle.

The value commitment

Each 2-in/2-out Action carries a single net value commitment over two independent BabyJubJub generators:

cvnet=(vin1+vin2voldvout1+vout2vnew)H+rcvGcv_{net} = \big(\underbrace{v_{in1}+v_{in2}}_{v_{old}} - \underbrace{v_{out1}+v_{out2}}_{v_{new}}\big)\cdot H + rcv\cdot G
  • G = BASE8: the prime-order subgroup generator.
  • H = VALUE_H: the value base, derived nothing-up-my-sleeve from Poseidon2("platus.value_commit.h.v1").
  • rcv: a fresh per-Action blinding scalar.

Only cv_net's (x, y) are public (in the ActionOp); they reveal nothing without v_old, v_new, and rcv.

The binding signature

The binding signature proves the whole bundle balances against its declared netPublicValue, without revealing any blinding factor. Define:

bsk=ircvi,bvk=icvnet,inetPublicValueHbsk = \sum_i rcv_i, \qquad bvk = \sum_i cv_{net,i} - netPublicValue\cdot H

By linearity of Pedersen commitments:

bvk=(ivold,iivnew,inetPublicValue)H+bskGbvk = \Big(\sum_i v_{old,i} - \sum_i v_{new,i} - netPublicValue\Big)\cdot H + bsk\cdot G

If — and only if — the bundle balances does the H term vanish, leaving bvk = bsk·G. So bvk is a public key whose secret is bsk; a valid Schnorr signature over the bundle digest proves knowledge of that secret. An unbalanced bundle leaves a non-zero H component whose discrete log is unknown, and no signature can be forged.

Sign convention and the two forms

The Schnorr equation verified on-chain is s·G == R + e·bvk, with the challenge

e=(H02256modr+H1)modr,Hb=keccak256(DOMAIN,Rx,Ry,bvkx,bvky,msg,b)e = \Big(\frac{H_0\cdot 2^{256} \bmod r + H_1}{} \Big)\bmod r,\quad H_b = \text{keccak256}(\text{DOMAIN}, R_x, R_y, bvk_x, bvk_y, msg, b)