pulsar: simplify wire-format tags — drop redundant -M and LUXROUND

Hard fork of all customization tags. Per the family rename
(Pulsar-M → Pulsar), the -M suffix is now redundant. Per the
compound-word discipline, LUXROUND braids brand+concept and is
replaced by ROUND.

  PULSAR-M-DKG-COMMIT-V1       → PULSAR-DKG-COMMIT-V1
  PULSAR-M-DKG-TRANSCRIPT-V1   → PULSAR-DKG-TRANSCRIPT-V1
  PULSAR-M-DKG-DEALER-V1       → PULSAR-DKG-DEALER-V1
  PULSAR-M-DKG-BLINDMASK-V1    → PULSAR-DKG-BLINDMASK-V1
  PULSAR-M-COMMITTEE-V1        → PULSAR-COMMITTEE-V1
  PULSAR-M-SIGN-{R1,R2,...}-V1 → PULSAR-SIGN-{R1,R2,...}-V1
  PULSAR-M-RESHARE-*-V1        → PULSAR-RESHARE-*-V1
  PULSAR-M-EXPANDB-V1          → PULSAR-EXPANDB-V1
  PULSAR-M-COMPLAINT-V1        → PULSAR-COMPLAINT-V1
  PULSAR-M-SEED-SHARE-V1       → PULSAR-SEED-SHARE-V1
  PULSAR-M-LUXROUND-COMMITTEE-V1 → PULSAR-ROUND-COMMITTEE-V1
  cSHAKE function-name "Pulsar-M" → "Pulsar"

