Files
zeekay 2c63fd34fc lens: classical curve threshold kernel — sister to Pulsar
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.
2026-03-03 12:00:00 -08:00

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)
}