mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-04-26 12:56:21 +02:00
Release prep: 54 engines, self-hosted signatures, i18n, dashboard updates
This commit is contained in:
parent
694e32be26
commit
41cbfd6e0a
178 changed files with 36008 additions and 399 deletions
200
internal/infrastructure/pqcrypto/pqcrypto.go
Normal file
200
internal/infrastructure/pqcrypto/pqcrypto.go
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// Package pqcrypto implements SEC-013 (Homomorphic Encryption research)
|
||||
// and SEC-014 (Post-Quantum Signatures).
|
||||
//
|
||||
// SEC-013: Provides an interface for future lattice-based HE integration
|
||||
// (CKKS/BFV schemes) to enable correlation on encrypted events.
|
||||
//
|
||||
// SEC-014: Implements CRYSTALS-Dilithium-like post-quantum signatures
|
||||
// using a hybrid classical+PQ approach for Decision Logger chain.
|
||||
//
|
||||
// Current state: Research stubs with interface definitions.
|
||||
// Production: requires official NIST PQC library bindings.
|
||||
package pqcrypto
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// --- SEC-014: Post-Quantum Signatures ---
|
||||
|
||||
// SignatureScheme defines the signature algorithm.
|
||||
type SignatureScheme string
|
||||
|
||||
const (
|
||||
SchemeClassical SignatureScheme = "ed25519"
|
||||
SchemeHybrid SignatureScheme = "hybrid-ed25519-dilithium"
|
||||
SchemeDilithium SignatureScheme = "dilithium3" // CRYSTALS-Dilithium Level 3
|
||||
)
|
||||
|
||||
// HybridSignature combines classical Ed25519 + post-quantum signature.
|
||||
type HybridSignature struct {
|
||||
ClassicalSig string `json:"classical_sig"` // Ed25519
|
||||
PQSig string `json:"pq_sig"` // Dilithium (simulated)
|
||||
Scheme SignatureScheme `json:"scheme"`
|
||||
Hash string `json:"hash"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// HybridSigner provides quantum-resistant signing with classical fallback.
|
||||
type HybridSigner struct {
|
||||
mu sync.RWMutex
|
||||
scheme SignatureScheme
|
||||
classicalPub ed25519.PublicKey
|
||||
classicalPriv ed25519.PrivateKey
|
||||
logger *slog.Logger
|
||||
stats SignerStats
|
||||
}
|
||||
|
||||
// SignerStats tracks signing metrics.
|
||||
type SignerStats struct {
|
||||
mu sync.Mutex
|
||||
TotalSigns int64 `json:"total_signs"`
|
||||
TotalVerifies int64 `json:"total_verifies"`
|
||||
Scheme SignatureScheme `json:"scheme"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
}
|
||||
|
||||
// NewHybridSigner creates a new post-quantum hybrid signer.
|
||||
func NewHybridSigner(scheme SignatureScheme) (*HybridSigner, error) {
|
||||
pub, priv, err := ed25519.GenerateKey(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pqcrypto: generate ed25519 key: %w", err)
|
||||
}
|
||||
|
||||
signer := &HybridSigner{
|
||||
scheme: scheme,
|
||||
classicalPub: pub,
|
||||
classicalPriv: priv,
|
||||
logger: slog.Default().With("component", "sec-014-pqcrypto"),
|
||||
stats: SignerStats{
|
||||
Scheme: scheme,
|
||||
StartedAt: time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
signer.logger.Info("hybrid signer initialized",
|
||||
"scheme", scheme,
|
||||
"classical", "ed25519",
|
||||
)
|
||||
|
||||
return signer, nil
|
||||
}
|
||||
|
||||
// Sign creates a hybrid (classical + PQ) signature.
|
||||
func (hs *HybridSigner) Sign(data []byte) (*HybridSignature, error) {
|
||||
hs.stats.mu.Lock()
|
||||
hs.stats.TotalSigns++
|
||||
hs.stats.mu.Unlock()
|
||||
|
||||
hash := sha256.Sum256(data)
|
||||
hashHex := hex.EncodeToString(hash[:])
|
||||
|
||||
// Classical Ed25519 signature.
|
||||
classicalSig := ed25519.Sign(hs.classicalPriv, hash[:])
|
||||
|
||||
// Post-quantum signature (simulated — real impl needs CRYSTALS-Dilithium).
|
||||
pqSig := simulateDilithiumSign(hash[:])
|
||||
|
||||
return &HybridSignature{
|
||||
ClassicalSig: hex.EncodeToString(classicalSig),
|
||||
PQSig: pqSig,
|
||||
Scheme: hs.scheme,
|
||||
Hash: hashHex,
|
||||
Timestamp: time.Now(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Verify checks both classical and PQ signatures.
|
||||
func (hs *HybridSigner) Verify(data []byte, sig *HybridSignature) bool {
|
||||
hs.stats.mu.Lock()
|
||||
hs.stats.TotalVerifies++
|
||||
hs.stats.mu.Unlock()
|
||||
|
||||
hash := sha256.Sum256(data)
|
||||
|
||||
// Verify classical signature.
|
||||
classicalSigBytes, err := hex.DecodeString(sig.ClassicalSig)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !ed25519.Verify(hs.classicalPub, hash[:], classicalSigBytes) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify PQ signature (simulated).
|
||||
if !simulateDilithiumVerify(hash[:], sig.PQSig) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PublicKeyHex returns the classical public key.
|
||||
func (hs *HybridSigner) PublicKeyHex() string {
|
||||
return hex.EncodeToString(hs.classicalPub)
|
||||
}
|
||||
|
||||
// Stats returns signer metrics.
|
||||
func (hs *HybridSigner) Stats() SignerStats {
|
||||
hs.stats.mu.Lock()
|
||||
defer hs.stats.mu.Unlock()
|
||||
return SignerStats{
|
||||
TotalSigns: hs.stats.TotalSigns,
|
||||
TotalVerifies: hs.stats.TotalVerifies,
|
||||
Scheme: hs.stats.Scheme,
|
||||
StartedAt: hs.stats.StartedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// --- SEC-013: Homomorphic Encryption (Research Interface) ---
|
||||
|
||||
// HEScheme defines the homomorphic encryption scheme.
|
||||
type HEScheme string
|
||||
|
||||
const (
|
||||
HE_CKKS HEScheme = "CKKS" // Approximate arithmetic (ML-friendly)
|
||||
HE_BFV HEScheme = "BFV" // Exact integer arithmetic
|
||||
)
|
||||
|
||||
// EncryptedEvent represents a homomorphically encrypted SOC event.
|
||||
type EncryptedEvent struct {
|
||||
CiphertextID string `json:"ciphertext_id"`
|
||||
Scheme HEScheme `json:"scheme"`
|
||||
FieldCount int `json:"field_count"`
|
||||
Created time.Time `json:"created"`
|
||||
}
|
||||
|
||||
// HEEngine defines the interface for homomorphic encryption operations.
|
||||
// This is a research interface — real implementation requires a lattice-based
|
||||
// HE library (e.g., Microsoft SEAL, OpenFHE, or Lattigo for Go).
|
||||
type HEEngine interface {
|
||||
// Encrypt encrypts event fields for correlation without decryption.
|
||||
Encrypt(fields map[string]float64) (*EncryptedEvent, error)
|
||||
|
||||
// CorrelateEncrypted runs correlation rules on encrypted events.
|
||||
CorrelateEncrypted(events []*EncryptedEvent) (float64, error)
|
||||
|
||||
// Decrypt recovers plaintext (requires private key).
|
||||
Decrypt(event *EncryptedEvent) (map[string]float64, error)
|
||||
}
|
||||
|
||||
// --- Simulated PQ functions ---
|
||||
|
||||
func simulateDilithiumSign(hash []byte) string {
|
||||
// Simulated Dilithium signature: SHA-256 of hash with prefix.
|
||||
// In production: use circl or pqcrypto-go for real Dilithium.
|
||||
prefixed := append([]byte("DILITHIUM3-SIM:"), hash...)
|
||||
sig := sha256.Sum256(prefixed)
|
||||
return hex.EncodeToString(sig[:])
|
||||
}
|
||||
|
||||
func simulateDilithiumVerify(hash []byte, sigHex string) bool {
|
||||
expected := simulateDilithiumSign(hash)
|
||||
return expected == sigHex
|
||||
}
|
||||
83
internal/infrastructure/pqcrypto/pqcrypto_test.go
Normal file
83
internal/infrastructure/pqcrypto/pqcrypto_test.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package pqcrypto
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewHybridSigner(t *testing.T) {
|
||||
signer, err := NewHybridSigner(SchemeHybrid)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridSigner: %v", err)
|
||||
}
|
||||
if signer.PublicKeyHex() == "" {
|
||||
t.Error("public key empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignAndVerify(t *testing.T) {
|
||||
signer, err := NewHybridSigner(SchemeHybrid)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridSigner: %v", err)
|
||||
}
|
||||
|
||||
data := []byte("decision: allow event EVT-001")
|
||||
sig, err := signer.Sign(data)
|
||||
if err != nil {
|
||||
t.Fatalf("Sign: %v", err)
|
||||
}
|
||||
|
||||
if sig.ClassicalSig == "" {
|
||||
t.Error("classical sig empty")
|
||||
}
|
||||
if sig.PQSig == "" {
|
||||
t.Error("PQ sig empty")
|
||||
}
|
||||
if sig.Scheme != SchemeHybrid {
|
||||
t.Errorf("scheme = %s, want hybrid", sig.Scheme)
|
||||
}
|
||||
|
||||
if !signer.Verify(data, sig) {
|
||||
t.Error("verification failed for valid signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_TamperedData(t *testing.T) {
|
||||
signer, _ := NewHybridSigner(SchemeHybrid)
|
||||
|
||||
data := []byte("original data")
|
||||
sig, _ := signer.Sign(data)
|
||||
|
||||
tamperedData := []byte("tampered data")
|
||||
if signer.Verify(tamperedData, sig) {
|
||||
t.Error("should fail for tampered data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_TamperedSig(t *testing.T) {
|
||||
signer, _ := NewHybridSigner(SchemeHybrid)
|
||||
|
||||
data := []byte("test data")
|
||||
sig, _ := signer.Sign(data)
|
||||
|
||||
sig.PQSig = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
if signer.Verify(data, sig) {
|
||||
t.Error("should fail for tampered PQ sig")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStats(t *testing.T) {
|
||||
signer, _ := NewHybridSigner(SchemeHybrid)
|
||||
|
||||
signer.Sign([]byte("a"))
|
||||
signer.Sign([]byte("b"))
|
||||
sig, _ := signer.Sign([]byte("c"))
|
||||
signer.Verify([]byte("c"), sig)
|
||||
|
||||
stats := signer.Stats()
|
||||
if stats.TotalSigns != 3 {
|
||||
t.Errorf("signs = %d, want 3", stats.TotalSigns)
|
||||
}
|
||||
if stats.TotalVerifies != 1 {
|
||||
t.Errorf("verifies = %d, want 1", stats.TotalVerifies)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue