mirror of
https://github.com/luxfi/corona.git
synced 2026-07-27 02:50:34 +00:00
Leftover from Corona's "Pulsar-R" lineage. Pulsar (M-LWE) and Corona
(R-LWE) are independent constructions with separate hardness assumptions,
so their cSHAKE personalisation strings must be distinct.
Changes (Go, non-luxcpp):
- hash tags: PULSAR-HC-v1 -> CORONA-HC-v1, etc. (HU, TRANSCRIPT, PRF, MAC, PAIRWISE)
- profile IDs: "Pulsar-SHA3" -> "Corona-SHA3", "Pulsar-BLAKE3" -> "Corona-BLAKE3"
- context strings: pulsar.dkg2.A.v1 -> corona.dkg2.A.v1, etc.
- env vars: PULSAR_RESHARE_KAT_PATH -> CORONA_RESHARE_KAT_PATH, etc.
- struct names: pulsarSHA3 -> coronaSHA3
- KAT derive roots: sign_e2e_pulsar -> sign_e2e_corona
What's preserved (different scope):
- luxcpp/crypto/pulsar/* path references in comments (separate repo,
out of scope; the C++ side will rename in its own commit)
- Cross-runtime KAT files on disk (will regenerate next CI run)
All 11 packages test green: dkg, dkg2, hash, keyera, networking,
primitives, reshare, sign, threshold, utils, wire.
171 lines
4.6 KiB
Go
171 lines
4.6 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package reshare
|
|
|
|
// KeyShare regeneration for Corona / Corona integration.
|
|
//
|
|
// The Reshare and Refresh kernels operate on bare Shamir shares — the
|
|
// SkShare field of the production-grade
|
|
// `github.com/luxfi/nasua/threshold.KeyShare` struct. A KeyShare is
|
|
// MORE than just SkShare; it carries:
|
|
//
|
|
// type KeyShare struct {
|
|
// Index int
|
|
// SkShare structs.Vector[ring.Poly]
|
|
// Seeds map[int][][]byte
|
|
// MACKeys map[int][]byte
|
|
// Lambda ring.Poly
|
|
// GroupKey *GroupKey
|
|
// }
|
|
//
|
|
// All KDF derivations use the canonical Corona HashSuite (KMAC256
|
|
// under Corona-SHA3, keyed BLAKE3 under the legacy suite). Domain-
|
|
// separation tags:
|
|
//
|
|
// "corona.reshare.prf-seed.v1" — for Seeds
|
|
// "corona.reshare.mac-key.v1" — for MACKeys
|
|
// "corona.reshare.lambda-bind.v1" — bound into Lambda derivation when
|
|
// the committee computes Lambdas
|
|
// from a shared transcript hash.
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/luxfi/corona/hash"
|
|
"github.com/luxfi/corona/primitives"
|
|
"github.com/luxfi/corona/sign"
|
|
|
|
"github.com/luxfi/lattice/v7/ring"
|
|
"github.com/luxfi/lattice/v7/utils/structs"
|
|
)
|
|
|
|
// PartyKeyShare is the Corona-internal mirror of
|
|
// corona/threshold.KeyShare.
|
|
type PartyKeyShare struct {
|
|
Index int
|
|
SkShare structs.Vector[ring.Poly]
|
|
Seeds map[int][][]byte
|
|
MACKeys map[int][]byte
|
|
Lambda ring.Poly
|
|
GroupKey *PartyGroupKey
|
|
}
|
|
|
|
// PartyGroupKey mirrors corona/threshold.GroupKey.
|
|
type PartyGroupKey struct {
|
|
A structs.Matrix[ring.Poly]
|
|
BTilde structs.Vector[ring.Poly]
|
|
}
|
|
|
|
// PartyKeyShareFromShare wraps a bare Shamir share into a complete
|
|
// PartyKeyShare instance, given the committee context.
|
|
func PartyKeyShareFromShare(
|
|
r *ring.Ring,
|
|
share Share,
|
|
partyID1Indexed int,
|
|
newCommittee []int,
|
|
pairwiseSeeds map[[2]int][]byte,
|
|
pairwiseMACs map[[2]int][]byte,
|
|
groupKey *PartyGroupKey,
|
|
) (*PartyKeyShare, error) {
|
|
myIdx := -1
|
|
for i, id := range newCommittee {
|
|
if id == partyID1Indexed {
|
|
myIdx = i
|
|
break
|
|
}
|
|
}
|
|
if myIdx < 0 {
|
|
return nil, fmt.Errorf("reshare: party %d not in new committee", partyID1Indexed)
|
|
}
|
|
|
|
K := len(newCommittee)
|
|
lagrangeInputs := make([]int, K)
|
|
for i, id := range newCommittee {
|
|
lagrangeInputs[i] = id - 1
|
|
}
|
|
lagrange := primitives.ComputeLagrangeCoefficients(
|
|
r, lagrangeInputs, big.NewInt(int64(sign.Q)),
|
|
)
|
|
lambdaCopy := r.NewPoly()
|
|
lambdaCopy.Copy(lagrange[myIdx])
|
|
r.NTT(lambdaCopy, lambdaCopy)
|
|
r.MForm(lambdaCopy, lambdaCopy)
|
|
|
|
seeds := make(map[int][][]byte, K)
|
|
for i := 0; i < K; i++ {
|
|
seeds[i] = make([][]byte, K)
|
|
for j := 0; j < K; j++ {
|
|
seeds[i][j] = pairwiseSeeds[canonicalPair(i, j)]
|
|
}
|
|
}
|
|
macKeys := make(map[int][]byte, K)
|
|
for k := 0; k < K; k++ {
|
|
if k == myIdx {
|
|
continue
|
|
}
|
|
macKeys[k] = pairwiseMACs[canonicalPair(myIdx, k)]
|
|
}
|
|
|
|
return &PartyKeyShare{
|
|
Index: myIdx,
|
|
SkShare: share,
|
|
Seeds: seeds,
|
|
MACKeys: macKeys,
|
|
Lambda: lambdaCopy,
|
|
GroupKey: groupKey,
|
|
}, nil
|
|
}
|
|
|
|
// KDFOutput derives a fixed-length output from a keying material under
|
|
// the supplied HashSuite's pairwise KDF. suite=nil resolves to the
|
|
// production default (Corona-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 — required because the production suite uses
|
|
// a single KMAC256 customization for all pairwise calls.
|
|
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}
|
|
}
|
|
|
|
// EraseShare overwrites the SkShare field with zero bytes. After
|
|
// activation, every old share MUST be erased — failure to do so
|
|
// undermines the proactive-security guarantee.
|
|
func EraseShare(s Share) {
|
|
for _, p := range s {
|
|
if p.Coeffs == nil {
|
|
continue
|
|
}
|
|
for level := range p.Coeffs {
|
|
coeffs := p.Coeffs[level]
|
|
for k := range coeffs {
|
|
coeffs[k] = 0
|
|
}
|
|
}
|
|
}
|
|
}
|