mirror of
https://github.com/luxfi/corona.git
synced 2026-07-27 02:50:34 +00:00
Corona is Module-LWE (threshold-Raccoon/Ringtail), NOT Ring-LWE. Confirmed in code: sign/sign.go samples A in R_q^{8x7} (sign.go:87 SamplePolyMatrix M=8,N=7), secret s a rank-7 ring vector, b=A*s+e (sign.go:106-107) over R_q=Z_q[X]/(X^256+1) (LogN=8), q=0x1000000004A01 -- rank>1 module structure, not rank-1 ring-LWE. threshold/threshold.go:4-5 already said Module-LWE.
Fixed the family label across README, SPEC, SUBMISSION, NIST-SUBMISSION, PATENTS, LLM, CONTRIBUTING, SECURITY, CHANGELOG, DEPLOYMENT-RUNBOOK, Makefile, AXIOM-INVENTORY, PROOF-CLAIMS, BLOCKERS, CRYPTOGRAPHER-SIGN-OFF, FIPS-TRACEABILITY, TRUSTED-COMPUTING-BASE, AUDIT-2026-05/06, docs/mptc/*, jasmin/README, 3 Go comments + cli help string.
Also corrected the downstream false claim that Corona (Ring-LWE) and Pulsar (Module-LWE) are 'different lattice families' giving 'structural/family diversity': both are Module-LWE, so the Double-Lattice defense is construction/implementation diversity (threshold-Raccoon vs ML-DSA), not hardness-family diversity; a Module-LWE break affects both legs (hash-based Magnetar is the assumption-diversifier). Fixed companion R-SIS -> Module-SIS where it was the module scheme's SIS assumption; added the Langlois-Stehle (DCC 2015) Module-LWE citation alongside LPR 2010.
Delicate artifacts: proof identifiers (rlwe_sign_op, RLWE_Functional theory/file, *_eq_rlwe bridges, CentralRLWESign, RLWESign, rlwe_compute_*) were NOT renamed -- EasyCrypt/jasmin toolchains are absent here so a rename cannot be compile-verified, and .assurance/ gates parse those names. Added clarifying naming notes to the 5 prominent .ec files, proofs/easycrypt/README.md, AXIOM-INVENTORY.md, and jasmin/rlwe/sign.jazz. .assurance/*.txt left untouched (already say Module-LWE/Module-SIS; rlwe tokens are gate-parsed identifiers). Left AUDIT-2026-06.md:463 historical rename-log and the ProtoStar-LWE paper-title substring untouched.
go build ./... and go test ./... green (GOWORK=off; all packages ok).
96 lines
2.7 KiB
Go
96 lines
2.7 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package threshold
|
|
|
|
// verify_batch.go -- parallel CPU batch verifier for Corona
|
|
// (Module-LWE 2-round threshold) signatures.
|
|
//
|
|
// Corona signatures are NOT FIPS 204 byte-equal (that's Pulsar's
|
|
// Module-LWE sibling); the wire encoding is the (C, Z, Delta) ring
|
|
// polynomial triple defined in threshold.go. Verification is the
|
|
// single sign.Verify call wrapped by Verify() in threshold.go; this
|
|
// file composes it across N (groupKey, message, signature) tuples
|
|
// in parallel.
|
|
//
|
|
// Pure-Go, no CGO: keeps Corona portable. GPU dispatch (an NTT-batch
|
|
// kernel over the verifier's polynomial-arithmetic hotspot) is a
|
|
// luxfi/accel concern; consumers that want it call accel directly
|
|
// against the same wire bytes.
|
|
|
|
import (
|
|
"errors"
|
|
"runtime"
|
|
"sync"
|
|
)
|
|
|
|
// ErrBatchSizeMismatch is returned when groupKeys, messages, and sigs
|
|
// do not all have the same length.
|
|
var ErrBatchSizeMismatch = errors.New("corona: batch slices length mismatch")
|
|
|
|
// VerifyBatch verifies N (groupKey, message, signature) tuples in
|
|
// parallel. results[i] is true iff the i-th signature is valid under
|
|
// Verify(groupKeys[i], messages[i], sigs[i]).
|
|
//
|
|
// The slices MUST have equal length; mismatches return
|
|
// ErrBatchSizeMismatch with a nil results slice.
|
|
//
|
|
// Empty input (len == 0) returns (nil, nil).
|
|
//
|
|
// Parallelism is bounded by GOMAXPROCS so a caller that already has
|
|
// its own concurrency doesn't oversaturate the CPU.
|
|
//
|
|
// VerifyBatch is the canonical entry point for any consumer that
|
|
// needs to verify > 1 Corona signature. Use Verify only when N == 1.
|
|
func VerifyBatch(groupKeys []*GroupKey, messages []string, sigs []*Signature) ([]bool, error) {
|
|
n := len(sigs)
|
|
if n != len(groupKeys) || n != len(messages) {
|
|
return nil, ErrBatchSizeMismatch
|
|
}
|
|
if n == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
results := make([]bool, n)
|
|
|
|
workers := runtime.GOMAXPROCS(0)
|
|
if workers > n {
|
|
workers = n
|
|
}
|
|
|
|
jobs := make(chan int, n)
|
|
var wg sync.WaitGroup
|
|
wg.Add(workers)
|
|
for w := 0; w < workers; w++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := range jobs {
|
|
results[i] = Verify(groupKeys[i], messages[i], sigs[i])
|
|
}
|
|
}()
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
jobs <- i
|
|
}
|
|
close(jobs)
|
|
wg.Wait()
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// VerifyBatchAll is a convenience predicate: true iff every signature
|
|
// in the batch verifies. Returns (false, err) only on the structural
|
|
// ErrBatchSizeMismatch.
|
|
func VerifyBatchAll(groupKeys []*GroupKey, messages []string, sigs []*Signature) (bool, error) {
|
|
results, err := VerifyBatch(groupKeys, messages, sigs)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, ok := range results {
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|