Protocols
See how PLLM defines parties, messages, privacy assumptions, and failure behavior.
A protocol defines its parties, offline and online phases, inputs, outputs, messages, authentication, replay behavior, one-time material, visible information, trust assumptions, and failure behavior. Model adapters and deployment policy are separate concerns.
Start with privacy and threat models before using these implementation interfaces to select a protocol.
Current protocols include masked-linear inference and experimental garbling components. Check execution support, security review, assurance, and deployment status separately; apply the research evidence rules to any supporting records.
How methods fit into a pipeline
Protocol methods identify the message flow and trust contract for protected linear work. They do not select model ownership, preparation, placement, or kernels on their own. Start from a shipped pipeline profile when possible; constructing a method only validates that method's parameters. A typed profile binds the method to compatible preparation, role, kernel, and verification components.
API: Protocol objects and signatures
Python SDK example
The first four examples are complete experiment.py modules. Serve one through the
real trusted loopback gateway with:
pllm gateway --local \
--experiment experiment.py:experiment \
--trust-pythonSecureLinear and CleartextLinear are shown separately because no shipped typed
profile composes either into gateway or benchmark model execution.
Hide activations with MaskedLinear
MaskedLinear
uses one-time corrections prepared before chat for public transformer weights.
Online requests contact inference only; the trusted preparation role must not
collude with inference. Follow the masked-linear guide
for the complete offline and online flow.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import MaskedLinearCpu
from pllm.protocols import MaskedLinear
from pllm.sources import TinyModel
experiment = Experiment(
name="masked-method",
pipeline=MaskedLinearCpu(TinyModel(model_id="masked-tiny"), linear=MaskedLinear()),
deployment=Deployment.local(root="local://masked-method"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.client_runtime == "masked_transformer_v1"
assert resolved.requires_preparationUse encrypted transport with DirectFHE
DirectFHE sends encrypted
linear inputs through a separate runtime arm. It does not consume masked-linear
inventory and live use requires the optional HE dependency.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import DirectFHEProfile
from pllm.protocols import DirectFHE
from pllm.sources import TinyModel
experiment = Experiment(
name="direct-fhe-method",
pipeline=DirectFHEProfile(TinyModel(model_id="direct-fhe-tiny"), linear=DirectFHE()),
deployment=Deployment.local(root="local://direct-fhe-method"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.profile == "runtime.direct_fhe"
assert not resolved.requires_preparationBound clear execution with GuardedLinear
GuardedLinear configures
request and stage quotas for provider-owned weights. These controls bound use; they
do not cryptographically hide activations from the provider.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import ProprietaryGuarded
from pllm.protocols import GuardedLinear
from pllm.sources import TinyModel
experiment = Experiment(
name="guarded-method",
pipeline=ProprietaryGuarded(
TinyModel(model_id="guarded-tiny"),
linear=GuardedLinear(max_rows_per_request=8),
),
deployment=Deployment.local(root="local://guarded-method"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.proprietary_protocol == "guarded"
assert not resolved.requires_preparationBlind provider transport with BlindedLinear
BlindedLinear selects the
provider-owned blinded transport. Treat its support and leakage properties as
specific to that runtime arm rather than interchangeable with prepared masking.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import ProprietaryBlinded
from pllm.protocols import BlindedLinear
from pllm.sources import TinyModel
experiment = Experiment(
name="blinded-method",
pipeline=ProprietaryBlinded(
TinyModel(model_id="blinded-tiny"),
linear=BlindedLinear(),
),
deployment=Deployment.local(root="local://blinded-method"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.proprietary_protocol == "blinded"
assert not resolved.requires_preparationInspect the bounded SecureLinear preview
SecureLinear describes an
authenticated preview restricted to its fixed synthetic shape. It is useful for
research inspection, but it cannot be substituted into a shipped profile or run by
pllm gateway --local or pllm benchmark run.
from pllm.protocols import SecureLinear
method = SecureLinear()
descriptor = method.describe()
assert descriptor.required_host_features == ("synthetic-fixed-shape-only",)
assert method.component == "pllm/secure-linear/v1"Declare a non-private CleartextLinear baseline
CleartextLinear makes a
non-private control configuration explicit for tests and comparisons. Inputs are
visible to the executor. No shipped profile or CLI benchmark composes it, so this
descriptor inspection is intentionally not presented as a private-inference run.
from pllm.protocols import CleartextLinear
method = CleartextLinear()
descriptor = method.describe()
assert descriptor.role_eligibility == ("inference",)
assert method.component == "pllm/cleartext-linear"Check current Python support before moving from configuration to execution. Experimental garbling components protect nonlinear regions and are not another end-to-end linear protocol.