Skip to main content

Pedersen Commitments

Understanding the cryptographic foundation of Pedersen VRF's privacy features.

What is a Pedersen Commitment?

A Pedersen Commitment is a cryptographic scheme that allows you to commit to a value while keeping it hidden, with the ability to reveal it later.

Commit(m,r)=mG+rH\text{Commit}(m, r) = m \cdot G + r \cdot H

Where:

  • mm is the message (value being committed)
  • rr is the blinding factor (random)
  • G,HG, H are independent generator points

Properties

Hiding

The commitment reveals nothing about mm:

Commit(m1,r1)cCommit(m2,r2)\text{Commit}(m_1, r_1) \approx_c \text{Commit}(m_2, r_2)

An adversary cannot determine mm from the commitment alone.

Binding

Once committed, you cannot change the value:

extCommit(m1,r1)=Commit(m2,r2)m1=m2 ext{Commit}(m_1, r_1) = \text{Commit}(m_2, r_2) \Rightarrow m_1 = m_2

This holds with overwhelming probability assuming the discrete log relationship between GG and HH is unknown.

Homomorphic

Commitments can be combined:

Commit(m1,r1)+Commit(m2,r2)=Commit(m1+m2,r1+r2)\text{Commit}(m_1, r_1) + \text{Commit}(m_2, r_2) = \text{Commit}(m_1 + m_2, r_1 + r_2)

This enables advanced protocols like range proofs and anonymous credentials.

Pedersen VRF: Hiding the Public Key

In standard VRF, the verifier knows the signer's public key. Pedersen VRF hides it:

Standard VRF Verification

Verify(pk, input, output, proof) → bool

Public key is visible

Pedersen VRF Verification

Verify(input, output, proof) → bool

No public key needed!
(it's blinded in the proof)

How It Works

Key Commitment

Instead of revealing pkpk, the prover commits to it:

Cpk=pk+bBC_{pk} = pk + b \cdot B

Where:

  • pkpk is the actual public key
  • bb is a blinding factor
  • BB is a blinding base point

Blinding Factor Derivation

The blinding factor is deterministically derived:

b=Hash(sk,α,ad)b = \operatorname{Hash}(sk, \alpha, ad)

This ensures:

  • Determinism: Same inputs produce same blinding
  • Unlinkability: Different inputs produce different blindings
  • Unpredictability: Adversary cannot predict blindings

Proof Structure

A Pedersen VRF proof contains (based on the Bandersnatch VRF Specification):

  1. OO - VRF output point (same as IETF: O=skIO = sk \cdot I)
  2. Yˉ\bar{Y} - Blinded public key commitment (Yˉ=skG+bB\bar{Y} = sk \cdot G + b \cdot B)
  3. RR - Commitment: R=kG+kbBR = k \cdot G + k_b \cdot B
  4. OkO_k - VRF commitment: Ok=kIO_k = k \cdot I
  5. ss - Response scalar: s=k+csks = k + c \cdot sk
  6. sbs_b - Blinding response: sb=kb+cbs_b = k_b + c \cdot b

Where:

  • kk is a nonce derived from sksk and input
  • kbk_b is a nonce derived from bb and input
  • cc is the challenge: c=Hash(Yˉ,I,O,R,Ok,ad)c = \text{Hash}(\bar{Y}, I, O, R, O_k, ad)

Verification Equations

The verifier checks two equations:

Equation 1 (VRF relation):

Ok+cO=sIO_k + c \cdot O = s \cdot I

Equation 2 (Key commitment relation):

R+cYˉ=sG+sbBR + c \cdot \bar{Y} = s \cdot G + s_b \cdot B

Both equations must hold for the proof to be valid. The verifier never learns pkpk or bb individually!

Privacy Analysis

What the Verifier Learns

  • ✅ The proof is valid
  • ✅ The signer knows a valid secret key
  • ✅ The random output is correct

What the Verifier Does NOT Learn

  • ❌ Which public key was used
  • ❌ Whether two proofs came from the same key
  • ❌ Any information linking proofs together

Unlinkability

Two proofs from the same key cannot be linked:

# Same key, different inputs → different blindings
proof1 = PedersenVRF.prove(input1, sk, ad) # blinding b1
proof2 = PedersenVRF.prove(input2, sk, ad) # blinding b2

# b1 ≠ b2, so C_pk values are different
# Verifier cannot tell they came from the same key

Comparison with Standard VRF

PropertyIETF VRFPedersen VRF
Public Key Revealed✅ Yes❌ No (blinded)
Proofs Linkable✅ Yes❌ No
Proof SizeSmallerLarger
VerificationRequires pkNo pk needed

Mathematical Details

Generators

Pedersen VRF requires two independent generators GG and BB:

logG(B)=unknown\log_G(B) = \text{unknown}

If someone knew xx such that B=xGB = x \cdot G, they could:

  • Forge commitments
  • Break the binding property

Security Assumption

Security relies on the Discrete Log Problem:

Given GG and B=xGB = x \cdot G, it's computationally hard to find xx.

Use Cases

Anonymous Authentication

Prove you have valid credentials without revealing identity:

# User proves membership without identification
proof = PedersenVRF.prove(challenge, user_secret_key, context)

Private Voting

Cast verifiable votes without exposing voter identity:

# Vote is verifiable but voter is anonymous
vote_proof = PedersenVRF.prove(ballot_id, voter_key, vote_choice)

Unlinkable Tokens

Generate tokens that cannot be traced back:

# Each token is unlinkable to the issuer's identity
token = PedersenVRF.prove(token_id, issuer_key, metadata)

Further Reading