mirror of
https://github.com/luxfi/fhe.git
synced 2026-07-26 23:16:08 +00:00
docs(threshold): decomplect the threshold-FHE package — one canonical path
Establish exactly one way to do each thing and fence off the legacy primitives: - doc.go (new): package overview. DealerlessKeyGen is THE production keygen (dealerless); PartialDecryptLWE/CombineLWE is THE threshold decrypt (no-reconstruct); ShareLWESecretKey is a trusted-dealer test oracle only. Documents the F ⊥ M boundary (this package is FHE-only; MPC signing lives in luxfi/threshold) and the dealerless-bootstrap-key residual (homomorphic compute), stated honestly, not faked. - keygen.go: re-document GenerateSharedKey. It is a TRUSTED-DEALER key-COMMITMENT VSS that shares the SHA-256 hash of the key — useful for verifiable-sharing audit, NOT usable for threshold decryption. Marked Deprecated for the keygen role; points to DealerlessKeyGen. Removes the misleading 'distributed key generation … for now we generate keys and split them' framing. - partial_decrypt.go: label ShareLWESecretKey as TRUSTED-DEALER (retained as a KAT oracle); point to DealerlessKeyGen for production. No behaviour change; kernel tests green.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package threshold is the ONE threshold-FHE implementation for Lux — the
|
||||
// F-Chain confidential-decrypt lane. It is held to the trustless-by-default law:
|
||||
// no trusted dealer (dealerless key generation) and no reconstruction of the FHE
|
||||
// secret key at decrypt time, the same standard Corona / Pulsar / Magnetar meet.
|
||||
//
|
||||
// There is exactly one way to do each thing here. The canonical trustless flow:
|
||||
//
|
||||
// pub, shares := DealerlessKeyGen(params, t, n, crsSeed) // dealerless keygen
|
||||
// ct := encrypt(pub, m) // collective public key
|
||||
// d_j := PartialDecryptLWE(shares[j], ct, …) // per-party, no s formed
|
||||
// m := CombineLWE(ct, {d_j}_{|S|≥t}, …) // s masked behind c_1, never recovered
|
||||
//
|
||||
// File map (decomplected — each file is one concern, no overlap):
|
||||
//
|
||||
// - dealerless_dkg.go — THE production key generation. Dealerless (GJKR/Pedersen
|
||||
// DKG composed with the audited Lattigo multiparty CKG): each committee
|
||||
// member samples only its own contribution s_j, the collective secret
|
||||
// s = Σ s_j is NEVER formed, and the output is the collective LWE public key
|
||||
// plus one t-of-n LWEShare per party.
|
||||
//
|
||||
// - partial_decrypt.go — THE threshold decryption (AJL+12 noise-flooding with
|
||||
// Bendlin-Damgård denominator clearing). PartialDecryptLWE / CombineLWE are
|
||||
// no-reconstruct: the secret s appears only as the coefficient of the public
|
||||
// c_1 inside the masked aggregate and is never materialised. ShareLWESecretKey
|
||||
// in this file is a TRUSTED-DEALER split of a whole key — retained only as a
|
||||
// test/KAT oracle for the same LWEShare type; production uses DealerlessKeyGen.
|
||||
//
|
||||
// - lsss.go + keygen.go — a SEPARATE primitive: large-prime Shamir VSS with
|
||||
// Feldman commitments, and GenerateSharedKey, which shares the SHA-256 *hash*
|
||||
// of a serialized key. This is a key-COMMITMENT / verifiable-secret-sharing
|
||||
// facility (audit, dealer-equivocation checks). Its KeyShare values are shares
|
||||
// of a hash and are NOT usable for threshold DECRYPTION — do not mistake
|
||||
// GenerateSharedKey for the threshold-FHE keygen; that is DealerlessKeyGen.
|
||||
//
|
||||
// Scope and residual. This package realises the trustless confidential-DECRYPT
|
||||
// lane completely: dealerless generation of the encryption key + t-of-n shares,
|
||||
// and no-reconstruct threshold decryption. It deliberately does NOT generate the
|
||||
// FHEW blind-rotation / bootstrap (evaluation) key, which homomorphic COMPUTE on
|
||||
// committee ciphertexts requires. Dealerless bootstrap-key generation is a
|
||||
// distinct multiparty-FHEW protocol (collaborative RGSW key generation) and is
|
||||
// the documented residual — it is not faked here. Until it lands, the committee
|
||||
// can trustlessly ENCRYPT (collective public key) and trustlessly threshold-
|
||||
// DECRYPT (the launch-critical confidentiality property); homomorphic compute on
|
||||
// the committee's own ciphertexts still depends on a bootstrap key generated by a
|
||||
// dealer and is therefore out of the strict trustless lane.
|
||||
//
|
||||
// Decomplecting boundary (F ⊥ M). This package is FHE only (confidential
|
||||
// decrypt). It shares nothing with threshold MPC SIGNING (M-Chain: CGGMP21 /
|
||||
// FROST for bridge custody), which lives in github.com/luxfi/threshold. The two
|
||||
// are orthogonal primitives — different math, different purpose — and must never
|
||||
// be conflated.
|
||||
package threshold
|
||||
+14
-3
@@ -40,9 +40,20 @@ type KeyGenResult struct {
|
||||
Shares []*KeyShare // One per party
|
||||
}
|
||||
|
||||
// GenerateSharedKey performs distributed key generation.
|
||||
// In a real implementation, this would be done via MPC.
|
||||
// For now, we generate keys and split them using LSSS.
|
||||
// GenerateSharedKey is a TRUSTED-DEALER key-COMMITMENT facility, NOT the
|
||||
// threshold-FHE key generator. It generates a keypair in one process and
|
||||
// large-prime Shamir-splits the SHA-256 HASH of each secret-key component
|
||||
// (hashToFieldElement) — i.e. it shares a COMMITMENT to the key, for verifiable-
|
||||
// secret-sharing / dealer-equivocation auditing. The resulting KeyShare values
|
||||
// are shares of a hash and CANNOT perform threshold decryption.
|
||||
//
|
||||
// For the trustless threshold-FHE lane use DealerlessKeyGen (dealerless_dkg.go),
|
||||
// which is dealerless (no party ever holds the FHE secret key) and produces
|
||||
// decrypt-capable LWEShare values consumed by PartialDecryptLWE / CombineLWE. See
|
||||
// the package doc for the canonical flow.
|
||||
//
|
||||
// Deprecated: not part of the threshold-decrypt path; retained only for the
|
||||
// commitment-VSS use case.
|
||||
func GenerateSharedKey(params fhe.Parameters, threshold, total int, sessionID string) (*KeyGenResult, error) {
|
||||
if threshold > total {
|
||||
return nil, fmt.Errorf("threshold %d exceeds total %d", threshold, total)
|
||||
|
||||
@@ -241,6 +241,12 @@ type LWEPartialDecryption struct {
|
||||
// ShareLWESecretKey Shamir-splits the LWE secret key coefficient-by-
|
||||
// coefficient over Z_q where q is the LWE modulus.
|
||||
//
|
||||
// TRUSTED-DEALER. This takes a WHOLE secret key, so the caller momentarily holds
|
||||
// the full FHE secret — a single point of compromise. It is retained as a
|
||||
// test/KAT oracle for the LWEShare type; the trustless PRODUCTION key generation
|
||||
// is DealerlessKeyGen (dealerless_dkg.go), where no party ever holds the secret.
|
||||
// Both produce the same LWEShare via the same dealing helpers (dealCoeffSubShares).
|
||||
//
|
||||
// Pipeline:
|
||||
//
|
||||
// 1. Extract the secret-key polynomial from NTT+Montgomery form back to
|
||||
|
||||
Reference in New Issue
Block a user