mithril-go/internal/stm/verify_live_test.go
Kayos 920d7cf177 STM full verification landing — milestones C/D/E complete
Implemented the remaining STM verification layers:

- internal/stm/lottery.go: EvaluateSigma (Blake2b-512 lottery draw) +
  IsLotteryWon with Taylor-series threshold comparison (ported from
  mithril-stm::eligibility), big.Rat-based to match Rust's num_bigint/
  num_rational path
- internal/stm/merkle.go: Blake2b-256 Merkle batch-proof verification,
  faithful port of mithril-stm's verify_leaves_membership_from_batch_path
  including the 'current is left/right child' branch logic and the
  1-byte zero pad for missing siblings
- internal/stm/verify.go: top-level stm.Verify(msg, ms, avk, params)
  glues all four checks: k-threshold, lottery, Merkle, BLS aggregate
- cmd: 'verify head' now runs full STM verification; JSON output shows
  signers, wins, params, verified flag
- MCP: new 'mithril_verify_certificate' tool dispatches genesis Ed25519
  vs STM by cert kind

Verified against live networks:
  mainnet head cert bc00b551…  epoch=626  59 signers  1972/16948 wins  ✓
  mainnet genesis   25acfcfe…  epoch=539  Ed25519 ✓
  preprod head      dd9c4fcb…  epoch=284   2 signers    11/100 wins   ✓
  preprod genesis   69bc3bdf…  epoch=196  Ed25519 ✓

This is a consensus-correct pure-Go Mithril client. Single binary,
CGo-free, no upstream Rust dependency.

Next: full chain verification (walk head → genesis, check continuity).
2026-04-23 15:58:44 -07:00

72 lines
1.9 KiB
Go

//go:build live
package stm
import (
"context"
"encoding/json"
"io"
"net/http"
"testing"
"time"
)
func TestFullSTMVerify_LivePreprodHead(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, preprodHead+"/artifact/cardano-database", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Skipf("network: %v", err)
}
defer resp.Body.Close()
var snaps []struct {
CertificateHash string `json:"certificate_hash"`
}
if err := json.NewDecoder(resp.Body).Decode(&snaps); err != nil {
t.Fatal(err)
}
req, _ = http.NewRequestWithContext(ctx, http.MethodGet, preprodHead+"/certificate/"+snaps[0].CertificateHash, nil)
resp, err = http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var cert struct {
MultiSignature json.RawMessage `json:"multi_signature"`
AggregateVerificationKey json.RawMessage `json:"aggregate_verification_key"`
SignedMessage string `json:"signed_message"`
Metadata struct {
Parameters struct {
K uint64 `json:"k"`
M uint64 `json:"m"`
PhiF float64 `json:"phi_f"`
} `json:"parameters"`
} `json:"metadata"`
}
if err := json.Unmarshal(body, &cert); err != nil {
t.Fatal(err)
}
ms, err := DecodeMultiSig(cert.MultiSignature)
if err != nil {
t.Fatal(err)
}
avk, err := DecodeAVK(cert.AggregateVerificationKey)
if err != nil {
t.Fatal(err)
}
params := Parameters{
K: cert.Metadata.Parameters.K,
M: cert.Metadata.Parameters.M,
PhiF: cert.Metadata.Parameters.PhiF,
}
t.Logf("params: k=%d m=%d phi_f=%v", params.K, params.M, params.PhiF)
msg := []byte(cert.SignedMessage)
if err := Verify(msg, ms, avk, params); err != nil {
t.Fatalf("STM Verify: %v", err)
}
t.Logf("✓ FULL STM verification passed against live preprod head cert")
}