ERC-8227 — Encrypted Tokens and State
Summary: ERC-8227 defines a standard interface for fungible tokens with encrypted balances and the extension of that interface to arbitrary contract state fields. Balances are stored as BFV ciphertexts; arithmetic (addition, multiplication) is performed homomorphically on-chain via precompiles.
Covenant Surface
| Construct | Description |
|---|---|
encrypted token | Declare a fungible token with encrypted balances |
encrypted<T> | Mark any field as FHE-encrypted |
fhe_add(a, b) | Homomorphic addition |
fhe_mul(a, b) | Homomorphic multiplication |
fhe_encrypt(v, pk) | Encrypt a plaintext value |
fhe_decrypt(c, sk) | Decrypt a ciphertext (threshold protocol) |
reveal field to addr | Authorized threshold decryption |
Precompile Signatures
ERC-8227 defines seven precompiles. Their addresses are fixed across EVM-compatible chains that support Styx:
| Address | Name | Signature | Gas (L1) |
|---|---|---|---|
0x0f | fhe_encrypt | (bytes32 pk, uint256 value) → bytes128 ciphertext | 50,000 |
0x10 | fhe_add | (bytes128 a, bytes128 b) → bytes128 | 8,000 |
0x11 | fhe_mul | (bytes128 a, bytes128 b) → bytes128 | 120,000 |
0x12 | fhe_cmp | (bytes128 a, bytes128 b) → bytes128 | 90,000 |
0x13 | fhe_decrypt_auth | (bytes128 c, address[] validators) → bytes128 | 200,000 |
0x14 | fhe_reencrypt | (bytes128 c, bytes32 src_pk, bytes32 dst_pk) → bytes128 | 60,000 |
0x15 | fhe_verify_ct | (bytes128 c, bytes32 pk) → bool | 5,000 |
On Aster Chain, FHE operations use the pGas model (privacy gas, priced separately from compute gas). pGas costs are 10–50× lower than L1 due to native hardware acceleration:
| Operation | L1 Gas | Aster pGas |
|---|---|---|
fhe_encrypt | 50,000 | 5,000 |
fhe_add | 8,000 | 400 |
fhe_mul | 120,000 | 8,000 |
fhe_cmp | 90,000 | 6,000 |
fhe_decrypt_auth | 200,000 | 15,000 |
Ciphertext Representation
ERC-8227 standardizes ciphertexts as BFV (Brakerski-Fan-Vercauteren) scheme ciphertexts over a 128-bit packed plaintext space:
bytes128 ciphertext = [
bytes64 c0, // RLWE component A
bytes64 c1, // RLWE component B
]
Parameters:
- Polynomial degree: n = 4096
- Ciphertext modulus: q = 2^109
- Plaintext modulus: t = 2^64
- Security level: 128-bit classical
The 128-byte ciphertext representation is fixed for ERC-8227 v1. Future versions may support larger parameter sets via an extension byte.
Threshold Decryption Protocol
Decryption requires threshold participation from the network. The reveal statement in Covenant triggers this automatically:
action claim_salary(employee: address) only employer {
reveal salary[employee] to employee
}
Compiles to:
- Emit
DecryptionRequest(ciphertext, employee, block.number + 50)event - Validators independently partial-decrypt using their key shares
- When threshold reached (3/5 by default on Aster), combine shares into plaintext
- Deliver plaintext to
employeevia callback
The threshold is configurable at the network level. On Ethereum L1, decryption requires a separate transaction from the recipient after a challenge period.
Security Guarantees
- IND-CPA security: An adversary who sees only ciphertexts cannot determine underlying values
- Circuit privacy: The operations performed on encrypted data are not leaked by the output ciphertext
- Semantic security: Two encryptions of the same plaintext produce computationally indistinguishable ciphertexts
Not provided by ERC-8227:
- IND-CCA security (ciphertexts are malleable by design — this is a property of FHE)
- Protection against the network’s threshold validators colluding (requires honest majority assumption)
- Confidentiality of access patterns (who is calling which function is still visible)
Known Limitations
- Multiplication depth: BFV supports bounded multiplication depth (~10 before bootstrapping). Contracts that require deep polynomial circuits should use
@prove_offchain(ERC-8229) instead. - No FHE comparison branching:
if (encrypted_balance > 1000)cannot be used — comparisons return encrypted booleans, not plaintext. Usefhe_cmpand handle via encrypted conditional. - Integer overflow: FHE arithmetic is modular. Contracts must ensure values stay within
[0, 2^64). - Ciphertext size: Each encrypted
uint256uses 128 bytes of storage instead of 32 bytes. Factor this into storage cost.
Minimal ERC-8227 Interface (ABI)
{
"name": "IConfidentialToken",
"functions": [
{ "name": "encryptedBalanceOf", "inputs": [{"name":"account","type":"address"}], "outputs": [{"name":"","type":"bytes128"}] },
{ "name": "confidentialTransfer", "inputs": [{"name":"to","type":"address"},{"name":"encAmount","type":"bytes128"}], "outputs": [{"name":"","type":"bool"}] },
{ "name": "confidentialApprove", "inputs": [{"name":"spender","type":"address"},{"name":"encAmount","type":"bytes128"}], "outputs": [] },
{ "name": "requestDecrypt", "inputs": [{"name":"account","type":"address"}], "outputs": [] }
],
"events": [
{ "name": "ConfidentialTransfer", "inputs": [{"name":"from","type":"address","indexed":true},{"name":"to","type":"address","indexed":true}] },
{ "name": "DecryptionRequest", "inputs": [{"name":"account","type":"address","indexed":true},{"name":"ciphertext","type":"bytes128"},{"name":"deadline","type":"uint256"}] }
]
}
Note: ConfidentialTransfer intentionally omits the amount — emitting an encrypted amount would leak the transfer amount to validators during event indexing.