Every prior signature with -M tags is invalidated. KAT vectors
need regeneration. Test suite passes (85 tests, 0.530s).
This commit is contained in:
2026-05-11 15:28:15 -07:00
parent 19ae5179d2
commit 1b17935bc6
9 changed files with 38 additions and 38 deletions
+4 -4
View File
@@ -19,7 +19,7 @@ package pulsarm
//
// The v0.1 commitment is the RO-binding cSHAKE256 commit
//
// C_i = cSHAKE256(c_i || blind_i, 32, "PULSAR-M-DKG-COMMIT-V1")
// C_i = cSHAKE256(c_i || blind_i, 32, "PULSAR-DKG-COMMIT-V1")
//
// which is binding under collision resistance and hiding under
// uniformity of blind_i. The v0.2 path replaces this with R_q^k
@@ -158,7 +158,7 @@ func (s *DKGSession) Round1() (*DKGRound1Msg, error) {
// DKG sessions on the same contribution never collide.
committeeRoot := s.commitCommitteeRoot()
keyMaterial := []byte{}
keyMaterial = append(keyMaterial, []byte("PULSAR-M-DKG-DEALER-V1")...)
keyMaterial = append(keyMaterial, []byte("PULSAR-DKG-DEALER-V1")...)
keyMaterial = append(keyMaterial, committeeRoot[:]...)
keyMaterial = append(keyMaterial, byte(s.myIndex>>8), byte(s.myIndex))
keyMaterial = append(keyMaterial, s.myBlind[:]...)
@@ -190,7 +190,7 @@ func (s *DKGSession) Round1() (*DKGRound1Msg, error) {
blindMask := cshake256(
append(append([]byte{}, s.myBlind[:]...), recipient[:]...),
shareWireSize,
"PULSAR-M-DKG-BLINDMASK-V1",
"PULSAR-DKG-BLINDMASK-V1",
)
var blindOut [shareWireSize]byte
copy(blindOut[:], blindMask)
@@ -411,7 +411,7 @@ func (s *DKGSession) computeRound2Digest(ordered []*DKGRound1Msg) [32]byte {
// sorted committee.
func (s *DKGSession) commitCommitteeRoot() [32]byte {
parts := make([][]byte, 0, len(s.Committee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.Committee {
parts = append(parts, id[:])
}
+4 -4
View File
@@ -112,7 +112,7 @@ func (s *LargeDKGSession) Round1() (*LargeDKGRound1Msg, error) {
committeeRoot := s.commitCommitteeRoot()
keyMaterial := []byte{}
keyMaterial = append(keyMaterial, []byte("PULSAR-M-DKG-DEALER-V1")...)
keyMaterial = append(keyMaterial, []byte("PULSAR-DKG-DEALER-V1")...)
keyMaterial = append(keyMaterial, committeeRoot[:]...)
keyMaterial = append(keyMaterial, byte(s.myIndex>>8), byte(s.myIndex))
keyMaterial = append(keyMaterial, s.myBlind[:]...)
@@ -134,7 +134,7 @@ func (s *LargeDKGSession) Round1() (*LargeDKGRound1Msg, error) {
blindMask := cshake256(
append(append([]byte{}, s.myBlind[:]...), recipient[:]...),
shareWireSizeQ,
"PULSAR-M-DKG-BLINDMASK-V1",
"PULSAR-DKG-BLINDMASK-V1",
)
var envShare [shareWireSizeQ]byte
copy(envShare[:], shareBytes[:])
@@ -316,7 +316,7 @@ func (s *LargeDKGSession) computeRound2Digest(ordered []*LargeDKGRound1Msg) [32]
func (s *LargeDKGSession) commitCommitteeRoot() [32]byte {
parts := make([][]byte, 0, len(s.Committee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.Committee {
parts = append(parts, id[:])
}
@@ -356,7 +356,7 @@ func committeeRootFromLargeShares(shares []*LargeKeyShare) [32]byte {
}
}
parts := make([][]byte, 0, len(ids)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range ids {
parts = append(parts, id[:])
}
+4 -4
View File
@@ -149,7 +149,7 @@ func (s *LargeReshareSession) Round1() (*LargeDKGRound1Msg, error) {
myCommit := transcriptHash32(tagReshareCommit, commitInput)
keyMaterial := []byte{}
keyMaterial = append(keyMaterial, []byte("PULSAR-M-RESHARE-DEALER-V1")...)
keyMaterial = append(keyMaterial, []byte("PULSAR-RESHARE-DEALER-V1")...)
keyMaterial = append(keyMaterial, s.commitOldCommitteeRoot()...)
keyMaterial = append(keyMaterial, s.commitNewCommitteeRoot()...)
keyMaterial = append(keyMaterial, blind[:]...)
@@ -170,7 +170,7 @@ func (s *LargeReshareSession) Round1() (*LargeDKGRound1Msg, error) {
blindMask := cshake256(
append(append([]byte{}, blind[:]...), recipient[:]...),
shareWireSizeQ,
"PULSAR-M-RESHARE-BLINDMASK-V1",
"PULSAR-RESHARE-BLINDMASK-V1",
)
var envShare [shareWireSizeQ]byte
copy(envShare[:], shareBytes[:])
@@ -329,7 +329,7 @@ func (s *LargeReshareSession) reshareQuorumEvalPoints() []uint32 {
func (s *LargeReshareSession) commitOldCommitteeRoot() []byte {
parts := make([][]byte, 0, len(s.OldCommittee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.OldCommittee {
parts = append(parts, id[:])
}
@@ -339,7 +339,7 @@ func (s *LargeReshareSession) commitOldCommitteeRoot() []byte {
func (s *LargeReshareSession) commitNewCommitteeRoot() []byte {
parts := make([][]byte, 0, len(s.NewCommittee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.NewCommittee {
parts = append(parts, id[:])
}
+4 -4
View File
@@ -202,7 +202,7 @@ func (s *ReshareSession) Round1() (*DKGRound1Msg, error) {
// Shamir-share the contribution at threshold newT to the new committee.
keyMaterial := []byte{}
keyMaterial = append(keyMaterial, []byte("PULSAR-M-RESHARE-DEALER-V1")...)
keyMaterial = append(keyMaterial, []byte("PULSAR-RESHARE-DEALER-V1")...)
keyMaterial = append(keyMaterial, s.commitOldCommitteeRoot()...)
keyMaterial = append(keyMaterial, s.commitNewCommitteeRoot()...)
keyMaterial = append(keyMaterial, blind[:]...)
@@ -223,7 +223,7 @@ func (s *ReshareSession) Round1() (*DKGRound1Msg, error) {
blindMask := cshake256(
append(append([]byte{}, blind[:]...), recipient[:]...),
shareWireSize,
"PULSAR-M-RESHARE-BLINDMASK-V1",
"PULSAR-RESHARE-BLINDMASK-V1",
)
var envShare [64]byte
copy(envShare[:], shareBytes[:])
@@ -433,7 +433,7 @@ func (s *ReshareSession) reshareQuorumEvalPoints() []uint32 {
// old committee.
func (s *ReshareSession) commitOldCommitteeRoot() []byte {
parts := make([][]byte, 0, len(s.OldCommittee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.OldCommittee {
parts = append(parts, id[:])
}
@@ -445,7 +445,7 @@ func (s *ReshareSession) commitOldCommitteeRoot() []byte {
// new committee.
func (s *ReshareSession) commitNewCommitteeRoot() []byte {
parts := make([][]byte, 0, len(s.NewCommittee)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range s.NewCommittee {
parts = append(parts, id[:])
}
+2 -2
View File
@@ -66,7 +66,7 @@ func (c RoundContext) Encode() []byte {
// RoundSessionID derives a deterministic per-Lux-round Pulsar-M
// SessionID from a RoundContext. The session-id binds the Pulsar-M
// per-round PRNG (PULSAR-M-SIGN-PRNG-V1 customisation tag in
// per-round PRNG (PULSAR-SIGN-PRNG-V1 customisation tag in
// transcript.go) to the unique (epoch, round, item, committee) tuple,
// closing the CRIT-1 replay vector that del Pino-Niot's PRNGKeyForRound
// addresses in the small-committee path.
@@ -90,7 +90,7 @@ func RoundCommitteeRoot(committee []NodeID) [32]byte {
}
}
parts := make([][]byte, 0, len(sorted)+1)
parts = append(parts, []byte("PULSAR-M-LUXROUND-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-ROUND-COMMITTEE-V1"))
for _, id := range sorted {
parts = append(parts, id[:])
}
+1 -1
View File
@@ -70,7 +70,7 @@ func shamirDealRandom(secret [SeedSize]byte, n, t int, coeffStream []byte) ([]sh
// coefficients per slot are pulled from coeffStream.
//
// If coeffStream is shorter than needed, it is stretched via
// cSHAKE256(coeffStream, tag=PULSAR-M-SEED-SHARE-V1).
// cSHAKE256(coeffStream, tag=PULSAR-SEED-SHARE-V1).
//
// Use this when the secret vector contains values that may equal
// 256 (the 257-th GF element), e.g. an HJKY97 reshare contribution
+2 -2
View File
@@ -456,7 +456,7 @@ func deriveMACKey(a, b NodeID, pk *PublicKey) [32]byte {
if pk != nil {
parts = append(parts, pk.Bytes)
}
return transcriptHash32("PULSAR-M-SIGN-MACKEY-V1", parts...)
return transcriptHash32("PULSAR-SIGN-MACKEY-V1", parts...)
}
// committeeRootFromShares reconstructs the DKG committee root from a
@@ -474,7 +474,7 @@ func committeeRootFromShares(shares []*KeyShare) [32]byte {
}
}
parts := make([][]byte, 0, len(ids)+1)
parts = append(parts, []byte("PULSAR-M-COMMITTEE-V1"))
parts = append(parts, []byte("PULSAR-COMMITTEE-V1"))
for _, id := range ids {
parts = append(parts, id[:])
}
+16 -16
View File
@@ -30,27 +30,27 @@ import (
// pulsar-m.tex §3 table "purpose -> SP 800-185 customisation tag"
// byte-for-byte.
const (
tagDKGCommit = "PULSAR-M-DKG-COMMIT-V1"
tagDKGTranscript = "PULSAR-M-DKG-TRANSCRIPT-V1"
tagSignR1 = "PULSAR-M-SIGN-R1-V1"
tagSignR1MAC = "PULSAR-M-SIGN-R1-MAC-V1"
tagSignR2 = "PULSAR-M-SIGN-R2-V1"
tagSignPRNG = "PULSAR-M-SIGN-PRNG-V1"
tagSignPRNGKey = "PULSAR-M-SIGN-PRNGKEY-V1"
tagSignPRF = "PULSAR-M-SIGN-PRF-V1"
tagReshareCommit = "PULSAR-M-RESHARE-COMMIT-V1"
tagReshareTrans = "PULSAR-M-RESHARE-TRANSCRIPT-V1"
tagReshareBeacon = "PULSAR-M-RESHARE-BEACON-V1"
tagExpandB = "PULSAR-M-EXPANDB-V1"
tagComplaint = "PULSAR-M-COMPLAINT-V1"
tagSeedShare = "PULSAR-M-SEED-SHARE-V1"
tagDKGCommit = "PULSAR-DKG-COMMIT-V1"
tagDKGTranscript = "PULSAR-DKG-TRANSCRIPT-V1"
tagSignR1 = "PULSAR-SIGN-R1-V1"
tagSignR1MAC = "PULSAR-SIGN-R1-MAC-V1"
tagSignR2 = "PULSAR-SIGN-R2-V1"
tagSignPRNG = "PULSAR-SIGN-PRNG-V1"
tagSignPRNGKey = "PULSAR-SIGN-PRNGKEY-V1"
tagSignPRF = "PULSAR-SIGN-PRF-V1"
tagReshareCommit = "PULSAR-RESHARE-COMMIT-V1"
tagReshareTrans = "PULSAR-RESHARE-TRANSCRIPT-V1"
tagReshareBeacon = "PULSAR-RESHARE-BEACON-V1"
tagExpandB = "PULSAR-EXPANDB-V1"
tagComplaint = "PULSAR-COMPLAINT-V1"
tagSeedShare = "PULSAR-SEED-SHARE-V1"
)
// functionName is the SP 800-185 cSHAKE function-name parameter.
// All Pulsar-M cSHAKE calls pin N to "Pulsar-M" so that an integrator
// All Pulsar-M cSHAKE calls pin N to "Pulsar" so that an integrator
// who mistakenly fed Pulsar-M cSHAKE bytes into a non-Pulsar-M cSHAKE
// engine would get a deterministic mismatch.
const functionName = "Pulsar-M"
const functionName = "Pulsar"
// cshake256 returns the first outLen bytes of cSHAKE256(input, N,
// customisation) per SP 800-185 §3. Implemented over Go's
+1 -1
View File
@@ -212,7 +212,7 @@ type DKGShareEnvelope struct {
// equivocation gate of pulsar-m.tex §4.1).
type DKGRound2Msg struct {
NodeID NodeID
Digest [32]byte // cSHAKE256(commits) per PULSAR-M-DKG-COMMIT-V1
Digest [32]byte // cSHAKE256(commits) per PULSAR-DKG-COMMIT-V1
}
// DKGOutput is the result of a successful DKG.