The Toeplitz module implements efficient Toeplitz matrix multiplication over GF(2) for compressing LPN outputs to 127 bits.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/octra-labs/pvac_hfhe_cpp/llms.txt
Use this file to discover all available pages before exploring further.
Main function
toep_127()
Multiplies a Toeplitz matrix by a bit vector, returning the first 127 bits.First row and column of the Toeplitz matrix, packed as 64-bit words. Length should be
(lpn_t + 127 + 63) / 64 words.Input bit vector (LPN output), packed as 64-bit words. Length should be
(lpn_t + 63) / 64 words.Output: lower 64 bits of the result
Output: upper 63 bits of the result (most significant bit should be 0)
Algorithm
A Toeplitz matrix has constant diagonals:z = T * y is computed via GF(2) convolution:
- Perform binary polynomial multiplication:
R = top ⊗ ybits - Extract bits 0-126 from R as the output
This function performs runtime dispatch to choose between scalar, PCLMUL (x86), or PMULL (ARM) implementations based on hardware capabilities.
Implementation variants
toep_127_scalar()
Portable scalar implementation.gf2_conv_scalar() for binary polynomial multiplication without hardware acceleration.
toep_127_clmul()
Hardware-accelerated implementation using Intel PCLMUL.- x86-64 architecture
- PCLMUL instruction support
- Compile with
-mpclmulor-march=native
_mm_clmulepi64_si128 intrinsic for fast carryless multiplication.
toep_127_pmull()
Hardware-accelerated implementation for ARM NEON.- ARM64 (AArch64) architecture
- Crypto extensions
- Compile with
-march=armv8-a+crypto
vmull_p64 intrinsic for polynomial multiplication.
Binary polynomial multiplication
gf2_conv_scalar()
Scalar GF(2) convolution.First polynomial (bit-packed)
Second polynomial (bit-packed)
Output: product polynomial with length
A.size() + B.size()R(x) = A(x) · B(x) in GF(2)[x] using the standard schoolbook algorithm:
- For each set bit at position
iin A - For each word in B
- XOR shifted B into R at position
i
gf2_conv_clmul()
PCLMUL-accelerated GF(2) convolution.gf2_conv_scalar(), but uses _mm_clmulepi64_si128 for 64×64→128 bit carryless multiplication.
gf2_conv_pmull()
PMULL-accelerated GF(2) convolution for ARM.gf2_conv_scalar(), but uses vmull_p64 for polynomial multiplication on ARM64.
Runtime selection
select_toeplitz()
Benchmarks available implementations and selects the fastest.toep_127(). It:
- Tests all available implementations (scalar, PCLMUL, PMULL)
- Benchmarks each on typical inputs
- Selects the fastest implementation
- Stores the selection in global variable
g_toep
The selection is cached in a global variable, so it only runs once per program execution.
Global variables
Toeplitz matrix properties
Structure
A Toeplitz matrix has the form:Universal hashing
Random Toeplitz matrices form a family of universal hash functions:- Uniformity: For random T and fixed x ≠ y, Pr[Tx = Ty] ≤ 2^(-127)
- Compression: Maps
lpn_tbits (16384) to 127 bits - Efficiency: Computable via fast convolution
Security role
In PVAC-HFHE, Toeplitz hashing serves as a randomness extractor:- LPN outputs
lpn_t = 16384bits with ~11000 bits min-entropy - Toeplitz extraction produces 127 nearly-uniform bits
- Result is hashed to a field element via
hash_to_fp_nonzero()
Performance characteristics
Benchmarks (approximate, varies by hardware)
| Implementation | Architecture | Time per call |
|---|---|---|
| toep_127_scalar | Any | ~150 μs |
| toep_127_clmul | x86-64 + PCLMUL | ~15 μs |
| toep_127_pmull | ARM64 + Crypto | ~20 μs |
Optimization notes
- The convolution is computed over
(lpn_t + 127)bits - Only the first 127 output bits are extracted
- Sparse inputs (few set bits) benefit from early termination
- Hardware implementations use SIMD parallelism
Example usage
Implementation details
Bit extraction
After convolution, the code extracts bits 0-126:Intrinsics used
x86-64 PCLMUL:Related functions
prf_R_core()- Usestoep_127()for randomness extractionlpn_make_ybits()- Generates the input to Toeplitz hashing