mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
quasar: rename Corona→Corona, MLDSAProof→MLDSARollup, drop "triple"
The Quasar cert layers are the right cardinality of "Double Lattice +
Identity Rollup + optional Classical Fast-path", not "Triple Quantum":
BLS-12-381 classical fast-path (pairing) — empty in pure-PQ
Corona Ring-LWE threshold ML-DSA (luxfi/corona; production R-LWE)
Pulsar Module-LWE threshold ML-DSA (luxfi/pulsar; Class N1 byte-equal
to FIPS 204)
MLDSARollup per-validator ML-DSA-65 rolled into one STARK / Groth16 proof
(Z-Chain → P3Q)
"Triple Quantum" misled because BLS is classical — at most one of three
legs was quantum in the historic BLS+Corona+ZK shape. The honest PQ
cardinality is **Double Lattice** (Ring + Module). Pure-PQ profiles
drop BLS entirely and rely on Corona + Pulsar.
Corona is the academic R-LWE construction with trusted-dealer DKG;
it stays out of any open public-chain path. Corona is the production
Ring-LWE library (Pedersen DKG over R_q + proactive resharing).
Surface (in protocol/quasar/types.go):
QuasarCert.BLS → unchanged (classical fast-path, optional)
QuasarCert.Corona → QuasarCert.Corona (Ring-LWE threshold sig)
QuasarCert.MLDSAProof → QuasarCert.MLDSARollup (succinct identity rollup)
QuasarCert now also has a Pulsar field (Module-LWE threshold sig,
populated when wired)
QuasarSig.Corona → QuasarSig.Corona (also added Pulsar []byte)
FinalityEvent.Corona / MLDSAProof → Corona / Pulsar / MLDSARollup
New predicates:
QuasarCert.IsDoubleLattice() — Corona ∧ Pulsar (honest PQ count)
QuasarCert.HasClassicalFastPath() — len(BLS) > 0
QuasarCert.HasIdentityRollup() — len(MLDSARollup) > 0
The wire byte layout is unchanged (length-prefixed slots). Callers that
read the bytes don't notice. Source-level references that compiled
before the rename now compile against the new identifiers; bulk
rename swept the consensus repo (22 files, 219 insertions, 151
deletions) plus the engine/pq facing FinalityEvent.
Tests: GOWORK=off go test -short -count=1 ./... → all 28 packages green
(quasar suite 32s; integration 60s; no regressions).
This commit is contained in:
@@ -276,7 +276,7 @@ func BenchmarkPQModes_BLSPlusMLDSA(b *testing.B) {
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: blsAgg,
|
||||
MLDSAProof: mldsaPayload,
|
||||
MLDSARollup: mldsaPayload,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
@@ -472,7 +472,7 @@ func BenchmarkPQModes_BLSPlusCorona(b *testing.B) {
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: res.blsAgg,
|
||||
Corona: res.rtBytes,
|
||||
Corona: res.rtBytes,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
@@ -514,7 +514,7 @@ func BenchmarkPQModes_BLSPlusGroth16(b *testing.B) {
|
||||
groth16Placeholder := make([]byte, 192)
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: blsAgg,
|
||||
MLDSAProof: groth16Placeholder,
|
||||
MLDSARollup: groth16Placeholder,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
@@ -619,8 +619,8 @@ func BenchmarkPQModes_TripleQuantum(b *testing.B) {
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: res.blsAgg,
|
||||
Corona: res.rtBytes,
|
||||
MLDSAProof: mldsaPayload,
|
||||
Corona: res.rtBytes,
|
||||
MLDSARollup: mldsaPayload,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
|
||||
@@ -43,7 +43,7 @@ Each cryptographic layer is independently toggleable:
|
||||
|
||||
- BLS-only: fastest classical consensus (BLS12-381 threshold)
|
||||
- BLS + ML-DSA: dual with PQ identity proof (FIPS 204)
|
||||
- BLS + Corona: dual with PQ threshold proof (Ring-LWE)
|
||||
- BLS + Corona: dual with PQ threshold proof (Ring-LWE)
|
||||
- BLS + Corona + ML-DSA: full Quasar (all three in parallel)
|
||||
|
||||
# Testing
|
||||
|
||||
+27
-21
@@ -35,15 +35,19 @@ type ConsensusEngine struct {
|
||||
func (e *ConsensusEngine) PQMode() config.PQMode { return e.pqMode }
|
||||
|
||||
// FinalityEvent represents a finalized block with quantum-resistant proofs.
|
||||
// Carries all three components for parallel verification: classical BLS,
|
||||
// lattice Corona, and FIPS 204 ML-DSA. Defense in depth.
|
||||
// Carries the configured layers for parallel verification: classical
|
||||
// BLS fast-path, Corona (Ring-LWE) threshold, optional Pulsar (Module-
|
||||
// LWE) threshold, and the per-validator ML-DSA-65 identity rollup.
|
||||
// Defence in depth across one classical curve and (one or two) PQ
|
||||
// lattice families.
|
||||
type FinalityEvent struct {
|
||||
Height uint64
|
||||
BlockID ids.ID
|
||||
Timestamp time.Time
|
||||
BLSProof []byte // Classical BLS12-381 aggregate
|
||||
Corona []byte // Corona lattice threshold sig
|
||||
MLDSAProof []byte // FIPS 204 ML-DSA proof
|
||||
Height uint64
|
||||
BlockID ids.ID
|
||||
Timestamp time.Time
|
||||
BLSProof []byte // Classical BLS-12-381 aggregate (optional)
|
||||
Corona []byte // Corona (Ring-LWE) threshold sig
|
||||
Pulsar []byte // Pulsar-M (Module-LWE) threshold sig (optional)
|
||||
MLDSARollup []byte // Per-validator ML-DSA-65 rolled up via STARK/Groth16
|
||||
}
|
||||
|
||||
// memoryStore is a simple in-memory implementation of dag.Store for P-Chain vertices
|
||||
@@ -201,11 +205,11 @@ func (e *ConsensusEngine) ProcessBlock(ctx context.Context, blockID ids.ID, vote
|
||||
// Emit finality event
|
||||
select {
|
||||
case e.finality <- FinalityEvent{
|
||||
Height: e.height,
|
||||
BlockID: blockID,
|
||||
Timestamp: time.Now(),
|
||||
MLDSAProof: cert.PQCert,
|
||||
BLSProof: cert.BLSAgg,
|
||||
Height: e.height,
|
||||
BlockID: blockID,
|
||||
Timestamp: time.Now(),
|
||||
MLDSARollup: cert.PQCert,
|
||||
BLSProof: cert.BLSAgg,
|
||||
}:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
@@ -238,19 +242,21 @@ func (e *ConsensusEngine) Height() uint64 {
|
||||
// blockToFinalityEvent converts a quasar.Block to a FinalityEvent
|
||||
func blockToFinalityEvent(block *quasar.Block) FinalityEvent {
|
||||
blockID, _ := ids.FromString(block.Hash)
|
||||
var mldsaProof, corona, blsProof []byte
|
||||
var mldsaRollup, corona, pulsar, blsProof []byte
|
||||
if block.Cert != nil {
|
||||
mldsaProof = block.Cert.MLDSAProof
|
||||
mldsaRollup = block.Cert.MLDSARollup
|
||||
corona = block.Cert.Corona
|
||||
pulsar = block.Cert.Pulsar
|
||||
blsProof = block.Cert.BLS
|
||||
}
|
||||
return FinalityEvent{
|
||||
Height: block.Height,
|
||||
BlockID: blockID,
|
||||
Timestamp: block.Timestamp,
|
||||
MLDSAProof: mldsaProof,
|
||||
Corona: corona,
|
||||
BLSProof: blsProof,
|
||||
Height: block.Height,
|
||||
BlockID: blockID,
|
||||
Timestamp: block.Timestamp,
|
||||
MLDSARollup: mldsaRollup,
|
||||
Corona: corona,
|
||||
Pulsar: pulsar,
|
||||
BLSProof: blsProof,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ func TestProcessBlockEmptyCertificates(t *testing.T) {
|
||||
select {
|
||||
case event := <-engine.FinalityChannel():
|
||||
require.Equal(t, blockID, event.BlockID)
|
||||
require.NotEmpty(t, event.MLDSAProof)
|
||||
require.NotEmpty(t, event.MLDSARollup)
|
||||
require.NotEmpty(t, event.BLSProof)
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("Expected finality event")
|
||||
@@ -285,14 +285,14 @@ func TestFinalityEventFields(t *testing.T) {
|
||||
Height: 100,
|
||||
BlockID: ids.GenerateTestID(),
|
||||
Timestamp: time.Now(),
|
||||
MLDSAProof: []byte("pq-proof"),
|
||||
MLDSARollup: []byte("pq-proof"),
|
||||
BLSProof: []byte("bls-proof"),
|
||||
}
|
||||
|
||||
require.Equal(t, uint64(100), event.Height)
|
||||
require.NotEmpty(t, event.BlockID)
|
||||
require.False(t, event.Timestamp.IsZero())
|
||||
require.Equal(t, []byte("pq-proof"), event.MLDSAProof)
|
||||
require.Equal(t, []byte("pq-proof"), event.MLDSARollup)
|
||||
require.Equal(t, []byte("bls-proof"), event.BLSProof)
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte("bls-proof-data"),
|
||||
MLDSAProof: []byte("pq-proof-data"),
|
||||
MLDSARollup: []byte("pq-proof-data"),
|
||||
},
|
||||
},
|
||||
wantBLS: []byte("bls-proof-data"),
|
||||
@@ -497,7 +497,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte{},
|
||||
MLDSAProof: []byte{},
|
||||
MLDSARollup: []byte{},
|
||||
},
|
||||
},
|
||||
wantBLS: []byte{},
|
||||
@@ -534,7 +534,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
require.Equal(t, tc.block.Height, event.Height)
|
||||
require.Equal(t, tc.block.Timestamp, event.Timestamp)
|
||||
require.Equal(t, tc.wantBLS, event.BLSProof)
|
||||
require.Equal(t, tc.wantPQ, event.MLDSAProof)
|
||||
require.Equal(t, tc.wantPQ, event.MLDSARollup)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -613,7 +613,7 @@ func TestSetFinalizedCallbackInvocation(t *testing.T) {
|
||||
Timestamp: time.Now(),
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte("test-bls"),
|
||||
MLDSAProof: []byte("test-pq"),
|
||||
MLDSARollup: []byte("test-pq"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ func TestSetFinalizedCallbackInvocation(t *testing.T) {
|
||||
require.True(t, callbackCalled)
|
||||
require.Equal(t, uint64(42), receivedEvent.Height)
|
||||
require.Equal(t, []byte("test-bls"), receivedEvent.BLSProof)
|
||||
require.Equal(t, []byte("test-pq"), receivedEvent.MLDSAProof)
|
||||
require.Equal(t, []byte("test-pq"), receivedEvent.MLDSARollup)
|
||||
}
|
||||
|
||||
// TestSetFinalizedCallbackInvocationNilCert tests callback with nil certificate
|
||||
@@ -663,5 +663,5 @@ func TestSetFinalizedCallbackInvocationNilCert(t *testing.T) {
|
||||
require.True(t, callbackCalled)
|
||||
require.Equal(t, uint64(100), receivedEvent.Height)
|
||||
require.Nil(t, receivedEvent.BLSProof)
|
||||
require.Nil(t, receivedEvent.MLDSAProof)
|
||||
require.Nil(t, receivedEvent.MLDSARollup)
|
||||
}
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ func (pq *PostQuantum) GenerateQuantumProof(ctx context.Context, blockID ids.ID)
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
}
|
||||
if len(sig.MLDSA) > 0 {
|
||||
cert.MLDSAProof = quasar.EncodeMLDSASigs([][]byte{sig.MLDSA})
|
||||
cert.MLDSARollup = quasar.EncodeMLDSASigs([][]byte{sig.MLDSA})
|
||||
}
|
||||
return cert.MarshalBinary()
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func TestFinalityChannel(t *testing.T) {
|
||||
if event.Height != 1 {
|
||||
t.Errorf("Wrong height in event: got %d, want 1", event.Height)
|
||||
}
|
||||
if len(event.MLDSAProof) == 0 {
|
||||
if len(event.MLDSARollup) == 0 {
|
||||
t.Error("Missing PQ proof in event")
|
||||
}
|
||||
if len(event.BLSProof) == 0 {
|
||||
|
||||
@@ -622,8 +622,8 @@ func (p *QuantumPolicy) MaybeFinalize(ctx context.Context, candidateID Candidate
|
||||
// embed individual ML-DSA-65 signatures in MLDSAProof.
|
||||
qc := &quasar.QuasarCert{
|
||||
BLS: concatSignatures(p.blsVotes[candidateID]),
|
||||
Corona: concatSignatures(p.pqVotes[candidateID]),
|
||||
MLDSAProof: nil,
|
||||
Corona: concatSignatures(p.pqVotes[candidateID]),
|
||||
MLDSARollup: nil,
|
||||
Epoch: candidate.Height,
|
||||
Finality: time.Now(),
|
||||
Validators: blsCount,
|
||||
|
||||
@@ -119,7 +119,7 @@ func TestRealThresholdSig_Accepted(t *testing.T) {
|
||||
func TestQuasarCert_GarbageBytes_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{0x01},
|
||||
MLDSAProof: []byte{0x01},
|
||||
MLDSARollup: []byte{0x01},
|
||||
Validators: 1,
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func TestQuasarCert_NilCert_Rejected(t *testing.T) {
|
||||
func TestQuasarCert_EmptyBLS_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{},
|
||||
MLDSAProof: []byte{0x01, 0x02},
|
||||
MLDSARollup: []byte{0x01, 0x02},
|
||||
}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("key")),
|
||||
"QuasarCert with empty BLS must return false")
|
||||
@@ -155,7 +155,7 @@ func TestQuasarCert_EmptyBLS_Rejected(t *testing.T) {
|
||||
func TestQuasarCert_EmptyPQ_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{0x01, 0x02},
|
||||
MLDSAProof: []byte{},
|
||||
MLDSARollup: []byte{},
|
||||
}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("key")),
|
||||
"QuasarCert with empty PQ must return false")
|
||||
|
||||
@@ -54,8 +54,8 @@ func TestQuasarCert_RoundTrip_E2E(t *testing.T) {
|
||||
// end-to-end byte exercise; full aggregation is a higher-layer concern.
|
||||
cert := &QuasarCert{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: []byte{0x01}, // structural-only; cryptographic Corona is via coronaGobEncode of a real Signature
|
||||
MLDSAProof: EncodeMLDSASigs([][]byte{sig.MLDSA}),
|
||||
Corona: []byte{0x01}, // structural-only; cryptographic Corona is via coronaGobEncode of a real Signature
|
||||
MLDSARollup: EncodeMLDSASigs([][]byte{sig.MLDSA}),
|
||||
Epoch: 1,
|
||||
Finality: time.Unix(1700000000, 0),
|
||||
Validators: 3,
|
||||
@@ -83,7 +83,7 @@ func TestQuasarCert_RoundTrip_E2E(t *testing.T) {
|
||||
if string(got.Corona) != string(cert.Corona) {
|
||||
t.Fatalf("Corona round-trip mismatch")
|
||||
}
|
||||
if string(got.MLDSAProof) != string(cert.MLDSAProof) {
|
||||
if string(got.MLDSARollup) != string(cert.MLDSARollup) {
|
||||
t.Fatalf("MLDSAProof round-trip mismatch")
|
||||
}
|
||||
if got.Epoch != cert.Epoch {
|
||||
|
||||
@@ -613,7 +613,7 @@ func TestQuasarConsensus_GenerateCert(t *testing.T) {
|
||||
t.Error("expected non-empty BLS")
|
||||
}
|
||||
|
||||
if len(cert.MLDSAProof) == 0 {
|
||||
if len(cert.MLDSARollup) == 0 {
|
||||
t.Error("expected non-empty PQ")
|
||||
}
|
||||
|
||||
@@ -690,7 +690,7 @@ func TestSigner_VerifyQuasarSig_ValidatorNotFound(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "nonexistent",
|
||||
BLS: []byte{1, 2, 3},
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
@@ -706,7 +706,7 @@ func TestSigner_VerifyQuasarSig_InvalidBLS(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
@@ -886,7 +886,7 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
name: "empty BLS",
|
||||
cert: &QuasarCert{
|
||||
BLS: nil,
|
||||
MLDSAProof: []byte{1, 2, 3},
|
||||
MLDSARollup: []byte{1, 2, 3},
|
||||
},
|
||||
validators: []string{"v1"},
|
||||
want: false,
|
||||
@@ -895,7 +895,7 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
name: "empty PQ",
|
||||
cert: &QuasarCert{
|
||||
BLS: []byte{1, 2, 3},
|
||||
MLDSAProof: nil,
|
||||
MLDSARollup: nil,
|
||||
},
|
||||
validators: []string{"v1"},
|
||||
want: false,
|
||||
@@ -904,7 +904,7 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
name: "non-empty cert without crypto verification returns false",
|
||||
cert: &QuasarCert{
|
||||
BLS: []byte{1, 2, 3},
|
||||
MLDSAProof: []byte{4, 5, 6},
|
||||
MLDSARollup: []byte{4, 5, 6},
|
||||
Validators: 0,
|
||||
},
|
||||
validators: []string{"v1", "v2"},
|
||||
@@ -934,7 +934,7 @@ func TestBlock_Fields(t *testing.T) {
|
||||
Data: []byte("test data"),
|
||||
Cert: &QuasarCert{
|
||||
BLS: []byte{7, 8, 9},
|
||||
MLDSAProof: []byte{10, 11, 12},
|
||||
MLDSARollup: []byte{10, 11, 12},
|
||||
Validators: 1,
|
||||
Epoch: 100,
|
||||
Finality: now,
|
||||
@@ -1867,7 +1867,7 @@ func TestSigner_AggregateSignatures_InvalidBLS(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*QuasarSig{sig})
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//
|
||||
// BLS-only: fastest classical consensus
|
||||
// BLS + ML-DSA: dual PQ consensus (single-round PQ sigs)
|
||||
// BLS + Corona: dual PQ consensus (2-round threshold)
|
||||
// BLS + Corona: dual PQ consensus (2-round threshold)
|
||||
// BLS + Corona + ML-DSA: Quasar (all three hardness assumptions)
|
||||
//
|
||||
// Quasar signing via [signer.TripleSignRound1] runs all three paths in parallel.
|
||||
|
||||
@@ -257,9 +257,9 @@ func TestDualSigningFlow(t *testing.T) {
|
||||
// Verify Corona
|
||||
rtValid := coronaThreshold.Verify(rtGroupKey, messageStr, rtSig)
|
||||
require.True(t, rtValid, "Corona signature verification failed")
|
||||
t.Log(" Corona: ✓ verified")
|
||||
t.Log(" Corona: ✓ verified")
|
||||
|
||||
t.Log("✓ Dual BLS + Corona signing flow complete")
|
||||
t.Log(" - BLS: 1 round, aggregated, verified")
|
||||
t.Log(" - Corona: 2 rounds, aggregated, verified (post-quantum)")
|
||||
t.Log(" - Corona: 2 rounds, aggregated, verified (post-quantum)")
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ func (h *Certifier) generateCert(block *Block) *QuasarCert {
|
||||
// as "round did not finalise" rather than silently
|
||||
// emitting a downgraded cert.
|
||||
if demandsTriple {
|
||||
if cert.Corona == nil || len(cert.MLDSAProof) == 0 || len(cert.BLS) == 0 {
|
||||
if cert.Corona == nil || len(cert.MLDSARollup) == 0 || len(cert.BLS) == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -373,11 +373,11 @@ func (h *Certifier) generateCert(block *Block) *QuasarCert {
|
||||
pqData := sha256.Sum256(append(block.ID[:], block.ChainID[:]...))
|
||||
|
||||
return &QuasarCert{
|
||||
BLS: blsData[:],
|
||||
MLDSAProof: pqData[:],
|
||||
Epoch: block.Height,
|
||||
Finality: time.Now(),
|
||||
Validators: validatorCount,
|
||||
BLS: blsData[:],
|
||||
MLDSARollup: pqData[:],
|
||||
Epoch: block.Height,
|
||||
Finality: time.Now(),
|
||||
Validators: validatorCount,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ func (h *Certifier) realCert(ctx context.Context, s *signer, block *Block, valid
|
||||
}
|
||||
|
||||
cert := &QuasarCert{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: nil, // Corona Round 1 commitment is not a verifiable
|
||||
// signature on its own; aggregation/Round2 is run by the
|
||||
// consensus driver. We leave Corona empty here -- it's wired
|
||||
@@ -436,7 +436,7 @@ func (h *Certifier) realCert(ctx context.Context, s *signer, block *Block, valid
|
||||
}
|
||||
|
||||
if len(sig.MLDSA) > 0 {
|
||||
cert.MLDSAProof = EncodeMLDSASigs([][]byte{sig.MLDSA})
|
||||
cert.MLDSARollup = EncodeMLDSASigs([][]byte{sig.MLDSA})
|
||||
}
|
||||
|
||||
return cert
|
||||
|
||||
@@ -246,7 +246,7 @@ func TestBlock(t *testing.T) {
|
||||
Timestamp: time.Now(),
|
||||
Cert: &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
MLDSAProof: []byte("pq"),
|
||||
MLDSARollup: []byte("pq"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ func TestQuantumFinality_Integration(t *testing.T) {
|
||||
Timestamp: time.Now(),
|
||||
Cert: &QuasarCert{
|
||||
BLS: cert.BLSAgg,
|
||||
MLDSAProof: cert.PQCert,
|
||||
MLDSARollup: cert.PQCert,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ func BenchmarkAggregateSignatures(b *testing.B) {
|
||||
// Copy to avoid pool reuse during benchmark
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
@@ -126,7 +126,7 @@ func BenchmarkVerifyAggregatedSignature(b *testing.B) {
|
||||
}
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
@@ -173,7 +173,7 @@ func BenchmarkVerifyAggregatedSignatureParallel(b *testing.B) {
|
||||
}
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
New: func() any {
|
||||
return &QuasarSig{
|
||||
BLS: make([]byte, 0, 96),
|
||||
Corona: make([]byte, 0, 4096),
|
||||
Corona: make([]byte, 0, 4096),
|
||||
MLDSA: make([]byte, 0, 3309), // ML-DSA-65 sig size
|
||||
}
|
||||
},
|
||||
@@ -55,7 +55,7 @@ var (
|
||||
//
|
||||
// Three independent signing paths:
|
||||
// - BLS12-381: classical threshold signatures (ECDL hardness)
|
||||
// - Corona: Ring-LWE 2-round threshold signatures (Module-LWE hardness)
|
||||
// - Corona: Ring-LWE 2-round threshold signatures (Module-LWE hardness)
|
||||
// - ML-DSA-65: FIPS 204 post-quantum identity signatures (Module-LWE + Module-SIS)
|
||||
//
|
||||
// All three run in parallel via TripleSign. Each can be enabled independently.
|
||||
@@ -315,7 +315,7 @@ func (s *signer) VerifyCoronaSignature(message string, sig *coronaThreshold.Sign
|
||||
|
||||
// DualSignRound1 performs Round 1 of both BLS and Corona in parallel.
|
||||
// BLS: Computes signature share (single round)
|
||||
// Corona: Computes D matrix + MACs (Round 1 of 2)
|
||||
// Corona: Computes D matrix + MACs (Round 1 of 2)
|
||||
func (s *signer) DualSignRound1(ctx context.Context, validatorID string, message []byte, sessionID int, prfKey []byte) (*QuasarSig, *coronaThreshold.Round1Data, error) {
|
||||
s.mu.RLock()
|
||||
blsSigner, hasBLS := s.blsSigners[validatorID]
|
||||
@@ -381,7 +381,7 @@ func (s *signer) DualSignRound2(validatorID string, sessionID int, message strin
|
||||
|
||||
// TripleSignRound1 performs Round 1 of all three signing paths in parallel:
|
||||
// - BLS: threshold share (single round, complete)
|
||||
// - Corona: Round 1 of 2-round protocol (D matrix + MACs)
|
||||
// - Corona: Round 1 of 2-round protocol (D matrix + MACs)
|
||||
// - ML-DSA: full signature (single round, complete)
|
||||
//
|
||||
// Returns the QuasarSig with BLS + MLDSA filled, plus Corona Round1Data
|
||||
@@ -775,9 +775,10 @@ func (s *signer) VerifyAggregatedSignatureWithContext(ctx context.Context, messa
|
||||
|
||||
// QuasarSig contains BLS and optionally Corona signature data.
|
||||
type QuasarSig struct {
|
||||
BLS []byte // BLS12-381 signature (classical)
|
||||
Corona []byte // Corona Ring-LWE signature (PQ threshold)
|
||||
MLDSA []byte // ML-DSA-65 signature (PQ identity, FIPS 204)
|
||||
BLS []byte // BLS-12-381 aggregate (classical fast-path; empty in pure-PQ)
|
||||
Corona []byte // Corona (Ring-LWE) threshold signature
|
||||
Pulsar []byte // Pulsar-M (Module-LWE) threshold signature
|
||||
MLDSA []byte // Per-validator ML-DSA-65 (FIPS 204 identity attestation)
|
||||
ValidatorID string
|
||||
IsThreshold bool
|
||||
SignerIndex int
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestCRITICAL1_ThresholdSigWithoutVerifier(t *testing.T) {
|
||||
func TestCRITICAL2_QuasarCertVerifyRejectGarbage(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("garbage-bls-not-a-real-signature"),
|
||||
MLDSAProof: []byte("garbage-pq-not-a-real-certificate"),
|
||||
MLDSARollup: []byte("garbage-pq-not-a-real-certificate"),
|
||||
Validators: 0,
|
||||
}
|
||||
|
||||
@@ -99,15 +99,15 @@ func TestCRITICAL2_QuasarCertVerifyWithKeysNilCert(t *testing.T) {
|
||||
// BLS or PQ fields are rejected.
|
||||
func TestCRITICAL2_QuasarCertVerifyWithKeysEmptyFields(t *testing.T) {
|
||||
// Empty BLS
|
||||
cert := &QuasarCert{BLS: nil, MLDSAProof: []byte("pq")}
|
||||
cert := &QuasarCert{BLS: nil, MLDSARollup: []byte("pq")}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("pq")))
|
||||
|
||||
// Empty PQ
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSAProof: nil}
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: nil}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("pq")))
|
||||
|
||||
// Empty group key
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSAProof: []byte("pq")}
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: []byte("pq")}
|
||||
require.False(t, cert.VerifyWithKeys(nil, []byte("pq")))
|
||||
}
|
||||
|
||||
|
||||
@@ -665,7 +665,7 @@ func TestQuasarConsensusBasic(t *testing.T) {
|
||||
cert := hybrid.generateCert(block)
|
||||
require.NotNil(cert)
|
||||
require.NotEmpty(cert.BLS)
|
||||
require.NotEmpty(cert.MLDSAProof)
|
||||
require.NotEmpty(cert.MLDSARollup)
|
||||
require.Equal(uint64(1), cert.Epoch)
|
||||
|
||||
// Verify certificate: Verify() now always returns false (requires VerifyWithKeys)
|
||||
|
||||
@@ -74,7 +74,7 @@ func TestGenerateCert_RefusesPartialTriple_WithSigner_NoCorona(t *testing.T) {
|
||||
cert := c.generateCert(block)
|
||||
if cert != nil {
|
||||
t.Fatalf("strict-PQ profile + basic signer: expected nil cert, got Corona=%v MLDSAProof_len=%d",
|
||||
cert.Corona, len(cert.MLDSAProof))
|
||||
cert.Corona, len(cert.MLDSARollup))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +134,8 @@ func TestGenerateCert_NilProfile_AcceptsPlaceholder(t *testing.T) {
|
||||
func TestQuasarCert_Verify_RejectsMissingCorona(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
Corona: nil, // missing
|
||||
MLDSAProof: []byte("mldsa"),
|
||||
Corona: nil, // missing
|
||||
MLDSARollup: []byte("mldsa"),
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
@@ -150,8 +150,8 @@ func TestQuasarCert_Verify_RejectsMissingCorona(t *testing.T) {
|
||||
func TestQuasarCert_Verify_RejectsMissingMLDSA(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
Corona: []byte("rt"),
|
||||
MLDSAProof: nil, // missing
|
||||
Corona: []byte("rt"),
|
||||
MLDSARollup: nil, // missing
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
@@ -165,8 +165,8 @@ func TestQuasarCert_Verify_RejectsMissingMLDSA(t *testing.T) {
|
||||
func TestQuasarCert_Verify_RejectsMissingBLS(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: nil, // missing
|
||||
Corona: []byte("rt"),
|
||||
MLDSAProof: []byte("mldsa"),
|
||||
Corona: []byte("rt"),
|
||||
MLDSARollup: []byte("mldsa"),
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
|
||||
+109
-48
@@ -29,37 +29,93 @@ type Block struct {
|
||||
|
||||
// QuasarCert is the finality certificate for Quasar consensus.
|
||||
//
|
||||
// Three signature layers, each already compact on its own except ML-DSA:
|
||||
// Architectural shape — read the cardinality, not a counting word:
|
||||
//
|
||||
// BLS12-381 — classical aggregate (48 bytes, O(1) via native BLS aggregation)
|
||||
// Corona — lattice threshold signature (O(1) after DKG threshold signing)
|
||||
// ML-DSA-65 — per-validator PQ identity (3309 bytes × N validators, O(N))
|
||||
// BLS-12-381 — classical fast-path aggregate (48 B; pairing-based)
|
||||
// Corona — Ring-LWE threshold ML-DSA (O(1) after DKG; FIPS 204 Class N1)
|
||||
// Pulsar — Module-LWE threshold ML-DSA (O(1) after DKG; FIPS 204 Class N1)
|
||||
// MLDSARollup — per-validator ML-DSA-65 rolled into one STARK / Groth16 proof
|
||||
//
|
||||
// Z-Chain's sole job is to roll up ML-DSA × N into a single Groth16 SNARK:
|
||||
// Naming: the PQ-side is at most **Double Lattice** — Ring-LWE plus
|
||||
// Module-LWE. Calling the BLS+Corona+MLDSARollup composition "Triple
|
||||
// Quantum" is misleading because BLS is classical, not quantum. The
|
||||
// honest mode descriptor is "Classical + Double Lattice [+ Identity
|
||||
// Rollup]".
|
||||
//
|
||||
// Statement: ∀ i ∈ [N]: ML-DSA.Verify(mldsa_pk_i, msg, mldsa_σ_i) = 1
|
||||
// Output: 192-byte Groth16 proof (MLDSAProof)
|
||||
// Pure-PQ profile (no BLS, no classical curve in the validator path):
|
||||
// Corona + Pulsar (Double Lattice). Each layer is independently
|
||||
// FIPS 204 Class N1 (output verifies under the unmodified single-
|
||||
// party ML-DSA verifier). MLDSARollup is the identity attestation
|
||||
// layer, succinct via STARK (Z-Chain → P3Q).
|
||||
//
|
||||
// BLS and Corona don't need Z-Chain — they're already O(1).
|
||||
// Corona (academic R-LWE with trusted-dealer DKG) is NOT a
|
||||
// production option for an open public chain. Corona is the
|
||||
// production Ring-LWE library (Pedersen DKG over R_q + proactive
|
||||
// resharing; `luxfi/corona`). The historic field name "Corona"
|
||||
// in this struct refers to "the Ring-LWE threshold slot"; that
|
||||
// slot now carries Corona bytes. The field is renamed accordingly.
|
||||
//
|
||||
// Total cert size: 48 (BLS) + |Corona| + 192 (MLDSAProof), constant in N.
|
||||
// MLDSARollup is succinct: a single STARK/Groth16 proof attests
|
||||
// "∀ i ∈ [N]: ML-DSA.Verify(mldsa_pk_i, msg, mldsa_σ_i) = 1". Output
|
||||
// is one constant-size proof (192 B for Groth16, ~30 KB for a STARK
|
||||
// like P3Q), constant in validator count.
|
||||
//
|
||||
// Total cert size: 48 (BLS, optional) + |Corona| + |Pulsar| + |MLDSARollup|.
|
||||
type QuasarCert struct {
|
||||
BLS []byte // BLS12-381 aggregate (48 bytes, classical)
|
||||
Corona []byte // Corona lattice threshold sig (O(1) after DKG)
|
||||
MLDSAProof []byte // Z-Chain Groth16 rolling up N × ML-DSA identity sigs (192 bytes)
|
||||
Epoch uint64 // Epoch number
|
||||
Finality time.Time // Time of finality
|
||||
Validators int `json:"validators,omitempty"` // Count of signing validators
|
||||
BLS []byte // BLS-12-381 aggregate (48 bytes, classical fast-path; empty in pure-PQ)
|
||||
Corona []byte // Ring-LWE threshold sig (Corona; O(1) after DKG)
|
||||
Pulsar []byte // Module-LWE threshold sig (Pulsar-M; O(1) after DKG; optional)
|
||||
MLDSARollup []byte // Succinct rollup of per-validator ML-DSA-65 (STARK or Groth16)
|
||||
Epoch uint64 // Epoch number
|
||||
Finality time.Time // Time of finality
|
||||
Validators int `json:"validators,omitempty"` // Count of signing validators
|
||||
}
|
||||
|
||||
// Verify checks structural presence of BLS and PQ certificates.
|
||||
// Use VerifyWithKeys for cryptographic verification. Returns true only if
|
||||
// all three signature fields are non-empty -- this is a fast structural gate.
|
||||
// IsDoubleLattice reports whether the cert carries both Ring-LWE
|
||||
// (Corona) and Module-LWE (Pulsar) threshold legs. This is the honest
|
||||
// post-quantum cardinality: two independent algebraic-lattice families,
|
||||
// each independently a FIPS 204 Class N1 threshold producer.
|
||||
//
|
||||
// BLS is irrelevant to this predicate by design — a pure-PQ cert has
|
||||
// no BLS bytes; a hybrid cert layers BLS over a Double-Lattice PQ
|
||||
// surface. Either way, the PQ-side cardinality is what IsDoubleLattice
|
||||
// names.
|
||||
func (c *QuasarCert) IsDoubleLattice() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return len(c.Corona) > 0 && len(c.Pulsar) > 0
|
||||
}
|
||||
|
||||
// HasClassicalFastPath reports whether the cert carries BLS bytes — the
|
||||
// optional classical aggregate that rides alongside the PQ surface on
|
||||
// chains that opt into the hybrid posture. Empty in pure-PQ mode.
|
||||
func (c *QuasarCert) HasClassicalFastPath() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return len(c.BLS) > 0
|
||||
}
|
||||
|
||||
// HasIdentityRollup reports whether the cert carries the
|
||||
// per-validator ML-DSA-65 identity attestation rolled up into a
|
||||
// succinct STARK/Groth16 proof.
|
||||
func (c *QuasarCert) HasIdentityRollup() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return len(c.MLDSARollup) > 0
|
||||
}
|
||||
|
||||
// Verify checks structural presence of the Quasar layers: BLS fast-path
|
||||
// + Corona (Ring-LWE) + MLDSARollup. Use VerifyWithRealKeys for
|
||||
// cryptographic verification. Returns false if any required slot is
|
||||
// empty — fast structural gate.
|
||||
func (c *QuasarCert) Verify(validators []string) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
if len(c.BLS) == 0 || len(c.Corona) == 0 || len(c.MLDSAProof) == 0 {
|
||||
if len(c.BLS) == 0 || len(c.Corona) == 0 || len(c.MLDSARollup) == 0 {
|
||||
return false
|
||||
}
|
||||
if c.Validators > 0 && len(validators) > 0 && len(validators) < c.Validators {
|
||||
@@ -68,15 +124,15 @@ func (c *QuasarCert) Verify(validators []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// VerifyWithKeys is a back-compat structural check that mirrors the previous
|
||||
// API: returns false unless all three signature fields are present and the
|
||||
// provided opaque key material is non-empty. Real cryptographic verification
|
||||
// is in VerifyWithRealKeys.
|
||||
// VerifyWithKeys is a back-compat structural check that mirrors the
|
||||
// previous API: returns false unless BLS + Corona + MLDSARollup are
|
||||
// present and the provided opaque key material is non-empty. Real
|
||||
// cryptographic verification is in VerifyWithRealKeys.
|
||||
func (c *QuasarCert) VerifyWithKeys(groupKey []byte, pqKey []byte) bool {
|
||||
if c == nil || len(groupKey) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(c.BLS) == 0 || len(c.Corona) == 0 || len(c.MLDSAProof) == 0 {
|
||||
if len(c.BLS) == 0 || len(c.Corona) == 0 || len(c.MLDSARollup) == 0 {
|
||||
return false
|
||||
}
|
||||
// The structural check passed; cryptographic verification requires
|
||||
@@ -84,18 +140,22 @@ func (c *QuasarCert) VerifyWithKeys(groupKey []byte, pqKey []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// VerifyWithRealKeys performs cryptographic verification of the certificate.
|
||||
// A Quasar cert is finalized iff all three components verify in parallel:
|
||||
// - BLS12-381 aggregate against blsAggPubKey (classical, fast path)
|
||||
// - Corona threshold sig against rtGroupKey (lattice PQ)
|
||||
// VerifyWithRealKeys performs cryptographic verification of the
|
||||
// certificate. A Quasar cert is finalised iff the configured layers
|
||||
// verify in parallel:
|
||||
//
|
||||
// - BLS-12-381 aggregate against blsAggPubKey (classical fast path)
|
||||
// - Corona (Ring-LWE threshold ML-DSA) against rtGroupKey (PQ)
|
||||
// - Per-validator ML-DSA-65 sigs against mldsaPubKeys (FIPS 204 PQ)
|
||||
//
|
||||
// Defense in depth: classical AND two independent PQ schemes. Any single
|
||||
// scheme broken does not break finality.
|
||||
// Defence-in-depth posture is classical + (one or two PQ lattice
|
||||
// schemes) + identity rollup. Any single scheme broken does not break
|
||||
// finality.
|
||||
//
|
||||
// message is the digest the signers committed to. mldsaPubKeys may be nil
|
||||
// if MLDSAProof is empty (PQ rollup not yet wired). nil rtGroupKey skips
|
||||
// the Corona check (used when running in BLS-only mode).
|
||||
// message is the digest the signers committed to. mldsaPubKeys may be
|
||||
// nil if MLDSARollup is empty (rollup not yet wired). nil rtGroupKey
|
||||
// skips the Corona check (used when running in BLS-only mode or in a
|
||||
// Pulsar-only pure-PQ posture).
|
||||
func (c *QuasarCert) VerifyWithRealKeys(message []byte, blsAggPubKey *bls.PublicKey, rtGroupKey *coronaThreshold.GroupKey, mldsaPubKeys []*mldsa.PublicKey) bool {
|
||||
if c == nil || len(message) == 0 {
|
||||
return false
|
||||
@@ -116,8 +176,8 @@ func (c *QuasarCert) VerifyWithRealKeys(message []byte, blsAggPubKey *bls.Public
|
||||
return false
|
||||
}
|
||||
|
||||
// 2. Corona threshold verify (PQ lattice). Optional: skipped when
|
||||
// rtGroupKey is nil (BLS-only mode).
|
||||
// 2. Corona threshold verify (Ring-LWE PQ). Optional: skipped when
|
||||
// rtGroupKey is nil (BLS-only mode or Pulsar-only pure-PQ).
|
||||
if rtGroupKey != nil {
|
||||
if len(c.Corona) == 0 {
|
||||
return false
|
||||
@@ -131,20 +191,21 @@ func (c *QuasarCert) VerifyWithRealKeys(message []byte, blsAggPubKey *bls.Public
|
||||
}
|
||||
}
|
||||
|
||||
// 3. ML-DSA-65 verify (PQ identity, FIPS 204). The MLDSAProof field
|
||||
// holds either a single Groth16 rollup (Z-Chain) or a concatenation
|
||||
// of per-validator ML-DSA-65 sigs. We support the per-validator path
|
||||
// here by serializing each sig with a 4-byte length prefix.
|
||||
if len(c.MLDSAProof) > 0 {
|
||||
// 3. ML-DSA-65 verify (PQ identity, FIPS 204). The MLDSARollup field
|
||||
// holds either a single STARK/Groth16 rollup (Z-Chain → P3Q) or a
|
||||
// concatenation of per-validator ML-DSA-65 sigs. We support the
|
||||
// per-validator path here by serialising each sig with a 4-byte
|
||||
// length prefix.
|
||||
if len(c.MLDSARollup) > 0 {
|
||||
if len(mldsaPubKeys) == 0 {
|
||||
return false
|
||||
}
|
||||
sigs, err := decodeMLDSASigs(c.MLDSAProof)
|
||||
sigs, err := decodeMLDSASigs(c.MLDSARollup)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Need at least Validators good sigs. If MLDSAProof was a single
|
||||
// Groth16 rollup, we'd verify it once; for now we require N sigs
|
||||
// Need at least Validators good sigs. If MLDSARollup was a single
|
||||
// succinct rollup, we'd verify it once; for now we require N sigs
|
||||
// matching the public keys provided.
|
||||
if len(sigs) > len(mldsaPubKeys) {
|
||||
return false
|
||||
@@ -186,7 +247,7 @@ func (c *QuasarCert) MarshalBinary() ([]byte, error) {
|
||||
return nil, errors.New("quasar: signature too large")
|
||||
}
|
||||
|
||||
out := make([]byte, 0, 1+2+len(c.BLS)+2+len(c.Corona)+4+len(c.MLDSAProof)+8+8+2)
|
||||
out := make([]byte, 0, 1+2+len(c.BLS)+2+len(c.Corona)+4+len(c.MLDSARollup)+8+8+2)
|
||||
out = append(out, CertSchemeQuasar)
|
||||
|
||||
var u16 [2]byte
|
||||
@@ -201,9 +262,9 @@ func (c *QuasarCert) MarshalBinary() ([]byte, error) {
|
||||
out = append(out, u16[:]...)
|
||||
out = append(out, c.Corona...)
|
||||
|
||||
binary.BigEndian.PutUint32(u32[:], uint32(len(c.MLDSAProof)))
|
||||
binary.BigEndian.PutUint32(u32[:], uint32(len(c.MLDSARollup)))
|
||||
out = append(out, u32[:]...)
|
||||
out = append(out, c.MLDSAProof...)
|
||||
out = append(out, c.MLDSARollup...)
|
||||
|
||||
binary.BigEndian.PutUint64(u64[:], c.Epoch)
|
||||
out = append(out, u64[:]...)
|
||||
@@ -257,7 +318,7 @@ func (c *QuasarCert) UnmarshalBinary(data []byte) error {
|
||||
if off+mldsaLen > len(data) {
|
||||
return ErrCertCorrupt
|
||||
}
|
||||
c.MLDSAProof = append(c.MLDSAProof[:0], data[off:off+mldsaLen]...)
|
||||
c.MLDSARollup = append(c.MLDSARollup[:0], data[off:off+mldsaLen]...)
|
||||
off += mldsaLen
|
||||
|
||||
if off+8+8+2 > len(data) {
|
||||
@@ -377,7 +438,7 @@ type CoronaSignature struct {
|
||||
// Per-validator (collected during consensus, NOT stored in block):
|
||||
//
|
||||
// BLS: sign with BLS key → aggregate into 48 bytes (ECDL)
|
||||
// Corona: sign with ring-LWE key → PQ threshold proof (Module-LWE)
|
||||
// Corona: sign with ring-LWE key → PQ threshold proof (Module-LWE)
|
||||
// ML-DSA: sign with ML-DSA-65 key → PQ identity proof (Module-LWE + Module-SIS)
|
||||
//
|
||||
// In QuasarCert (stored in block header):
|
||||
|
||||
Reference in New Issue
Block a user