ElGamal Encryption
Obelysk uses Exponential ElGamal encryption over the STARK curve to hide all token amounts on-chain. This is the foundational cryptographic primitive powering every privacy feature in Track 1 — from confidential transfers to dark pool trading.
Why ElGamal?
ElGamal encryption has a critical property that makes it perfect for on-chain privacy: additive homomorphism. The contract can update encrypted balances without ever decrypting them.
If Enc(a) encrypts amount a and Enc(b) encrypts amount b, then Enc(a) ⊕ Enc(b) = Enc(a + b). The contract can add encrypted amounts together without knowing what they are. This is how balances are updated on-chain.
The Scheme
ElGamal on the STARK curve works as follows:
Key Generation
Private key: sk ← random scalar in [1, n-1]
Public key: pk = sk · G
Where G is the STARK curve generator and n is the curve order.
Encryption
To encrypt an amount m with randomness r:
Ciphertext = (L, R) where:
L = m · G + r · pk (left component — encodes the message)
R = r · G (right component — encodes the randomness)
Decryption
The private key holder computes:
m · G = L - sk · R
= (m·G + r·pk) - sk·(r·G)
= m·G + r·sk·G - sk·r·G
= m·G
Then recovers m via discrete log (using AE hints for O(1) decryption instead of brute force).
Since solving discrete log is expensive, the sender includes an AE hint — an encrypted version of the plaintext amount. The recipient decrypts the hint using a shared secret derived from ECDH, recovering the amount in O(1) time.
STARK Curve Parameters
The STARK curve is an elliptic curve defined over the Stark prime field:
Curve equation: y² = x³ + α·x + β (mod p)
where α = 1
Field prime (p):
0x800000000000011000000000000000000000000000000000000000000000001
Curve order (n):
0x800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
Generator G:
x = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca
y = 0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f
Pedersen Generator H (nothing-up-my-sleeve):
x = 0x73bd2c9434c955f80b06d2847f8384a226d6cc2557a5735fd9f84d632f576be
y = 0x1bd58ea52858154de69bf90e446ff200f173d49da444c4f462652ce6b93457e
A critical implementation detail: all scalar operations (Schnorr challenges, blinding factors) must use the curve order n, NOT the field prime p. Using p instead of n breaks Schnorr signature security and can lead to forgery attacks.
Proof System
Every encrypted operation requires zero-knowledge proofs verified on-chain. These prove the operation is valid without revealing the plaintext amounts.
Schnorr Proof of Ownership
Proves knowledge of the private key sk without revealing it:
Prover:
1. Choose random k
2. Commitment: A = k · G
3. Challenge: c = Hash(A || pk || domain)
4. Response: s = k + c · sk (mod n)
Verifier:
Check: s · G == A + c · pk
Chaum-Pedersen Encryption Proof
Proves that a ciphertext (L, R) correctly encrypts a value under a given public key:
Statement: L = m·G + r·pk AND R = r·G
Prover (knows m, r):
1. Random km, kr
2. AL = km·G + kr·pk, AR = kr·G
3. c = Hash(AL, AR, L, R, pk)
4. sm = km + c·m, sr = kr + c·r
Verifier:
Check: sm·G + sr·pk == AL + c·L
Check: sr·G == AR + c·R
Same-Encryption Proof
Proves that multiple ciphertexts encrypt the same amount under different public keys. This is critical for confidential transfers where sender, receiver, and auditor must all receive the same value:
Statement: (L₁, R₁) under pk₁ and (L₂, R₂) under pk₂
both encrypt the same message b
Prover:
Shared response: sb = kb + c·b (mod n)
Per-key responses: sr₁ = kr₁ + c·r₁, sr₂ = kr₂ + c·r₂
Verifier:
Same sb used in BOTH checks ← proves same message!
The SameEncryption3Proof extends this to three parties (sender, receiver, auditor) and is used by PrivacyRouter for compliance-ready transfers. Domain separator: obelysk-same-enc-3-v1.
Range Proofs
Prove that an encrypted amount is within valid bounds (0 to 2^64) without revealing the value. This prevents negative balances and overflow attacks.
Where ElGamal Is Used
| Contract | How ElGamal Is Used |
|---|---|
| ConfidentialTransfer | All balances stored as ElGamal ciphertexts. 6 proofs per transfer. |
| PrivacyRouter | Multi-asset encrypted balances with epoch-based settlement. |
| DarkPool | Balance commitments and amount proofs for sealed-bid auctions. |
| ShieldedSwap | Balance proofs for privacy pool interactions. |
| StealthRegistry | Encrypted amount in payment announcements. |
Security Properties
Next Steps
- STARK Curve Primitives — Schnorr, Pedersen, and curve arithmetic details
- Confidential Transfer — how encrypted balances work end-to-end
- Privacy Pools — Merkle-based deposit/withdrawal with range proofs
- Whitepaper — formal cryptographic specification