How Secret Sharing Works
When you call.to_arcis() on encrypted data, it does not decrypt the data. Instead, it converts the ciphertext into secret shares distributed across ARX nodes (Arcium’s MPC execution nodes).
Think of it like splitting a secret number into random pieces:
Security guarantee: All ARX nodes would need to collude together to reconstruct the secret. As long as even one node refuses to participate, the secret remains protected.
The Circuit is Compiled Once
Here’s the crucial insight: your Arcis code compiles into a fixed circuit structure before any data flows through it. The circuit structure—which operations happen, in what order, how many times—is locked in at compile time. Secret data flows through this fixed structure at runtime. This is the root cause of all Arcis constraints. If the circuit structure could change based on secret data, observers could learn information by watching how the computation runs, not just what it outputs.Both Branches Always Execute
In normal code,if/else picks one branch to run:
.to_arcis(), no individual node knows the actual value—each holds a random-looking share. The condition is_large is itself secret-shared, meaning no node can determine which branch “should” execute. The MPC protocol executes both branches, then uses the secret condition to select which result to keep—without revealing which branch applied.
The rule: If a condition is not a compile-time constant, Arcis executes both branches. This includes:
- Conditions derived from secret data (via
.to_arcis()) - Conditions using public runtime parameters
if true { ... } or if CONST > 5 { ... } allow single-branch execution because the value is known during circuit compilation.
Compile-time constant: A value the Arcis compiler can determine before circuit generation—literals like
10, const declarations, or expressions involving only constants. Values from function parameters or .to_arcis() results are NOT compile-time constants.Fixed Iteration Counts
Loops must have iteration counts known at compile time:while loops? The number of iterations would depend on secret data:
- Secret starts at 10 → 90 iterations → takes X time
- Secret starts at 99 → 1 iteration → takes X/90 time
break or continue? Same reason—early exit based on secret data reveals information:
Fixed-Size Data Only
Variable-length types likeVec, String, and HashMap are not supported:
Vec that might hold 10 or 10,000 elements would create a circuit of unknown size.
Reveal and Encryption Placement
The.reveal() and .from_arcis() methods cannot be called inside if/else blocks when the condition is not a compile-time constant:
.reveal() broadcasts data to all parties—a global side effect that cannot be undone during the merge. If reveal happened inside a branch, it would leak which branch was taken.
The same applies to .from_arcis():
Dynamic Indexing is O(n)
When the index is known at compile time, array access is O(1):Cost Model
Not all operations are equal in MPC. Here’s a practical cost ranking:| Operation | Relative Cost | Notes |
|---|---|---|
| Addition, subtraction | Nearly free | Local computation on shares |
| Multiplication by constant | Nearly free | Local computation |
| Multiplication | Cheap | Optimized via preprocessing |
Comparisons (<, >, ==) | Expensive | Bit-by-bit operations |
| Division, modulo by power of 2 | Expensive | Bit shift operations |
| Division, modulo (general) | Very expensive | Iterative algorithms |
| Dynamic array indexing | O(n) | Must check all positions |
| Sorting | O(n·log²(n)·bit_size) | Fixed comparison pattern |
Rust Patterns That Need Adjustment
Arcis is Rust, but some common patterns need adaptation:| Standard Rust | Arcis Equivalent | Why |
|---|---|---|
Vec<T> | [T; N] | Fixed size required |
String | [u8; N] | Fixed size required |
while condition { } | for i in 0..MAX { } | Fixed iterations |
match | Nested if/else | match not supported yet |
break, continue, return | Restructure logic | No early exit |
.filter() | Manual loop with conditional | Would produce variable length |
HashMap | Arrays with manual lookup | Fixed size required |
Syntax Constraints
A few syntax rules to keep in mind:if,else, andelse ifall work normally — but remember: when the condition is not a compile-time constant, both branches execute (MPC cost = sum of all branches).reveal()and.from_arcis()cannot be called insideif/elseblocks when the condition is not a compile-time constant — if the condition is a compile-time constant (likeif true), only one branch runs and reveal is allowed inside- No
match: Useif/elsechains instead - No early
return: Functions must have a single exit point - No
while,loop,break,continue: Useforloops with fixed bounds - Enums: Not supported yet
What You Learned
- Secret sharing splits data across nodes — no single node sees the actual value
- Circuits are fixed at compile time — structure cannot depend on secret data
- Both branches execute — MPC cost is the sum, not max
- Loops need fixed bounds — no
while,break, orcontinue - Use fixed-size types —
[T; N]instead ofVec<T> - Reveal outside conditionals —
.reveal()and.from_arcis()are global operations - Dynamic indexing is O(n) — the circuit checks all positions
- Comparisons are expensive — additions and multiplications are cheap
What’s Next?
Now that you understand the mental model:Types
Supported types including integers, arrays, and encrypted types.
Input/Output
Working with
Enc<Owner, T> for encrypted data.Operations
Complete operation support matrix.
Quick Reference
Concise syntax lookup while coding.