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.
116 lines
2.6 KiB
Go
116 lines
2.6 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Command dkg_oracle emits a deterministic FROST DKG transcript for
|
|
// cross-language KAT validation. Drives lens/dkg.Run with a
|
|
// BLAKE3-keyed RNG and prints per-party shares + the joint group key.
|
|
package main
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
|
|
"github.com/luxfi/lens/dkg"
|
|
"github.com/luxfi/lens/primitives"
|
|
|
|
"github.com/zeebo/blake3"
|
|
)
|
|
|
|
type vector struct {
|
|
Curve string `json:"curve"`
|
|
N int `json:"n"`
|
|
T int `json:"t"`
|
|
Seed string `json:"seed"`
|
|
GroupKey string `json:"group_key_hex"`
|
|
Shares map[int]string `json:"shares_hex"`
|
|
VerShares map[int]string `json:"verification_shares_hex"`
|
|
PartyOrder []int `json:"party_order"`
|
|
}
|
|
|
|
func main() {
|
|
curveName := flag.String("curve", "ed25519", "curve: ed25519, secp256k1, ristretto255")
|
|
n := flag.Int("n", 5, "number of parties")
|
|
t := flag.Int("t", 3, "threshold")
|
|
seed := flag.String("seed", "lens.dkg.kat.v1", "deterministic RNG seed")
|
|
flag.Parse()
|
|
|
|
c := pickCurve(*curveName)
|
|
|
|
rng := blake3.New()
|
|
_, _ = rng.Write([]byte("lens.dkg.oracle.rng:"))
|
|
_, _ = rng.Write([]byte(*seed))
|
|
stream := rng.Digest()
|
|
|
|
shares, gk, err := dkg.Run(c, *n, *t, stream)
|
|
if err != nil {
|
|
fail("dkg.Run", err)
|
|
}
|
|
|
|
order := make([]int, 0, len(shares))
|
|
for id := range shares {
|
|
order = append(order, id)
|
|
}
|
|
sort.Ints(order)
|
|
|
|
out := vector{
|
|
Curve: c.Name(),
|
|
N: *n,
|
|
T: *t,
|
|
Seed: *seed,
|
|
GroupKey: hexPoint(gk.X),
|
|
Shares: map[int]string{},
|
|
VerShares: map[int]string{},
|
|
PartyOrder: order,
|
|
}
|
|
for _, id := range order {
|
|
ks := shares[id]
|
|
out.Shares[id] = hexScalar(ks.SkShare)
|
|
out.VerShares[id] = hexPoint(ks.VerificationShare)
|
|
}
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(out); err != nil {
|
|
fail("encode", err)
|
|
}
|
|
}
|
|
|
|
func pickCurve(name string) primitives.Curve {
|
|
switch name {
|
|
case "ed25519":
|
|
return primitives.NewEd25519()
|
|
case "secp256k1":
|
|
return primitives.NewSecp256k1()
|
|
case "ristretto255":
|
|
return primitives.NewRistretto255()
|
|
default:
|
|
fail("curve", fmt.Errorf("unknown curve %q", name))
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func hexScalar(s primitives.Scalar) string {
|
|
b, err := s.MarshalBinary()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
func hexPoint(p primitives.Point) string {
|
|
b, err := p.MarshalBinary()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
func fail(stage string, err error) {
|
|
fmt.Fprintf(os.Stderr, "lens-dkg-oracle: %s: %v\n", stage, err)
|
|
os.Exit(1)
|
|
}
|