Files
corona/threshold/verify_batch.go
T
zeekay df1db68bd0 docs/comments: correct lattice-family label Ring-LWE -> Module-LWE (Corona is Module-LWE)
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).
2026-06-27 16:12:24 -07:00

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
}