Expand description
Circuit builder for fully homomorphic encryption (FHE) programs.
This crate exposes the Builder type, a high-level interface for constructing FHE
circuits as intermediate representation (IR) graphs. A circuit takes encrypted and plaintext
integer inputs, applies arithmetic operations and programmable bootstrapping (PBS) lookups
on individual blocks, and produces encrypted outputs.
The four value types — Ciphertext, CiphertextBlock, Plaintext, and
PlaintextBlock — are opaque handles into the IR graph. They cannot be inspected
directly; instead, they are passed to Builder methods that emit the corresponding IR
instructions.
§Radix Decomposition
Large encrypted integers are represented using a radix decomposition: an integer of
int_size message bits is split into int_size / message_size blocks, each carrying
message_size bits of payload. For example, with
message_size = 2, an 8-bit integer is decomposed into 4 blocks, each encoding a
base-4 digit.
Each CiphertextBlock also reserves carry_size extra bits above the message to
absorb carries from arithmetic operations. A programmable bootstrapping (PBS) lookup
can then be used to propagate carries and extract the message, restoring the block to a
canonical state. The bit layout of a block, from MSB to LSB, is:
┌─────────┬────────────┬─────────┐
│ padding │ carry │ message │
│ (1 bit) │ (c bits) │ (m bits)│
└─────────┴────────────┴─────────┘
MSB LSBThe CiphertextBlockSpec captures the (carry_size, message_size) pair and is shared
by every block in a circuit. Plaintext blocks follow the same radix but have no carry or
padding bits — only the message_size message bits.
All block-level operations (block_* methods) work on individual blocks, while
multi-block integers must first be split into their radix
digits and later joined back.
§Operation Flavors
Depending on the integer-level operation being implemented, different flavors of block-level arithmetic may be needed:
- The user may want to protect the padding bit, ensuring a swift (non-negacyclic) lookup in PBSes.
- The user may want to set the padding bit, when executing a negacyclic lookup.
- The user may want to rely on the overflow/underflow of the whole block, to implement signed integer semantics for instance.
To accommodate these use cases, block-level operations come in three flavors:
protect— operand padding bits must be zero, and the result must not overflow into the padding bit. This is the default and most common flavor.temper— operand padding bits may be arbitrary, but the result must not overflow/underflow past the padding bit.wrapping— operand padding bits may be arbitrary, and overflow/underflow is unrestricted. Similar to Rust’swrapping_add/wrapping_subon integers.
Unless explicited in their name, Builder arithmetic methods use the protect flavor.
Methods that use a different flavor are explicitly marked (e.g.
block_wrapping_add_plaintext).
§Typical Workflow
// 1. Create a builder for a given block spec.
let builder = Builder::new(CiphertextBlockSpec(2, 2));
// 2. Declare circuit inputs.
let a = builder.ciphertext_input(8);
let b = builder.ciphertext_input(8);
// 3. Decompose into blocks and operate.
let a_blocks = builder.ciphertext_split(&a);
let b_blocks = builder.ciphertext_split(&b);
let sum_blocks: Vec<_> = a_blocks.iter().zip(b_blocks.iter())
.map(|(ab, bb)| builder.block_add(ab, bb))
.collect();
// 4. Reassemble and declare the output.
let result = builder.ciphertext_join(&sum_blocks, None);
builder.ciphertext_output(&result);
// 5. Finalize — this runs dead-code elimination and CSE.
let ir = builder.into_ir();Structs§
- Builder
- High-level builder for constructing FHE circuits as IR graphs.
- Ciphertext
- An opaque handle to a multi-block encrypted integer in the IR graph.
- Ciphertext
Block - An opaque handle to a single encrypted block (radix digit) in the IR graph.
- Ciphertext
Block Spec - Specification for the bit layout of a single ciphertext block.
- Ciphertext
Spec - Specification for a multi-block radix ciphertext representing a large integer.
- Plaintext
- An opaque handle to a multi-block plaintext integer in the IR graph.
- Plaintext
Block - An opaque handle to a single plaintext block (radix digit) in the IR graph.
Enums§
- BitType
- BwKind
- The kind of bitwise operation to apply block-wise.
- CmpKind
- The comparison relation to evaluate between two encrypted integers.
- Extension
Behavior - Strategy for handling mismatched slice lengths in binary vector operations.
- Propagation
Direction - Type
- A circuit I/O type, either encrypted or plaintext.
Functions§
- add
- Creates an IR for the addition of two encrypted integers.
- bitwise_
and - Creates an IR for bitwise AND of two encrypted integers.
- bitwise_
or - Creates an IR for bitwise OR of two encrypted integers.
- bitwise_
xor - Creates an IR for bitwise XOR of two encrypted integers.
- cmp_eq
- Creates an IR for an equality comparison of two encrypted integers.
- cmp_gt
- Creates an IR for a greater-than comparison of two encrypted integers.
- cmp_gte
- Creates an IR for a greater-or-equal comparison of two encrypted integers.
- cmp_lt
- Creates an IR for a less-than comparison of two encrypted integers.
- cmp_lte
- Creates an IR for a less-or-equal comparison of two encrypted integers.
- cmp_neq
- Creates an IR for an inequality comparison of two encrypted integers.
- count_0
- Creates an IR that counts the number of zero bits in an encrypted integer.
- count_1
- Creates an IR that counts the number of one bits in an encrypted integer.
- if_
then_ else - Creates an IR for a conditional select between two encrypted integers.
- if_
then_ zero - Creates an IR for a conditional zeroing of an encrypted integer.
- ilog2
- lead0
- lead1
- mul_lsb
- Creates an IR for a multiplication of two encrypted integers.
- overflow_
mul_ lsb - Creates an IR for a multiplication of two encrypted integers.
- trail0
- trail1