mirror of
https://github.com/luxfi/indexer.git
synced 2026-09-24 00:25:37 +00:00
866 lines
27 KiB
Go
866 lines
27 KiB
Go
// Copyright (c) 2025 Lux Industries Inc
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// Package qchain provides the Q-Chain (Quantum) adapter for the DAG indexer.
|
|
// Q-Chain handles quantum-resistant finality proofs using lattice-based cryptography.
|
|
package quantum
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/luxfi/indexer/dag"
|
|
"github.com/luxfi/indexer/storage"
|
|
)
|
|
|
|
const (
|
|
// DefaultRPCEndpoint is the default Q-Chain RPC endpoint
|
|
DefaultRPCEndpoint = "http://localhost:9650/v1/chain/Q/rpc"
|
|
// DefaultHTTPPort is the default API port for Q-Chain indexer
|
|
DefaultHTTPPort = 4300
|
|
)
|
|
|
|
// QuasarCert is the dual consensus finality certificate.
|
|
// Matches github.com/luxfi/consensus/protocol/quasar.QuasarCert.
|
|
//
|
|
// Two verification paths:
|
|
// 1. BLS aggregate (48 bytes) — classical fast-path consensus (BLS12-381)
|
|
// 2. PQ proof (variable) — post-quantum certificate (ML-DSA-65 or Corona)
|
|
type QuasarCert struct {
|
|
ID string `json:"id"`
|
|
VertexID string `json:"vertexId"`
|
|
BLS []byte `json:"bls"` // BLS aggregate signature (48 bytes)
|
|
PQProof []byte `json:"pqProof"` // STARK proof aggregating N ML-DSA sigs (~200 bytes)
|
|
Epoch uint64 `json:"epoch"`
|
|
Finality time.Time `json:"finality"`
|
|
Validators int `json:"validators"` // Count of validators proven by PQProof
|
|
}
|
|
|
|
// FinalityProof represents a quantum-resistant finality proof (legacy lattice-level detail).
|
|
type FinalityProof struct {
|
|
ID string `json:"id"`
|
|
VertexID string `json:"vertexId"`
|
|
ProofType ProofType `json:"proofType"`
|
|
LatticeParams Lattice `json:"latticeParams"`
|
|
Signature []byte `json:"signature"`
|
|
PublicKey []byte `json:"publicKey"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Verified bool `json:"verified"`
|
|
}
|
|
|
|
// ProofType identifies the quantum-resistant algorithm used
|
|
type ProofType string
|
|
|
|
const (
|
|
ProofDilithium ProofType = "dilithium" // NIST PQC standard
|
|
ProofKyber ProofType = "kyber" // Key encapsulation
|
|
ProofFalcon ProofType = "falcon" // Fast lattice-based
|
|
ProofSphincsh ProofType = "sphincs+" // Hash-based
|
|
)
|
|
|
|
// Lattice contains lattice-based cryptography parameters
|
|
type Lattice struct {
|
|
Dimension int `json:"dimension"` // Lattice dimension (n)
|
|
Modulus int64 `json:"modulus"` // Modulus (q)
|
|
ErrorBound int `json:"errorBound"` // Error distribution bound
|
|
SecurityLvl int `json:"securityLvl"` // NIST security level (1-5)
|
|
Algorithm string `json:"algorithm"` // Specific algorithm variant
|
|
}
|
|
|
|
// QuantumVertex extends DAG vertex with quantum-specific data
|
|
type QuantumVertex struct {
|
|
dag.Vertex
|
|
QuasarCert *QuasarCert `json:"quasarCert,omitempty"`
|
|
FinalityProof *FinalityProof `json:"finalityProof,omitempty"`
|
|
ProofCount int `json:"proofCount"`
|
|
Finalized bool `json:"finalized"`
|
|
}
|
|
|
|
// QuantumStamp represents a quantum-certified timestamp for finality
|
|
type QuantumStamp struct {
|
|
ID string `json:"id"`
|
|
VertexID string `json:"vertexId"`
|
|
ChainID string `json:"chainId"` // Which chain this stamp is for
|
|
BlockHeight uint64 `json:"blockHeight"` // Block height being stamped
|
|
BlockHash []byte `json:"blockHash"` // Block hash being certified
|
|
Entropy []byte `json:"entropy"` // Quantum random entropy
|
|
KeyID string `json:"keyId"` // Corona key used for signing
|
|
Signature []byte `json:"signature"` // Quantum-resistant signature
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Certified bool `json:"certified"` // Whether stamp has been verified
|
|
}
|
|
|
|
// CoronaKey represents a quantum-resistant signing key (Corona is LUX's post-quantum signature scheme)
|
|
type CoronaKey struct {
|
|
ID string `json:"id"`
|
|
PublicKey []byte `json:"publicKey"`
|
|
KeyType ProofType `json:"keyType"` // dilithium, falcon, sphincs+
|
|
Algorithm string `json:"algorithm"` // Specific algorithm variant
|
|
SecurityLvl int `json:"securityLevel"` // NIST security level 1-5
|
|
Owner string `json:"owner"` // Key owner address
|
|
ValidFrom time.Time `json:"validFrom"`
|
|
ValidUntil time.Time `json:"validUntil"`
|
|
Revoked bool `json:"revoked"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
}
|
|
|
|
// Adapter implements dag.Adapter for Q-Chain
|
|
type Adapter struct {
|
|
rpcEndpoint string
|
|
httpClient *http.Client
|
|
}
|
|
|
|
// New creates a new Q-Chain adapter
|
|
func New(rpcEndpoint string) *Adapter {
|
|
if rpcEndpoint == "" {
|
|
rpcEndpoint = DefaultRPCEndpoint
|
|
}
|
|
return &Adapter{
|
|
rpcEndpoint: rpcEndpoint,
|
|
httpClient: &http.Client{Timeout: 30 * time.Second},
|
|
}
|
|
}
|
|
|
|
// rpcRequest represents a JSON-RPC request
|
|
type rpcRequest struct {
|
|
JSONRPC string `json:"jsonrpc"`
|
|
ID int `json:"id"`
|
|
Method string `json:"method"`
|
|
Params []interface{} `json:"params,omitempty"`
|
|
}
|
|
|
|
// rpcResponse represents a JSON-RPC response
|
|
type rpcResponse struct {
|
|
JSONRPC string `json:"jsonrpc"`
|
|
ID int `json:"id"`
|
|
Result json.RawMessage `json:"result,omitempty"`
|
|
Error *rpcError `json:"error,omitempty"`
|
|
}
|
|
|
|
type rpcError struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// call executes an RPC request to the Q-Chain node
|
|
func (a *Adapter) call(ctx context.Context, method string, params ...interface{}) (json.RawMessage, error) {
|
|
req := rpcRequest{
|
|
JSONRPC: "2.0",
|
|
ID: 1,
|
|
Method: method,
|
|
Params: params,
|
|
}
|
|
|
|
body, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal request: %w", err)
|
|
}
|
|
|
|
httpReq, err := http.NewRequestWithContext(ctx, "POST", a.rpcEndpoint, bytes.NewReader(body))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create request: %w", err)
|
|
}
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := a.httpClient.Do(httpReq)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("http request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var rpcResp rpcResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&rpcResp); err != nil {
|
|
return nil, fmt.Errorf("decode response: %w", err)
|
|
}
|
|
|
|
if rpcResp.Error != nil {
|
|
return nil, fmt.Errorf("rpc error %d: %s", rpcResp.Error.Code, rpcResp.Error.Message)
|
|
}
|
|
|
|
return rpcResp.Result, nil
|
|
}
|
|
|
|
// ParseVertex parses raw RPC data into a DAG vertex
|
|
func (a *Adapter) ParseVertex(data json.RawMessage) (*dag.Vertex, error) {
|
|
var qv QuantumVertex
|
|
if err := json.Unmarshal(data, &qv); err != nil {
|
|
return nil, fmt.Errorf("unmarshal quantum vertex: %w", err)
|
|
}
|
|
|
|
// Build metadata with quantum-specific fields
|
|
meta := make(map[string]interface{})
|
|
if qv.QuasarCert != nil {
|
|
meta["quasar_cert"] = true
|
|
meta["quasar_epoch"] = qv.QuasarCert.Epoch
|
|
meta["quasar_validators"] = qv.QuasarCert.Validators
|
|
meta["quasar_bls_size"] = len(qv.QuasarCert.BLS)
|
|
meta["quasar_pqproof_size"] = len(qv.QuasarCert.PQProof)
|
|
}
|
|
if qv.FinalityProof != nil {
|
|
meta["proof_type"] = qv.FinalityProof.ProofType
|
|
meta["proof_verified"] = qv.FinalityProof.Verified
|
|
meta["lattice_dimension"] = qv.FinalityProof.LatticeParams.Dimension
|
|
meta["security_level"] = qv.FinalityProof.LatticeParams.SecurityLvl
|
|
}
|
|
meta["proof_count"] = qv.ProofCount
|
|
meta["finalized"] = qv.Finalized
|
|
|
|
v := &dag.Vertex{
|
|
ID: qv.ID,
|
|
Type: "quantum",
|
|
ParentIDs: qv.ParentIDs,
|
|
Height: qv.Height,
|
|
Epoch: qv.Epoch,
|
|
TxIDs: qv.TxIDs,
|
|
Timestamp: qv.Timestamp,
|
|
Status: qv.Status,
|
|
Data: data,
|
|
Metadata: meta,
|
|
}
|
|
|
|
// Serialize QuasarCert into the vertex for API consumers
|
|
if qv.QuasarCert != nil {
|
|
certJSON, err := json.Marshal(qv.QuasarCert)
|
|
if err == nil {
|
|
v.QuasarCert = certJSON
|
|
}
|
|
}
|
|
|
|
// Update status based on finalization
|
|
if qv.Finalized {
|
|
v.Status = dag.StatusAccepted
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
// GetRecentVertices fetches recent vertices from Q-Chain
|
|
func (a *Adapter) GetRecentVertices(ctx context.Context, limit int) ([]json.RawMessage, error) {
|
|
result, err := a.call(ctx, "qvm.getRecentVertices", map[string]interface{}{
|
|
"limit": limit,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var response struct {
|
|
Vertices []json.RawMessage `json:"vertices"`
|
|
}
|
|
if err := json.Unmarshal(result, &response); err != nil {
|
|
return nil, fmt.Errorf("unmarshal vertices: %w", err)
|
|
}
|
|
|
|
return response.Vertices, nil
|
|
}
|
|
|
|
// GetVertexByID fetches a specific vertex by ID
|
|
func (a *Adapter) GetVertexByID(ctx context.Context, id string) (json.RawMessage, error) {
|
|
result, err := a.call(ctx, "qvm.getVertex", map[string]interface{}{
|
|
"id": id,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var response struct {
|
|
Vertex json.RawMessage `json:"vertex"`
|
|
}
|
|
if err := json.Unmarshal(result, &response); err != nil {
|
|
return nil, fmt.Errorf("unmarshal vertex: %w", err)
|
|
}
|
|
|
|
return response.Vertex, nil
|
|
}
|
|
|
|
// InitSchema creates Q-Chain specific database tables
|
|
func (a *Adapter) InitSchema(ctx context.Context, store storage.Store) error {
|
|
// Create finality proofs table
|
|
err := store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_finality_proofs (
|
|
id TEXT PRIMARY KEY,
|
|
vertex_id TEXT NOT NULL,
|
|
proof_type TEXT NOT NULL,
|
|
lattice_dimension INTEGER,
|
|
lattice_modulus INTEGER,
|
|
lattice_error_bound INTEGER,
|
|
security_level INTEGER,
|
|
algorithm TEXT,
|
|
signature BYTEA,
|
|
public_key BYTEA,
|
|
verified INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create finality proofs table: %w", err)
|
|
}
|
|
|
|
// Create indexes
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_proofs_vertex ON qchain_finality_proofs(vertex_id)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_proofs_type ON qchain_finality_proofs(proof_type)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_proofs_verified ON qchain_finality_proofs(verified)`)
|
|
|
|
// Create lattice parameters table
|
|
err = store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_lattice_params (
|
|
id SERIAL PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
dimension INTEGER NOT NULL,
|
|
modulus INTEGER NOT NULL,
|
|
error_bound INTEGER NOT NULL,
|
|
security_level INTEGER NOT NULL,
|
|
algorithm TEXT NOT NULL,
|
|
description TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create lattice params table: %w", err)
|
|
}
|
|
|
|
// Insert default lattice configurations
|
|
defaults := []struct {
|
|
name, algorithm, description string
|
|
dimension, errorBound, secLvl int
|
|
modulus int64
|
|
}{
|
|
{"dilithium2", "dilithium", "NIST Level 2 Dilithium", 256, 2, 2, 8380417},
|
|
{"dilithium3", "dilithium", "NIST Level 3 Dilithium", 256, 4, 3, 8380417},
|
|
{"dilithium5", "dilithium", "NIST Level 5 Dilithium", 256, 8, 5, 8380417},
|
|
{"kyber512", "kyber", "Kyber-512", 256, 2, 1, 3329},
|
|
{"kyber768", "kyber", "Kyber-768", 256, 2, 3, 3329},
|
|
{"kyber1024", "kyber", "Kyber-1024", 256, 2, 5, 3329},
|
|
{"falcon512", "falcon", "Falcon-512", 512, 1, 1, 12289},
|
|
{"falcon1024", "falcon", "Falcon-1024", 1024, 1, 5, 12289},
|
|
}
|
|
for _, d := range defaults {
|
|
_ = store.Exec(ctx, `
|
|
INSERT INTO qchain_lattice_params (name, dimension, modulus, error_bound, security_level, algorithm, description)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT DO NOTHING
|
|
`, d.name, d.dimension, d.modulus, d.errorBound, d.secLvl, d.algorithm, d.description)
|
|
}
|
|
|
|
// Create quantum stamps table
|
|
err = store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_stamps (
|
|
id TEXT PRIMARY KEY,
|
|
vertex_id TEXT,
|
|
chain_id TEXT NOT NULL,
|
|
block_height INTEGER NOT NULL,
|
|
block_hash BYTEA NOT NULL,
|
|
entropy BYTEA,
|
|
key_id TEXT,
|
|
signature BYTEA,
|
|
timestamp TIMESTAMP NOT NULL,
|
|
certified INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create stamps table: %w", err)
|
|
}
|
|
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_stamps_chain ON qchain_stamps(chain_id)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_stamps_height ON qchain_stamps(chain_id, block_height)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_stamps_key ON qchain_stamps(key_id)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_stamps_certified ON qchain_stamps(certified)`)
|
|
|
|
// Create Corona keys table
|
|
err = store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_corona_keys (
|
|
id TEXT PRIMARY KEY,
|
|
public_key BYTEA NOT NULL,
|
|
key_type TEXT NOT NULL,
|
|
algorithm TEXT NOT NULL,
|
|
security_level INTEGER NOT NULL,
|
|
owner TEXT NOT NULL,
|
|
valid_from TIMESTAMP NOT NULL,
|
|
valid_until TIMESTAMP NOT NULL,
|
|
revoked INTEGER DEFAULT 0,
|
|
vertex_id TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create corona keys table: %w", err)
|
|
}
|
|
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_keys_owner ON qchain_corona_keys(owner)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_keys_type ON qchain_corona_keys(key_type)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_keys_active ON qchain_corona_keys(revoked, valid_until)`)
|
|
|
|
// Create QuasarCert table (triple consensus: BLS + ZK(ML-DSA) + Corona)
|
|
err = store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_quasar_certs (
|
|
id TEXT PRIMARY KEY,
|
|
vertex_id TEXT NOT NULL,
|
|
bls BYTEA NOT NULL,
|
|
pq_proof BYTEA NOT NULL,
|
|
epoch BIGINT NOT NULL,
|
|
finality TIMESTAMP NOT NULL,
|
|
validators INTEGER NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create quasar certs table: %w", err)
|
|
}
|
|
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_certs_vertex ON qchain_quasar_certs(vertex_id)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_certs_epoch ON qchain_quasar_certs(epoch)`)
|
|
_ = store.Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_qchain_certs_finality ON qchain_quasar_certs(finality)`)
|
|
|
|
// Create extended stats table
|
|
err = store.Exec(ctx, `
|
|
CREATE TABLE IF NOT EXISTS qchain_extended_stats (
|
|
id INTEGER PRIMARY KEY DEFAULT 1,
|
|
total_proofs INTEGER DEFAULT 0,
|
|
verified_proofs INTEGER DEFAULT 0,
|
|
finalized_vertices INTEGER DEFAULT 0,
|
|
total_stamps INTEGER DEFAULT 0,
|
|
certified_stamps INTEGER DEFAULT 0,
|
|
total_keys INTEGER DEFAULT 0,
|
|
active_keys INTEGER DEFAULT 0,
|
|
dilithium_proofs INTEGER DEFAULT 0,
|
|
kyber_proofs INTEGER DEFAULT 0,
|
|
falcon_proofs INTEGER DEFAULT 0,
|
|
sphincs_proofs INTEGER DEFAULT 0,
|
|
avg_security_level REAL DEFAULT 0,
|
|
total_quasar_certs INTEGER DEFAULT 0,
|
|
latest_quasar_epoch BIGINT DEFAULT 0,
|
|
avg_quasar_validators REAL DEFAULT 0,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("create extended stats table: %w", err)
|
|
}
|
|
|
|
_ = store.Exec(ctx, `INSERT INTO qchain_extended_stats (id) VALUES (1) ON CONFLICT DO NOTHING`)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetStats returns Q-Chain specific statistics
|
|
func (a *Adapter) GetStats(ctx context.Context, store storage.Store) (map[string]interface{}, error) {
|
|
stats := make(map[string]interface{})
|
|
|
|
// Query extended stats
|
|
rows, err := store.Query(ctx, `
|
|
SELECT total_proofs, verified_proofs, finalized_vertices,
|
|
dilithium_proofs, kyber_proofs, falcon_proofs, sphincs_proofs,
|
|
avg_security_level
|
|
FROM qchain_extended_stats WHERE id = 1
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query extended stats: %w", err)
|
|
}
|
|
|
|
var totalProofs, verifiedProofs, finalizedVertices int64
|
|
var dilithiumProofs, kyberProofs, falconProofs, sphincsProofs int64
|
|
var avgSecurityLevel float64
|
|
|
|
if len(rows) > 0 {
|
|
row := rows[0]
|
|
if v, ok := row["total_proofs"].(int64); ok {
|
|
totalProofs = v
|
|
}
|
|
if v, ok := row["verified_proofs"].(int64); ok {
|
|
verifiedProofs = v
|
|
}
|
|
if v, ok := row["finalized_vertices"].(int64); ok {
|
|
finalizedVertices = v
|
|
}
|
|
if v, ok := row["dilithium_proofs"].(int64); ok {
|
|
dilithiumProofs = v
|
|
}
|
|
if v, ok := row["kyber_proofs"].(int64); ok {
|
|
kyberProofs = v
|
|
}
|
|
if v, ok := row["falcon_proofs"].(int64); ok {
|
|
falconProofs = v
|
|
}
|
|
if v, ok := row["sphincs_proofs"].(int64); ok {
|
|
sphincsProofs = v
|
|
}
|
|
if v, ok := row["avg_security_level"].(float64); ok {
|
|
avgSecurityLevel = v
|
|
}
|
|
}
|
|
|
|
stats["total_proofs"] = totalProofs
|
|
stats["verified_proofs"] = verifiedProofs
|
|
stats["finalized_vertices"] = finalizedVertices
|
|
stats["proof_types"] = map[string]int64{
|
|
"dilithium": dilithiumProofs,
|
|
"kyber": kyberProofs,
|
|
"falcon": falconProofs,
|
|
"sphincs": sphincsProofs,
|
|
}
|
|
stats["avg_security_level"] = avgSecurityLevel
|
|
|
|
// Calculate verification rate
|
|
if totalProofs > 0 {
|
|
stats["verification_rate"] = float64(verifiedProofs) / float64(totalProofs)
|
|
} else {
|
|
stats["verification_rate"] = 0.0
|
|
}
|
|
|
|
// QuasarCert stats
|
|
certRows, err := store.Query(ctx, `
|
|
SELECT total_quasar_certs, latest_quasar_epoch, avg_quasar_validators
|
|
FROM qchain_extended_stats WHERE id = 1
|
|
`)
|
|
if err == nil && len(certRows) > 0 {
|
|
cr := certRows[0]
|
|
if v, ok := cr["total_quasar_certs"].(int64); ok {
|
|
stats["total_quasar_certs"] = v
|
|
}
|
|
if v, ok := cr["latest_quasar_epoch"].(int64); ok {
|
|
stats["latest_quasar_epoch"] = v
|
|
}
|
|
if v, ok := cr["avg_quasar_validators"].(float64); ok {
|
|
stats["avg_quasar_validators"] = v
|
|
}
|
|
}
|
|
|
|
return stats, nil
|
|
}
|
|
|
|
// StoreQuasarCert stores a triple consensus certificate in the database
|
|
func (a *Adapter) StoreQuasarCert(ctx context.Context, store storage.Store, cert *QuasarCert) error {
|
|
return store.Exec(ctx, `
|
|
INSERT INTO qchain_quasar_certs
|
|
(id, vertex_id, bls, pq_proof, epoch, finality, validators)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
vertex_id = EXCLUDED.vertex_id,
|
|
bls = EXCLUDED.bls,
|
|
pq_proof = EXCLUDED.pq_proof,
|
|
epoch = EXCLUDED.epoch,
|
|
finality = EXCLUDED.finality,
|
|
validators = EXCLUDED.validators
|
|
`, cert.ID, cert.VertexID, cert.BLS, cert.PQProof, cert.Epoch, cert.Finality, cert.Validators)
|
|
}
|
|
|
|
// GetQuasarCert retrieves a QuasarCert by vertex ID
|
|
func (a *Adapter) GetQuasarCert(ctx context.Context, store storage.Store, vertexID string) (*QuasarCert, error) {
|
|
rows, err := store.Query(ctx, `
|
|
SELECT id, vertex_id, bls, pq_proof, epoch, finality, validators
|
|
FROM qchain_quasar_certs WHERE vertex_id = ? LIMIT 1
|
|
`, vertexID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(rows) == 0 {
|
|
return nil, nil
|
|
}
|
|
row := rows[0]
|
|
cert := &QuasarCert{}
|
|
if v, ok := row["id"].(string); ok {
|
|
cert.ID = v
|
|
}
|
|
if v, ok := row["vertex_id"].(string); ok {
|
|
cert.VertexID = v
|
|
}
|
|
if v, ok := row["bls"].([]byte); ok {
|
|
cert.BLS = v
|
|
}
|
|
if v, ok := row["pq_proof"].([]byte); ok {
|
|
cert.PQProof = v
|
|
}
|
|
if v, ok := row["epoch"].(int64); ok {
|
|
cert.Epoch = uint64(v)
|
|
}
|
|
if v, ok := row["finality"].(time.Time); ok {
|
|
cert.Finality = v
|
|
}
|
|
if v, ok := row["validators"].(int64); ok {
|
|
cert.Validators = int(v)
|
|
}
|
|
return cert, nil
|
|
}
|
|
|
|
// GetRecentQuasarCerts returns recent QuasarCerts ordered by epoch descending
|
|
func (a *Adapter) GetRecentQuasarCerts(ctx context.Context, store storage.Store, limit int) ([]QuasarCert, error) {
|
|
rows, err := store.Query(ctx, `
|
|
SELECT id, vertex_id, bls, pq_proof, epoch, finality, validators
|
|
FROM qchain_quasar_certs ORDER BY epoch DESC, finality DESC LIMIT ?
|
|
`, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var certs []QuasarCert
|
|
for _, row := range rows {
|
|
c := QuasarCert{}
|
|
if v, ok := row["id"].(string); ok {
|
|
c.ID = v
|
|
}
|
|
if v, ok := row["vertex_id"].(string); ok {
|
|
c.VertexID = v
|
|
}
|
|
if v, ok := row["bls"].([]byte); ok {
|
|
c.BLS = v
|
|
}
|
|
if v, ok := row["pq_proof"].([]byte); ok {
|
|
c.PQProof = v
|
|
}
|
|
if v, ok := row["epoch"].(int64); ok {
|
|
c.Epoch = uint64(v)
|
|
}
|
|
if v, ok := row["finality"].(time.Time); ok {
|
|
c.Finality = v
|
|
}
|
|
if v, ok := row["validators"].(int64); ok {
|
|
c.Validators = int(v)
|
|
}
|
|
certs = append(certs, c)
|
|
}
|
|
return certs, nil
|
|
}
|
|
|
|
// StoreProof stores a finality proof in the database
|
|
func (a *Adapter) StoreProof(ctx context.Context, store storage.Store, proof *FinalityProof) error {
|
|
verified := 0
|
|
if proof.Verified {
|
|
verified = 1
|
|
}
|
|
return store.Exec(ctx, `
|
|
INSERT INTO qchain_finality_proofs
|
|
(id, vertex_id, proof_type, lattice_dimension, lattice_modulus,
|
|
lattice_error_bound, security_level, algorithm, signature, public_key, verified)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
vertex_id = EXCLUDED.vertex_id,
|
|
proof_type = EXCLUDED.proof_type,
|
|
lattice_dimension = EXCLUDED.lattice_dimension,
|
|
lattice_modulus = EXCLUDED.lattice_modulus,
|
|
lattice_error_bound = EXCLUDED.lattice_error_bound,
|
|
security_level = EXCLUDED.security_level,
|
|
algorithm = EXCLUDED.algorithm,
|
|
signature = EXCLUDED.signature,
|
|
public_key = EXCLUDED.public_key,
|
|
verified = EXCLUDED.verified
|
|
`,
|
|
proof.ID, proof.VertexID, proof.ProofType,
|
|
proof.LatticeParams.Dimension, proof.LatticeParams.Modulus,
|
|
proof.LatticeParams.ErrorBound, proof.LatticeParams.SecurityLvl,
|
|
proof.LatticeParams.Algorithm, proof.Signature, proof.PublicKey, verified,
|
|
)
|
|
}
|
|
|
|
// VerifyProof performs quantum-resistant proof verification
|
|
// Returns true if the proof is valid under the specified lattice parameters
|
|
func (a *Adapter) VerifyProof(ctx context.Context, proof *FinalityProof) (bool, error) {
|
|
// Delegate verification to the Q-Chain node via RPC
|
|
result, err := a.call(ctx, "qvm.verifyProof", map[string]interface{}{
|
|
"proofId": proof.ID,
|
|
"vertexId": proof.VertexID,
|
|
"proofType": proof.ProofType,
|
|
"signature": proof.Signature,
|
|
"publicKey": proof.PublicKey,
|
|
})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
var response struct {
|
|
Valid bool `json:"valid"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
if err := json.Unmarshal(result, &response); err != nil {
|
|
return false, fmt.Errorf("unmarshal verify response: %w", err)
|
|
}
|
|
|
|
return response.Valid, nil
|
|
}
|
|
|
|
// UpdateExtendedStats updates Q-Chain specific statistics
|
|
func (a *Adapter) UpdateExtendedStats(ctx context.Context, store storage.Store) error {
|
|
return store.Exec(ctx, `
|
|
UPDATE qchain_extended_stats SET
|
|
total_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs),
|
|
verified_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs WHERE verified = 1),
|
|
finalized_vertices = (SELECT COUNT(*) FROM qchain_vertices WHERE status = 'accepted'),
|
|
dilithium_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs WHERE proof_type = 'dilithium'),
|
|
kyber_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs WHERE proof_type = 'kyber'),
|
|
falcon_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs WHERE proof_type = 'falcon'),
|
|
sphincs_proofs = (SELECT COUNT(*) FROM qchain_finality_proofs WHERE proof_type = 'sphincs+'),
|
|
avg_security_level = COALESCE((SELECT AVG(security_level) FROM qchain_finality_proofs), 0),
|
|
total_quasar_certs = (SELECT COUNT(*) FROM qchain_quasar_certs),
|
|
latest_quasar_epoch = COALESCE((SELECT MAX(epoch) FROM qchain_quasar_certs), 0),
|
|
avg_quasar_validators = COALESCE((SELECT AVG(validators) FROM qchain_quasar_certs), 0),
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = 1
|
|
`)
|
|
}
|
|
|
|
// NewConfig creates a default Q-Chain indexer configuration
|
|
func NewConfig() dag.Config {
|
|
return dag.Config{
|
|
ChainType: dag.ChainQ,
|
|
ChainName: "Q-Chain (Quantum)",
|
|
RPCEndpoint: DefaultRPCEndpoint,
|
|
RPCMethod: "qvm",
|
|
HTTPPort: DefaultHTTPPort,
|
|
PollInterval: 5 * time.Second,
|
|
}
|
|
}
|
|
|
|
// StoreStamp stores a quantum stamp for cross-chain finality
|
|
func (a *Adapter) StoreStamp(ctx context.Context, store storage.Store, stamp *QuantumStamp) error {
|
|
certified := 0
|
|
if stamp.Certified {
|
|
certified = 1
|
|
}
|
|
return store.Exec(ctx, `
|
|
INSERT INTO qchain_stamps
|
|
(id, vertex_id, chain_id, block_height, block_hash, entropy, key_id, signature, timestamp, certified)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
vertex_id = EXCLUDED.vertex_id,
|
|
chain_id = EXCLUDED.chain_id,
|
|
block_height = EXCLUDED.block_height,
|
|
block_hash = EXCLUDED.block_hash,
|
|
entropy = EXCLUDED.entropy,
|
|
key_id = EXCLUDED.key_id,
|
|
signature = EXCLUDED.signature,
|
|
timestamp = EXCLUDED.timestamp,
|
|
certified = EXCLUDED.certified
|
|
`, stamp.ID, stamp.VertexID, stamp.ChainID, stamp.BlockHeight, stamp.BlockHash,
|
|
stamp.Entropy, stamp.KeyID, stamp.Signature, stamp.Timestamp, certified)
|
|
}
|
|
|
|
// StoreCoronaKey stores a quantum-resistant signing key
|
|
func (a *Adapter) StoreCoronaKey(ctx context.Context, store storage.Store, key *CoronaKey, vertexID string) error {
|
|
revoked := 0
|
|
if key.Revoked {
|
|
revoked = 1
|
|
}
|
|
return store.Exec(ctx, `
|
|
INSERT INTO qchain_corona_keys
|
|
(id, public_key, key_type, algorithm, security_level, owner, valid_from, valid_until, revoked, vertex_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
public_key = EXCLUDED.public_key,
|
|
key_type = EXCLUDED.key_type,
|
|
algorithm = EXCLUDED.algorithm,
|
|
security_level = EXCLUDED.security_level,
|
|
owner = EXCLUDED.owner,
|
|
valid_from = EXCLUDED.valid_from,
|
|
valid_until = EXCLUDED.valid_until,
|
|
revoked = EXCLUDED.revoked,
|
|
vertex_id = EXCLUDED.vertex_id
|
|
`, key.ID, key.PublicKey, key.KeyType, key.Algorithm, key.SecurityLvl,
|
|
key.Owner, key.ValidFrom, key.ValidUntil, revoked, vertexID)
|
|
}
|
|
|
|
// GetStampsByChain retrieves quantum stamps for a specific chain
|
|
func (a *Adapter) GetStampsByChain(ctx context.Context, store storage.Store, chainID string, limit int) ([]QuantumStamp, error) {
|
|
rows, err := store.Query(ctx, `
|
|
SELECT id, vertex_id, chain_id, block_height, block_hash, entropy, key_id, signature, timestamp, certified
|
|
FROM qchain_stamps
|
|
WHERE chain_id = ?
|
|
ORDER BY block_height DESC
|
|
LIMIT ?
|
|
`, chainID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var stamps []QuantumStamp
|
|
for _, row := range rows {
|
|
s := QuantumStamp{}
|
|
if v, ok := row["id"].(string); ok {
|
|
s.ID = v
|
|
}
|
|
if v, ok := row["vertex_id"].(string); ok {
|
|
s.VertexID = v
|
|
}
|
|
if v, ok := row["chain_id"].(string); ok {
|
|
s.ChainID = v
|
|
}
|
|
if v, ok := row["block_height"].(int64); ok {
|
|
s.BlockHeight = uint64(v)
|
|
}
|
|
if v, ok := row["block_hash"].([]byte); ok {
|
|
s.BlockHash = v
|
|
}
|
|
if v, ok := row["entropy"].([]byte); ok {
|
|
s.Entropy = v
|
|
}
|
|
if v, ok := row["key_id"].(string); ok {
|
|
s.KeyID = v
|
|
}
|
|
if v, ok := row["signature"].([]byte); ok {
|
|
s.Signature = v
|
|
}
|
|
if v, ok := row["timestamp"].(time.Time); ok {
|
|
s.Timestamp = v
|
|
}
|
|
if v, ok := row["certified"].(int64); ok {
|
|
s.Certified = v == 1
|
|
}
|
|
stamps = append(stamps, s)
|
|
}
|
|
return stamps, nil
|
|
}
|
|
|
|
// GetActiveKeys retrieves active Corona keys for an owner
|
|
func (a *Adapter) GetActiveKeys(ctx context.Context, store storage.Store, owner string) ([]CoronaKey, error) {
|
|
rows, err := store.Query(ctx, `
|
|
SELECT id, public_key, key_type, algorithm, security_level, owner, valid_from, valid_until, revoked, created_at
|
|
FROM qchain_corona_keys
|
|
WHERE owner = ? AND revoked = 0 AND valid_until > CURRENT_TIMESTAMP
|
|
ORDER BY created_at DESC
|
|
`, owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var keys []CoronaKey
|
|
for _, row := range rows {
|
|
k := CoronaKey{}
|
|
if v, ok := row["id"].(string); ok {
|
|
k.ID = v
|
|
}
|
|
if v, ok := row["public_key"].([]byte); ok {
|
|
k.PublicKey = v
|
|
}
|
|
if v, ok := row["key_type"].(string); ok {
|
|
k.KeyType = ProofType(v)
|
|
}
|
|
if v, ok := row["algorithm"].(string); ok {
|
|
k.Algorithm = v
|
|
}
|
|
if v, ok := row["security_level"].(int64); ok {
|
|
k.SecurityLvl = int(v)
|
|
}
|
|
if v, ok := row["owner"].(string); ok {
|
|
k.Owner = v
|
|
}
|
|
if v, ok := row["valid_from"].(time.Time); ok {
|
|
k.ValidFrom = v
|
|
}
|
|
if v, ok := row["valid_until"].(time.Time); ok {
|
|
k.ValidUntil = v
|
|
}
|
|
if v, ok := row["revoked"].(int64); ok {
|
|
k.Revoked = v == 1
|
|
}
|
|
if v, ok := row["created_at"].(time.Time); ok {
|
|
k.CreatedAt = v
|
|
}
|
|
keys = append(keys, k)
|
|
}
|
|
return keys, nil
|
|
}
|
|
|
|
// Verify interface compliance at compile time
|
|
var _ dag.Adapter = (*Adapter)(nil)
|