Overview
The Halo Cross-Media Measurement System uses advanced cryptographic protocols to enable secure computation over encrypted data. This page describes the cryptographic building blocks, key management, encryption schemes, and protocol phases that make privacy-preserving measurement possible.All cryptographic operations are implemented in C++ for performance, with Java JNI wrappers for integration with the Kotlin codebase.
Cryptographic Primitives
The system relies on several fundamental cryptographic components:Elliptic Curve Cryptography
All public-key operations use elliptic curves over finite fields:- Curve Selection
- Point Operations
The system typically uses NIST P-256 (secp256r1):
- 256-bit security level
- Widely supported and standardized
- Efficient implementations available
- Suitable for ElGamal encryption
ElGamal Encryption
ElGamal is the primary encryption scheme used throughout the protocol:Key Generation
Each Duchy generates an ElGamal key pair:Encryption
To encrypt a messagem (represented as a curve point M):
Decryption
With private keyx:
Homomorphic Properties
ElGamal is additively homomorphic:Implementation: The
ProtocolCryptor class (src/main/cc/wfa/measurement/common/crypto/protocol_cryptor.h) provides methods for encryption, decryption, and homomorphic operations.Pohlig-Hellman Cipher
A deterministic encryption scheme used for blinding operations:- Each Duchy maintains a local Pohlig-Hellman private key
- Used during the “blind” operation: decrypt one layer of ElGamal, encrypt with Pohlig-Hellman
- Enables shuffling while maintaining unlinkability
- Deterministic (same plaintext → same ciphertext with same key)
- Used temporarily during protocol execution
- Removed in later stages via decryption
Key Management
The system employs a sophisticated multi-key encryption scheme:Composite Public Key
Publishers encrypt data using a composite public key formed from all Duchy public keys:Duchy Key Generation
Each Duchy
i generates:- ElGamal private key:
xᵢ - ElGamal public key:
Yᵢ = xᵢ · G
Key Aggregation
The Kingdom combines public keys:This is a single curve point representing the combined public key.
Publisher Encryption
Publishers encrypt sketches using the composite key:
- Encryption with composite key = encryption under all Duchy keys simultaneously
- Requires all Duchies to partially decrypt
Partial vs. Full Composite Keys
The system uses two types of composite keys:| Key Type | Composition | Use Case |
|---|---|---|
| Full Composite | All Duchy public keys | Initial publisher encryption |
| Partial Composite | Subset of Duchy keys | Re-encryption during protocol |
Key Storage and Security
Protocol Cryptographic Operations
The MPC protocol consists of multiple phases, each using specific cryptographic operations:Initialization Phase
Key Exchange
Key Exchange
Purpose: Establish cryptographic keys for the computationOperations:
- Each Duchy generates a fresh ElGamal key pair
- Public keys are sent to the Kingdom
- Kingdom computes and distributes the composite public key
- Publishers fetch the composite key to encrypt their sketches
Setup Phase
Noise Addition and Aggregation
Noise Addition and Aggregation
Purpose: Combine publisher sketches and add distributed noiseOperations:Non-Aggregator Duchies:
- Retrieve local fulfilled requisitions (encrypted sketches)
- Add distributed differential privacy noise:
- Generate random noise registers
- Encrypt noise values using composite key
- Combine with publisher sketches
- Send noised Combined Register Vector (CRV) to aggregator
- Collect CRVs from all non-aggregator Duchies
- Add its own noise to its local CRV
- Merge all CRVs into a global CRV:
- For each register index, collect all (key, count) tuples
- Result is a multi-set of encrypted tuples per register
EncryptCompositeElGamal(): Encrypt noise values- Homomorphic addition: Combine encrypted sketches
Execution Phase One: Shuffle and Join
Shuffling
Shuffling
Purpose: Destroy positional information to prevent linkingNon-Aggregator Duchies:
- Blind operation on each register:
- Re-randomize other ciphertext components
- Apply random permutation to register order
- Send shuffled CRV to next Duchy in the ring
- Receives shuffled CRV from last non-aggregator
- Performs Same Key Aggregation (SKA):
- Group registers by their (blinded) key values
- Combine counts for matching keys using homomorphic addition
- Result: One (flag, count) tuple per unique user
- Add additional noise for differential privacy
Blind(): ElGamal decrypt + Pohlig-Hellman encryptReRandomize(): Add encryption of zero to hide previous randomness- Shuffle: Cryptographically secure permutation
Same Key Aggregation (SKA)
Same Key Aggregation (SKA)
Purpose: Join encrypted keys representing the same userHow it works:
- Encrypted keys have been blinded (deterministically encrypted)
- Identical plaintext keys → identical blinded ciphertexts
- Group by blinded key value (possible because deterministic)
- For each group:
- Combine counts:
Σ Count_i(using homomorphic addition) - Create flag value indicating group size
- Combine counts:
- Re-encrypt everything for next phase
- Uses ElGamal homomorphism:
Enc(a) + Enc(b) = Enc(a + b) - Destructors identify registers to discard vs. preserve
- See “Privacy-Preserving Secure Cardinality” research paper for details
Execution Phase Two: Decrypt Flags
Partial Decryption Round
Partial Decryption Round
Purpose: Decrypt flag values to identify valid vs. noise registersAll Duchies (in ring order):
- Receive flag-count tuples from previous Duchy
- Partial decrypt flag values:
- Pass partially decrypted data to next Duchy
- Completes final decryption of flags
- Filters out differential privacy noise registers
- Estimates reach from remaining valid registers
- Constructs 2-D frequency matrix from count values (still encrypted)
DecryptLocalElGamal(): Partial decryption with local private keyIsDecryptLocalElGamalResultZero(): Check if decrypted value is identity element
Execution Phase Three: Decrypt Counts
Frequency Decryption
Frequency Decryption
Purpose: Decrypt count values to compute frequency distributionAll Duchies (in ring order):
- Receive 2-D frequency matrix (counts still encrypted)
- Partial decrypt count values using local private key
- Pass to next Duchy
- Completes decryption of all count values
- Aggregates frequency distribution:
- Applies final differential privacy noise to frequency estimates
- Returns reach and frequency results to Kingdom
DecryptLocalElGamal(): Partial decryption- Frequency aggregation: Summing counts at each frequency level
Cryptographic Implementation
The core cryptography is implemented in C++ with JNI wrappers:C++ Cryptography Library
Key files insrc/main/cc/wfa/measurement/common/crypto/:
protocol_cryptor.h: Main interface for cryptographic operations- Encryption/decryption methods
- Blinding and re-randomization
- Batch processing for performance
ec_point_util.h: Elliptic curve point operations- Point addition and scalar multiplication
- Serialization and deserialization
- Hashing to curve
encryption_utility_helper.h: Helper functions for Liquid Legions- Extract key-count pairs from encrypted registers
- Write encrypted values to byte strings
- Batch encryption operations
Protocol Cryptor Interface
TheProtocolCryptor class provides these key methods:
ProtocolCryptor instances are NOT thread-safe. For parallel processing, create multiple independent instances using CreateIdenticalProtocolCryptors().
JNI Wrappers
The C++ library is wrapped for use in Kotlin/Java:- SWIG definitions:
src/main/swig/protocol/liquidlegionsv2/ - Generated wrappers: Auto-generated Java classes with JNI bindings
- Usage: Called from Kotlin mill job implementations
src/main/swig/protocol/liquidlegionsv2/README.md for build instructions.
Liquid Legions V2 Protocol
The primary protocol implementation is Liquid Legions V2:Protocol Stages
Defined inliquid_legions_sketch_aggregation_v2.proto:
INITIALIZATION_PHASE: Key generationWAIT_REQUISITIONS_AND_KEY_SET: Waiting for data and keysCONFIRMATION_PHASE: Validate signatures and keysWAIT_TO_START/WAIT_SETUP_PHASE_INPUTS: SynchronizationSETUP_PHASE: Noise addition and aggregationEXECUTION_PHASE_ONE: Shuffle and joinEXECUTION_PHASE_TWO: Decrypt flags and estimate reachEXECUTION_PHASE_THREE: Decrypt counts and compute frequencyCOMPLETE: Final results returned
Encryption Methods
Specific encryption operations are defined in:liquid_legions_v2_encryption_methods.proto: Standard Liquid Legions V2reach_only_liquid_legions_v2_encryption_methods.proto: Optimized reach-only variant
Alternative Protocols
Other protocols are also implemented:- Honest Majority Share Shuffle: Alternative MPC protocol with different trust assumptions
- Reach-Only Liquid Legions V2: Optimized version when only reach (not frequency) is needed
Security Considerations
Cryptographic Assumptions
The security of the system relies on:- Discrete Logarithm Problem (DLP): Hard to compute
xfromx · G - Decisional Diffie-Hellman (DDH): ElGamal semantic security
- Elliptic Curve Security: Chosen curve provides adequate security level
- Random Number Generation: Secure RNG for key generation and randomization
Post-Quantum Considerations
Future-proofing: Current elliptic curve cryptography is vulnerable to quantum computers. Migrating to post-quantum secure primitives (e.g., lattice-based encryption) may be necessary as quantum computing advances.
Research References
The cryptographic protocols are detailed in:System Design Paper
High-level architecture and security model
Cardinality Estimation
Detailed cryptographic protocol specifications
Next Steps
Secure Computation
Understand how Duchies orchestrate the cryptographic protocol
Sketches
Learn about the data structures that are encrypted and processed