mirror of
https://github.com/luxfi/lens.git
synced 2026-10-30 16:21:16 +00:00
Lens is the curve-based threshold signing kernel for Lux. It is the classical analogue of Pulsar (the lattice kernel at github.com/luxfi/pulsar). Both kernels share the same lifecycle shape — Bootstrap → Reshare* → Reanchor — and the same activation circuit-breaker contract. They differ only in the math field: Pulsar over R_q (Module-LWE), Lens over a prime-order curve group (discrete log). Curves shipped: Ed25519, secp256k1, Ristretto255. Each has a deterministically-derived secondary Pedersen generator H from a Lens-specific nothing-up-my-sleeve tag. Sign math: FROST 2-round Schnorr threshold signing per RFC 9591 (Komlo-Goldberg 2020). Verifier checks z·G ?= R + c·X under the unchanged group public key. Reshare math: HJKY97 zero-poly Refresh + Desmedt-Jajodia ReshareToNewSet over the curve scalar field. Master secret s is preserved; only the share distribution rotates per epoch. Activation cert message format: QUASAR-LENS-ACTIVATE-v1, byte-equivalent shape to QUASAR-PULSAR-ACTIVATE-v1. Hash suite: HashSuite interface with Lens-SHA3 (production, cSHAKE256 / KMAC256 / TupleHash256) and Lens-BLAKE3 (legacy) profiles. DKG: distributed FROST DKG with Feldman commitments. No trusted dealer required at genesis if the chain prefers proper distributed DKG. KAT oracles: cmd/reshare_oracle and cmd/dkg_oracle emit deterministic JSON vectors for cross-language byte-equality validation against a future luxcpp/crypto/lens/ port. Tests: full unit + integration coverage on every shipped curve. 60 unique tests, 0 failures.
79 lines
2.4 KiB
Go
79 lines
2.4 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package reshare
|
|
|
|
// KeyShare regeneration for Lens.
|
|
//
|
|
// The Reshare and Refresh kernels operate on bare scalar shares —
|
|
// the SkShare field of the production-grade
|
|
// `github.com/luxfi/lens/threshold.KeyShare` struct. A KeyShare is
|
|
// MORE than just SkShare; it carries:
|
|
//
|
|
// type KeyShare struct {
|
|
// Index int
|
|
// PartyID int
|
|
// SkShare primitives.Scalar
|
|
// VerificationShare primitives.Point
|
|
// Lambda primitives.Scalar
|
|
// Seeds map[int][][]byte
|
|
// MACKeys map[int][]byte
|
|
// GroupKey *threshold.GroupKey
|
|
// }
|
|
//
|
|
// All KDF derivations use the canonical Lens HashSuite (KMAC256
|
|
// under Lens-SHA3, keyed BLAKE3 under the legacy suite). Domain-
|
|
// separation tags:
|
|
//
|
|
// "lens.reshare.prf-seed.v1" — for Seeds
|
|
// "lens.reshare.mac-key.v1" — for MACKeys
|
|
|
|
import (
|
|
"github.com/luxfi/lens/hash"
|
|
"github.com/luxfi/lens/primitives"
|
|
)
|
|
|
|
// KDFOutput derives a fixed-length output from keying material under
|
|
// the supplied HashSuite's pairwise KDF. suite=nil resolves to the
|
|
// production default (Lens-SHA3).
|
|
//
|
|
// The tag is folded into the chainID label with a `|` separator so
|
|
// two callers with distinct tags but the same remaining inputs always
|
|
// produce distinct bytes.
|
|
func KDFOutput(
|
|
suite hash.HashSuite,
|
|
tag string,
|
|
authKex []byte,
|
|
chainID, groupID []byte,
|
|
eraID, generation uint64,
|
|
partyI, partyJ int,
|
|
outLen int,
|
|
) []byte {
|
|
s := hash.Resolve(suite)
|
|
labelledChain := make([]byte, 0, len(tag)+1+len(chainID))
|
|
labelledChain = append(labelledChain, []byte(tag)...)
|
|
labelledChain = append(labelledChain, '|')
|
|
labelledChain = append(labelledChain, chainID...)
|
|
return s.DerivePairwise(authKex, labelledChain, groupID, eraID, generation, partyI, partyJ, outLen)
|
|
}
|
|
|
|
// CanonicalPair returns the (i, j) tuple in canonical (smaller-first)
|
|
// order. Used as a map key for pairwise material.
|
|
func CanonicalPair(i, j int) [2]int {
|
|
if i > j {
|
|
return [2]int{j, i}
|
|
}
|
|
return [2]int{i, j}
|
|
}
|
|
|
|
// EraseScalar overwrites the scalar's binary representation with zero
|
|
// bytes. After activation, every old share MUST be erased — failure
|
|
// to do so undermines the proactive-security guarantee.
|
|
func EraseScalar(s primitives.Scalar) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
zero := s.Curve().NewScalar()
|
|
s.Set(zero)
|
|
}
|