NssMPC Library Tutorial - 3-Party Computation with Replicated Secret Sharing
Overview
NssMPC supports both Honest Majority (HONEST_MAJORITY) and Semi-Honest (SEMI_HONEST) security models for three-party replicated secret sharing. In three-party replicated secret sharing, secrets are divided into three parts, with each participant holding one part. No single part contains enough information to recover the secret. To reconstruct the original secret, at least two participants must cooperate and combine their shares.
Prerequisites
from nssmpc import Party3PC, PartyRuntime, HONEST_MAJORITY, SEMI_HONEST, SecretTensor
from nssmpc.config.configs import DEVICE
import torch
Security Models
Honest Majority (HONEST_MAJORITY)
- Assumes at least 2 out of 3 parties are honest
- Provides stronger security guarantees
- Can tolerate one malicious party
Semi-Honest (SEMI_HONEST)
- All parties follow the protocol but may try to learn information from messages
- Weaker security but often more efficient
- Cannot tolerate malicious behavior
Party Initialization
Important: Separate Execution
Each party must run in a completely separate Python process/script. You cannot initialize multiple parties in the same file. This is crucial for maintaining security isolation and proper network communication.
Party 0 Setup - Honest Majority Mode (Separate File)
# File: party0_honest.py
# Party 0 - Data Owner/Initiator in Honest Majority mode
party = Party3PC(0, HONEST_MAJORITY)
with PartyRuntime(party0):
party.online() # Establish connections with P1 and P2
# All secret sharing operations go here
# ... rest of party0's code
Party 0 Setup - Semi-Honest Mode (Separate File)
# File: party0_semi.py
# Party 0 - Data Owner/Initiator in Semi-Honest mode
party = Party3PC(0, SEMI_HONEST)
with PartyRuntime(party0):
party.online() # Establish connections with P1 and P2
# All secret sharing operations go here
# ... rest of party0's code
Party 1 Setup (Separate File)
# File: party1.py
# Party 1 - Computation Participant
# Must use the SAME mode as party0
party = Party3PC(1, HONEST_MAJORITY) # or SEMI_HONEST
with PartyRuntime(party1):
party.online() # Establish connections with P0 and P2
# All secret sharing operations go here
# ... rest of party1's code
Party 2 Setup (Separate File)
# File: party2.py
# Party 2 - Computation Participant
# Must use the SAME mode as other parties
party = Party3PC(2, HONEST_MAJORITY) # or SEMI_HONEST
with PartyRuntime(party2):
party.online() # Establish connections with P0 and P1
# All secret sharing operations go here
# ... rest of party2's code
Important: All three parties must use the same security mode (either all HONEST_MAJORITY or all SEMI_HONEST).
Important Note: Runtime Context
All replicated secret sharing operations must be performed within the PartyRuntime context manager. This ensures proper resource management, network communication, and synchronization between all three parties.
Basic Operations
1. Secret Sharing and Reconstruction
Party 0: Creating and Sharing Secrets (Both Modes)
# File: party0.py (can be either honest or semi-honest mode)
with PartyRuntime(party):
party.online()
# Create local tensors (only party0 has the original data)
x = torch.tensor([1.1, 1.1, 1.3], device=DEVICE)
y = torch.tensor([1.2, 1.1, 2.3], device=DEVICE)
# Convert to secret-shared tensors (automatically shares with P1 and P2)
share_x = SecretTensor(tensor=x)
share_y = SecretTensor(tensor=y)
# Reconstruction example
reconstructed_x = share_x.recon(target_id=0).convert_to_real_field()
print("Reconstructed x:", reconstructed_x)
Party 1: Receiving and Working with Shares
# File: party1.py (must match party0's mode)
with PartyRuntime(party):
party.online()
# Receive secret shares (automatically handled by SecretTensor)
share_x = SecretTensor(src_id=0) # Shares from party 0
share_y = SecretTensor(src_id=0)
# Participate in reconstruction
reconstructed_x = share_x.recon(target_id=0).convert_to_real_field()
print("Reconstructed x:", reconstructed_x)
Party 2: Receiving and Working with Shares
# File: party2.py (must match party0's mode)
with PartyRuntime(party):
party.online()
# Receive secret shares
share_x = SecretTensor(src_id=0) # Shares from party 0
share_y = SecretTensor(src_id=0)
# Participate in reconstruction
reconstructed_x = share_x.recon(target_id=0).convert_to_real_field()
print("Reconstructed x:", reconstructed_x)
2. Arithmetic Operations (Same for Both Modes)
All three parties execute the same operations within their own runtime contexts:
# In each party's separate file (party0.py, party1.py, party2.py)
with PartyRuntime(party):
# Addition
share_z = share_x + share_y
result = share_z.recon().convert_to_real_field()
print("x + y:", result)
# Element-wise Multiplication
share_z = share_x * share_y
result = share_z.recon().convert_to_real_field()
print("x * y:", result)
# Matrix Multiplication (if x and y are matrices)
share_z = share_x @ share_y
result = share_z.recon().convert_to_real_field()
print("x @ y:", result)
3. Comparison Operations (Same for Both Modes)
# In each party's separate file
with PartyRuntime(party):
# Equality check
share_z = share_x == share_y
result = share_z.recon().convert_to_real_field()
print("x == y:", result)
# Greater than or equal
share_z = share_x >= share_y
result = share_z.recon().convert_to_real_field()
print("x >= y:", result)
# Less than or equal
share_z = share_x <= share_y
result = share_z.recon().convert_to_real_field()
print("x <= y:", result)
# Strictly greater than
share_z = share_x > share_y
result = share_z.recon().convert_to_real_field()
print("x > y:", result)
# Strictly less than
share_z = share_x < share_y
result = share_z.recon().convert_to_real_field()
print("x < y:", result)
4. Advanced Mathematical Functions (Same for Both Modes)
# In each party's separate file
with PartyRuntime(party):
# Division
share_z = share_x / share_y
result = share_z.recon().convert_to_real_field()
print("x / y:", result)
# Exponential function
share_z = share_x.exp()
result = share_z.recon().convert_to_real_field()
print("exp(x):", result)
# Inverse square root
share_z = share_y.rsqrt()
result = share_z.recon().convert_to_real_field()
print("rsqrt(y):", result)
# Summation along dimension
share_z = share_x.sum(dim=-1)
result = share_z.recon().convert_to_real_field()
print("sum(x, dim=-1):", result)
Key Points to Remember
-
Separate Execution is Mandatory: Each party must run in its own separate Python process/script file. Never initialize multiple parties in the same file.
-
Consistent Security Mode: All three parties must use the same security mode (either all
HONEST_MAJORITYor allSEMI_HONEST). -
Runtime Context Required: All operations must be performed within the
with PartyRuntime(party):block. -
Synchronization: All three parties must execute corresponding operations in the same order and within their respective runtime contexts.
-
Field Conversion: Use
.convert_to_real_field()after.recon()to get plaintext results. -
Security Mode Differences:
HONEST_MAJORITY: Can tolerate one malicious party, slightly more overheadSEMI_HONEST: More efficient, but all parties must follow protocol
Complete Example Structure
party0_honest.py (Semi-Honest Mode)
# File: party0_honest.py - MUST be run separately
from nssmpc import Party3PC, PartyRuntime, HONEST_MAJORITY, SecretTensor
import torch
# Initialize ONLY party0 in Honest Majority mode
party = Party3PC(0, HONEST_MAJORITY)
with PartyRuntime(party):
party.online()
# Only party0 creates the original data
x = torch.tensor([1.1, 1.1, 1.3])
share_x = SecretTensor(tensor=x)
# Perform computations
share_z = share_x + share_x
result = share_z.recon().convert_to_real_field()
print("Party 0 (Honest) Result:", result)
party0_semi.py (Semi-Honest Mode)
# File: party0_semi.py - MUST be run separately
from nssmpc import Party3PC, PartyRuntime, SEMI_HONEST, SecretTensor
import torch
# Initialize ONLY party0 in Semi-Honest mode
party0 = Party3PC(0, SEMI_HONEST)
with PartyRuntime(party):
party.online()
# Only party0 creates the original data
x = torch.tensor([1.1, 1.1, 1.3])
share_x = SecretTensor(tensor=x)
# Perform computations
share_z = share_x + share_x
result = share_z.recon().convert_to_real_field()
print("Party 0 (Semi-Honest) Result:", result)
party1.py (Matching Mode)
# File: party1.py - MUST be run separately
# Must match party0's mode (either HONEST_MAJORITY or SEMI_HONEST)
from nssmpc import Party3PC, PartyRuntime, HONEST_MAJORITY, SecretTensor
# Initialize ONLY party1 in SAME mode as party0
party = Party3PC(1, HONEST_MAJORITY) # or SEMI_HONEST
with PartyRuntime(party):
party.online()
# Receive shares from party0
share_x = SecretTensor(src_id=0)
# Perform SAME computations as party0
share_z = share_x + share_x
result = share_z.recon().convert_to_real_field()
print("Party 1 Result:", result)
party2.py (Matching Mode)
# File: party2.py - MUST be run separately
from nssmpc import Party3PC, PartyRuntime, HONEST_MAJORITY, SecretTensor
# Initialize ONLY party2 in SAME mode as other parties
party = Party3PC(2, HONEST_MAJORITY) # or SEMI_HONEST
with PartyRuntime(party):
party.online()
# Receive shares from party0
share_x = SecretTensor(src_id=0)
# Perform SAME computations as other parties
share_z = share_x + share_x
result = share_z.recon().convert_to_real_field()
print("Party 2 Result:", result)
Execution Instructions
For Honest Majority Mode:
- Open three separate terminal windows
- In Terminal 1: Run
python party0_honest.py - In Terminal 2: Run
python party1.py(withHONEST_MAJORITY) - In Terminal 3: Run
python party2.py(withHONEST_MAJORITY)
For Semi-Honest Mode:
- Open three separate terminal windows
- In Terminal 1: Run
python party0_semi.py - In Terminal 2: Run
python party1.py(withSEMI_HONEST) - In Terminal 3: Run
python party2.py(withSEMI_HONEST)
Error Handling
- Ensure all three parties use the same security mode
- Each party must be in its own separate process
- All operations must be within
PartyRuntimecontext - Verify network connectivity between all parties
Performance Considerations
SEMI_HONESTmode is generally more efficient thanHONEST_MAJORITY- Communication overhead is higher with three parties
- Batch operations to reduce round complexity
- Honest Majority provides stronger security at the cost of some efficiency
Choose HONEST_MAJORITY when you need to tolerate one malicious party, or SEMI_HONEST when you prioritize efficiency and trust all parties to follow the protocol.