Skip to main content
HUMΛN
Passport
Passport

Shamir cross-language alignment: GF(2^8) vs vsss-rs (and what to do)

HUMΛN Team··15 min·Crypto + Mobile engineers

The bug class

guardian-sss.ts implements byte-wise GF(2^8) Shamir secret sharing—the standard approach for compact shares in TypeScript with tests you already trust.

The HUMΛN Tauri stack also ships threshold.rs using vsss-rs-style curve25519 scalars and share layouts that are not bitwise-compatible with GF(2^8) byte streams.

You cannot mix shares across those algebras. “We have three shares” is not enough—the field, encoding, and identifier semantics must match or reconstruction silently fails or worse, produces garbage that looks plausible until HMAC verification fails downstream.

This essay is the decision record for teams touching guardian recovery on both server and device.

Three resolutions

1. Server adopts vsss-rs-shaped shares

Pros: one format end-to-end; Rust and TS speak the same bytes.
Cons: migration for in-flight recovery sessions; careful rollout for existing encrypted shard rows.

2. Rust implements GF(2^8) reconstruction

Pros: server issuance format unchanged; mobile reconstructs with matching math.
Cons: new Rust code path to test against TS vectors exhaustively; performance is fine at human scale—correctness is everything.

3. TypeScript reconstruct in the webview / JS layer

Pros: fastest path—reuse reconstructSecret() from guardian-sss.ts; HMAC via WebCrypto or @noble/hashes; Rust focuses on Keychain storage and platform glue.
Cons: secret material exists in JS memory—minimize lifetime, zeroize where possible, never log.

Phase A recommendation (per plan): Option 3 to unblock; plan migration toward 1 when shard format can move cleanly without stranding users mid-recovery.

Storage boundary

vault.rs demonstrates secure storage patterns. Guardian shards should use named keychain entries (e.g. guardian-shard-{shard_id}), not ad hoc shared buckets with unrelated secrets. Biometric gating remains in the product layer—Rust stores bytes after the user proves presence.

Transport: WebRTC vs BLE

WebRTC DataChannel is the primary P2P transport for shard delivery in the architecture we describe; ble.rs remains an optional path when radios are the only viable link. Do not merge transport logic into share semantics—bytes are bytes regardless of how they crossed the air gap.

Cross-test discipline

If you change one side without the other:

  • You will get “recovery succeeded in integration tests” with synthetic shares and “recovery failed in prod” with real shards.
  • Add golden vectors: fixed secret, fixed shares, expected reconstruction hex, cross-run in both TS and Rust (or TS-only reconstruct path) in CI.

Server-blind proof path: HMAC proofs and completion modes.

— Part of