Docs
/concepts
/Commitments

Commitments

Understanding Pedersen Commitments

Pedersen Commitments

Veil uses Pedersen Commitments to hide transaction amounts while retaining the ability to verify mathematical properties.

The Formula

A commitment CC is calculated as:

C=amountG+blindingHC = \text{amount} \cdot G + \text{blinding} \cdot H

Where:

  • amount\text{amount}: The value being committed to (in lamports for SOL, or smallest token unit).
  • blinding\text{blinding}: A cryptographically secure random blinding factor (32 bytes).
  • GG and HH: Public generator points on the BN254 (alt_bn128) elliptic curve, specifically on the G1 subgroup.

The generator HH uses a nothing-up-my-sleeve construction with domain separator NYX_PROTOCOL_PEDERSEN_H_V1 to ensure it's independent from GG and has no known discrete log relationship.

Cryptographic Properties

1. Perfectly Hiding (Information-Theoretic)

Given a commitment CC, it is impossible to determine the amount, even with infinite computing power. For any guessed value vv', there exists a corresponding blinding factor rr' such that C=vG+rHC = v' \cdot G + r' \cdot H. This provides unconditional privacy for transaction amounts.

This property holds because the blinding factor space is large enough (256 bits) that for every possible amount, there are an astronomically large number of valid blinding factors that produce the same commitment.

2. Computationally Binding (Under Discrete Logarithm Assumption)

It is computationally infeasible to find two different pairs (amount,blinding)(\text{amount}, \text{blinding}) and (amount,blinding)(\text{amount}', \text{blinding}') that produce the same commitment CC, assuming the hardness of the discrete logarithm problem on the BN254 curve.

This property prevents a user from "opening" a commitment to a different amount than originally committed, ensuring the integrity of private transactions.

Usage in Veil

When you call shield():

  1. The SDK generates a cryptographically secure random blinding factor (32 bytes) using OsRng.
  2. It computes the commitment: C=amountG+blindingHC = \text{amount} \cdot G + \text{blinding} \cdot H on the BN254 G1 curve.
  3. The commitment CC (32 bytes, represented as a single curve point) is sent to the Solana program.
  4. The program verifies the shield operation and adds CC to the Merkle tree as a new leaf.

The amount and blinding factor never leave your device and are not visible on-chain. Only the resulting commitment is public.

Technical Specifications

  • Curve: BN254 (alt_bn128), G1 subgroup
  • Commitment Size: 32 bytes (single curve point, compressed)
  • Blinding Factor: 32 bytes of cryptographically secure randomness
  • Security Level: ~128 bits (based on BN254 discrete log hardness)
  • Generator H: Derived using nothing-up-my-sleeve construction with domain separator NYX_PROTOCOL_PEDERSEN_H_V1

Security Considerations

The perfectly hiding property means that no amount of computational power can reveal the amount from a commitment alone. However, the binding property relies on the computational hardness of solving the discrete logarithm on BN254. If this assumption is ever broken (e.g., by quantum computers), the binding property would be compromised, though amounts would remain hidden.

For practical security, users must:

  • Keep blinding factors secret and backed up securely
  • Never reuse blinding factors across different commitments
  • Store commitment data to reconstruct notes for spending

See also: Nullifiers for how commitments are spent, and zkSNARKs for how commitment correctness is proven.