PRD: MPC Preprocessing Configuration
Status: Ready for Review Author: Claude Code Created: 2026-01-12 Related PRs: stoffel-rust-sdk#1Executive Summary
This PRD defines requirements for MPC preprocessing configuration across the Stoffel stack (CLI, Rust SDK, and future SDKs). The goal is to provide a consistent, user-friendly, and safe way to configure Beaver triples and random shares for HoneyBadger MPC preprocessing.Problem Statement
Current State
-
Rust SDK: Has hardcoded defaults (
n_triples=10,n_random_shares=20) that are arbitrary and may cause silent runtime failures if insufficient for the program being executed. -
CLI: Supports MPC parameters (
--parties,--threshold,--protocol,--field) but has no preprocessing configuration. Preprocessing values are only hardcoded in generated templates. -
Configuration Gap: No way to persist preprocessing settings in
Stoffel.tomlor pass them via CLI flags.
Consequences
- Silent failures: Programs run out of preprocessing material mid-execution
- Inconsistent UX: Users must manually edit generated code to change preprocessing
- No guidance: Users don’t know what values to use for their workload
- Poor defaults: Arbitrary values don’t scale with threshold or program complexity
Goals
| Goal | Description | Priority |
|---|---|---|
| Safety | Prevent silent runtime failures from insufficient preprocessing | P0 |
| Usability | Provide sensible defaults with clear override mechanisms | P0 |
| Consistency | Unified configuration across CLI, SDK, and config files | P1 |
| Flexibility | Support minimal testing through production workloads | P1 |
| Education | Help users understand preprocessing requirements | P2 |
Non-Goals
- Dynamic preprocessing replenishment during execution (protocol limitation)
- Support for protocols other than HoneyBadger (only protocol currently)
User Stories
US1: App Developer (Client-side)
As an app developer using StoffelClient, I don’t want to think about preprocessing at all. The servers I connect to should handle it.
Requirement: Client API requires no preprocessing configuration.
US2: Infrastructure Operator (Server-side, Development)
As an infrastructure operator setting up a dev/test MPC network, I want quick defaults that work for simple programs without configuration.Requirement: Named presets like
--preprocessing=minimal or .with_minimal_preprocessing().
US3: Infrastructure Operator (Server-side, Production)
As an infrastructure operator running production MPC servers, I need explicit control over preprocessing to match my workload and avoid resource waste.Requirement: Explicit configuration via
--beaver-triples=N --random-shares=M or .with_preprocessing(n, m).
US4: Project Maintainer
As a project maintainer, I want preprocessing settings persisted in Stoffel.toml so my team uses consistent values.
Requirement: Configuration file support with CLI override capability.
US5: New User
As a new user, I want clear errors if I misconfigure preprocessing, not silent failures during computation.Requirement: Validation at build/startup time with actionable error messages.
Technical Requirements
TR1: Preprocessing Parameters
| Parameter | Type | Description | Constraints |
|---|---|---|---|
n_triples | usize | Beaver triples for secure multiplication | > 0, typically ≥ 2t+1 |
n_random_shares | usize | Random shares for input masking | > 0, typically ≥ 2 + 2*n_triples |
TR2: Program-Aware Bytecode Analysis (Primary Approach)
The SDK automatically analyzes compiled bytecode to determine preprocessing requirements: Analysis Algorithm:- Automatically when
.with_program(program)is called onStoffelServerBuilder - Cached in the
Programstruct after first analysis - Can be manually triggered via
program.analyze_preprocessing()
- If user calls
.with_preprocessing(n, m)AFTER.with_program(), explicit values override analysis - If user calls
.with_preprocessing(n, m)BEFORE.with_program(), explicit values are preserved
TR3: Preprocessing Presets (Fallback/Override)
For cases where bytecode analysis isn’t available or user wants explicit control:| Preset | n_triples | n_random_shares | Use Case |
|---|---|---|---|
minimal | 2t + 1 | 2 + 2 * n_triples | Testing, simple programs |
standard | 32 | 66 | Development, moderate workloads |
production | 128 | 258 | Production, high throughput |
custom | User-specified | User-specified | Explicit control |
TR4: Configuration Hierarchy
Priority (highest to lowest):- Explicit SDK calls (
.with_preprocessing(n, m)) - CLI flags (
--beaver-triples,--random-shares,--preprocessing) - Environment variables (
STOFFEL_BEAVER_TRIPLES,STOFFEL_RANDOM_SHARES) - Project config (
Stoffel.toml→[mpc.preprocessing]) - Automatic bytecode analysis (when
.with_program()is called) - Error if no program and no explicit configuration
TR5: Validation Rules
n_triples > 0n_random_shares > 0n_random_shares >= 2 + 2 * n_triples(warning if violated, not error)- All servers in MPC network must use identical preprocessing values
Interface Design
CLI Interface
| Flag | Type | Default | Description |
|---|---|---|---|
--preprocessing | enum | None | Preset: minimal, standard, production |
--beaver-triples | int | None | Explicit Beaver triple count |
--random-shares | int | None | Explicit random share count |
- If neither preset nor explicit values provided: Error with guidance
- If only one of
--beaver-triples/--random-sharesprovided: Error (must specify both) - If preset AND explicit values: Explicit values override preset
Rust SDK Interface
Configuration File Interface
Stoffel.toml:- If
[mpc.preprocessing]section missing: Error with guidance - If
presetspecified: Calculate values from preset - If explicit values specified: Use those (override preset)
Migration & Compatibility
Breaking Changes
None expected. The new behavior is additive and backward-compatible:- SDK: Existing code with
.with_preprocessing(n, m)continues to work unchanged - SDK: Code with
.with_program()but no preprocessing now gets smart defaults (improvement) - CLI: Existing commands work; new flags are optional overrides
Behavioral Changes
- Before: Hardcoded defaults
n_triples=10, n_random_shares=20regardless of program - After: Calculated from program bytecode analysis when
.with_program()is called
Migration Path
Phase 1: Add Smart Defaults (v0.x.y)- Add bytecode analysis to
Program - Modify
with_program()to trigger analysis - Keep explicit
.with_preprocessing()working as override - Emit INFO log showing calculated values
- Remove explicit preprocessing from examples where automatic is sufficient
- Document override patterns for production use cases
- If program is provided but preprocessing is explicitly set to old defaults (10, 20), emit deprecation warning suggesting removal of explicit values
Template Updates
Update generated code instoffel init:
Error Messages
SDK Errors
When no program and no explicit preprocessing:CLI Errors
Normal operation (informational):Documentation Requirements
- CLI Reference: Document new flags in
stoffel help dev/run/test - SDK Guide: Add preprocessing section to Rust SDK documentation
- Conceptual Guide: Explain what Beaver triples and random shares are
- Migration Guide: Document upgrade path from implicit defaults
- Troubleshooting: Common errors and solutions
Testing Requirements
Unit Tests
- SDK:
Program::count_multiplications()correctly counts MUL instructions - SDK:
Program::preprocessing_requirements()calculates correct values - SDK:
with_program()triggers automatic analysis and sets defaults - SDK:
with_preprocessing()overrides automatic analysis - SDK:
with_preprocessing_preset()applies correct values - SDK: Build fails when no program AND no explicit preprocessing
- SDK: Warning emitted when user override < calculated requirements
- SDK: Validation rejects invalid values (0, negative)
Integration Tests
- CLI:
stoffel devautomatically analyzes program and displays calculated values - CLI:
--preprocessing=minimaloverrides automatic analysis - CLI:
--beaver-triplesand--random-sharesoverride automatic analysis - CLI: Config file values override automatic analysis
- CLI: Warning shown when override < calculated
- SDK: Server starts successfully with only
.with_program()(automatic analysis)
E2E Tests
- Full MPC computation succeeds with minimal preprocessing
- Full MPC computation succeeds with production preprocessing
- Computation fails gracefully when preprocessing exhausted (clear error)
Implementation Plan
Phase 1: SDK Changes (stoffel-rust-sdk)
Step 1.1: Bytecode Analysis in Program- Add
preprocessing_requirements()method toProgramstruct - Add
count_multiplications()to parse bytecode and count MUL instructions - Add
count_random_share_consumers()for other preprocessing-consuming ops - Cache analysis results in
Programstruct
- Modify
with_program()to trigger automatic analysis - Store calculated preprocessing values in builder
- Add
with_preprocessing_preset()for override with presets - Modify
with_preprocessing()to override calculated values - Add
PreprocessingPresetenum
- In
build(): If no program AND no explicit preprocessing → error - Log calculated values at INFO level for visibility
- Warn if user override is less than calculated (potential runtime failure)
src/program.rs(bytecode analysis methods)src/mpcaas/server.rs(builder integration)src/lib.rs(re-exports)src/prelude.rs(PreprocessingPreset export)examples/honeybadger_mpc_demo.rs(remove explicit preprocessing)examples/README.md(document automatic behavior)
Phase 2: CLI Changes (Stoffel)
Step 2.1: Default Behavior (Program-Aware)- When
stoffel devcompiles a program, analyze bytecode automatically - Display calculated preprocessing values in output
- Use calculated values by default for MPC execution
- Add
--preprocessingflag for presets (minimal/standard/production) - Add
--beaver-triplesand--random-sharesfor explicit override - Override flags take precedence over automatic analysis
- Extend
MpcConfigstruct with optional preprocessing section - Update
Stoffel.tomlschema to include[mpc.preprocessing] - CLI flags override config file, config file overrides automatic analysis
- Update
stoffel inittemplates to NOT specify explicit preprocessing - Add comments explaining automatic behavior
- Show how to override if needed
src/main.rs(CLI flags, program analysis integration)src/init.rs(config struct, templates)src/templates/rust/main.rs(remove hardcoded values)src/templates/stoffel.toml.template(add preprocessing section)
Phase 3: Documentation (docs)
- Add preprocessing conceptual guide
- Update CLI reference
- Update SDK reference
- Add migration guide
docs/src/cli/overview.mddocs/src/mpc-protocols/overview.md- New:
docs/src/guides/preprocessing.md
Open Questions
-
Q: Should
minimalpreset be calculated at build time or runtime?- Build time: Requires threshold to be known when calling preset method
- Runtime: More flexible but delayed validation
- Decision: Build time (fail fast)
-
Q: Should we support per-program preprocessing analysis?
- Decision: Yes, this is now the PRIMARY approach. Bytecode analysis at
.with_program()time.
- Decision: Yes, this is now the PRIMARY approach. Bytecode analysis at
-
Q: Should preprocessing be refreshable during long-running servers?
- Protocol limitation: preprocessing is done once at startup
- Decision: Out of scope. Document limitation.
-
Q: Default preset for
stoffel initgenerated projects?- Decision: Use automatic program analysis (no explicit preset needed in templates)
-
Q: Safety margin for bytecode analysis?
- Should we add extra triples beyond the counted MUL instructions?
- Options: +0 (exact), +2 (small margin), +10% (proportional)
- Decision: +2 fixed margin for safety
-
Q: How to handle loops in bytecode analysis?
- Static analysis cannot determine loop iteration count
- Options: Assume 1 iteration, require user override, emit warning
- Decision: Assume 1 iteration, emit warning suggesting explicit override for loops
Success Metrics
| Metric | Target |
|---|---|
| No silent preprocessing failures in production | 100% |
| Users understand preprocessing errors | >90% (survey) |
| Migration completed without support tickets | >95% |
| Documentation covers all use cases | 100% |
Appendix: Preprocessing Formula Derivation
Fromexternal/stoffel-vm/crates/stoffel-vm/src/tests/mpc_multiplication_integration.rs:
- Beaver triples: Need enough for worst-case multiplication depth in preprocessing
- Random shares: Need shares for each triple generation plus input masking overhead
Next Steps (Post-Approval)
- Store PRD: Move this document to
docs/rfcs/0001-preprocessing-configuration.mdon a new branch - Create Linear Issues: Create implementation issues for each phase:
- SDK: Bytecode analysis and builder integration
- CLI: Flag additions and program analysis integration
- Docs: Preprocessing guide and CLI reference updates
- Address PR #1 Comment: Update PR #1 with link to this PRD and implementation plan
- Begin Implementation: Start with Phase 1 (SDK changes) as foundation for CLI and docs