Files
git.stella-ops.org/docs/modules/attestor/proof-spine-algorithm.md
master 2170a58734
Some checks failed
Lighthouse CI / Lighthouse Audit (push) Waiting to run
Lighthouse CI / Axe Accessibility Audit (push) Waiting to run
Manifest Integrity / Validate Schema Integrity (push) Waiting to run
Manifest Integrity / Validate Contract Documents (push) Waiting to run
Manifest Integrity / Validate Pack Fixtures (push) Waiting to run
Manifest Integrity / Audit SHA256SUMS Files (push) Waiting to run
Manifest Integrity / Verify Merkle Roots (push) Waiting to run
Policy Lint & Smoke / policy-lint (push) Waiting to run
Policy Simulation / policy-simulate (push) Waiting to run
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
Add comprehensive security tests for OWASP A02, A05, A07, and A08 categories
- Implemented tests for Cryptographic Failures (A02) to ensure proper handling of sensitive data, secure algorithms, and key management.
- Added tests for Security Misconfiguration (A05) to validate production configurations, security headers, CORS settings, and feature management.
- Developed tests for Authentication Failures (A07) to enforce strong password policies, rate limiting, session management, and MFA support.
- Created tests for Software and Data Integrity Failures (A08) to verify artifact signatures, SBOM integrity, attestation chains, and feed updates.
2025-12-16 16:40:44 +02:00

8.9 KiB

Proof Spine Assembly Algorithm

Sprint: SPRINT_0501_0004_0001 Module: Attestor / ProofChain

Overview

The Proof Spine is the cryptographic backbone of StellaOps' proof chain. It aggregates evidence, reasoning, and VEX statements into a single merkle-rooted bundle that can be verified independently.

Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                         PROOF SPINE STRUCTURE                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│  │ SBOMEntryID  │  │ EvidenceID[] │  │ ReasoningID  │  │ VEXVerdictID │    │
│  │ (leaf 0)     │  │ (leaves 1-N) │  │ (leaf N+1)   │  │ (leaf N+2)   │    │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘    │
│         │                 │                 │                 │            │
│         └─────────────────┴─────────────────┴─────────────────┘            │
│                                    │                                        │
│                                    ▼                                        │
│                    ┌───────────────────────────────┐                        │
│                    │     MERKLE TREE BUILDER       │                        │
│                    │  - SHA-256 hash function      │                        │
│                    │  - Lexicographic sorting      │                        │
│                    │  - Power-of-2 padding         │                        │
│                    └───────────────┬───────────────┘                        │
│                                    │                                        │
│                                    ▼                                        │
│                    ┌───────────────────────────────┐                        │
│                    │      ProofBundleID (Root)     │                        │
│                    │  sha256:<64-hex-chars>        │                        │
│                    └───────────────────────────────┘                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Algorithm Specification

Input

Parameter Type Description
sbomEntryId string Content-addressed ID of the SBOM entry
evidenceIds string[] Array of evidence statement IDs
reasoningId string ID of the reasoning/policy match statement
vexVerdictId string ID of the VEX verdict statement

Output

Parameter Type Description
proofBundleId string Merkle root in format sha256:<64-hex>

Pseudocode

FUNCTION BuildProofBundleMerkle(sbomEntryId, evidenceIds[], reasoningId, vexVerdictId):
    
    // Step 1: Prepare leaves in deterministic order
    leaves = []
    leaves.append(SHA256(UTF8.GetBytes(sbomEntryId)))
    
    // Step 2: Sort evidence IDs lexicographically
    sortedEvidenceIds = evidenceIds.Sort(StringComparer.Ordinal)
    FOR EACH evidenceId IN sortedEvidenceIds:
        leaves.append(SHA256(UTF8.GetBytes(evidenceId)))
    
    leaves.append(SHA256(UTF8.GetBytes(reasoningId)))
    leaves.append(SHA256(UTF8.GetBytes(vexVerdictId)))
    
    // Step 3: Pad to power of 2 (duplicate last leaf)
    WHILE NOT IsPowerOfTwo(leaves.Length):
        leaves.append(leaves[leaves.Length - 1])
    
    // Step 4: Build tree bottom-up
    currentLevel = leaves
    WHILE currentLevel.Length > 1:
        nextLevel = []
        FOR i = 0 TO currentLevel.Length STEP 2:
            left = currentLevel[i]
            right = currentLevel[i + 1]
            parent = SHA256(left || right)  // Concatenate then hash
            nextLevel.append(parent)
        currentLevel = nextLevel
    
    // Step 5: Return root as formatted ID
    RETURN "sha256:" + HexEncode(currentLevel[0])

Determinism Invariants

Invariant Rule Rationale
Evidence Ordering Lexicographic (byte comparison) Reproducible across platforms
Hash Function SHA-256 only No algorithm negotiation
Padding Duplicate last leaf Not zeros, preserves tree structure
Concatenation Left || Right Consistent ordering
String Encoding UTF-8 Cross-platform compatibility
ID Format sha256:<lowercase-hex> Canonical representation

Example

Input

{
  "sbomEntryId": "sha256:abc123...",
  "evidenceIds": [
    "sha256:evidence-cve-2024-0001...",
    "sha256:evidence-reachability...",
    "sha256:evidence-sbom-component..."
  ],
  "reasoningId": "sha256:reasoning-policy...",
  "vexVerdictId": "sha256:vex-not-affected..."
}

Processing

  1. Leaf 0: SHA256("sha256:abc123...") → SBOM
  2. Leaf 1: SHA256("sha256:evidence-cve-2024-0001...") → Evidence (sorted first)
  3. Leaf 2: SHA256("sha256:evidence-reachability...") → Evidence
  4. Leaf 3: SHA256("sha256:evidence-sbom-component...") → Evidence
  5. Leaf 4: SHA256("sha256:reasoning-policy...") → Reasoning
  6. Leaf 5: SHA256("sha256:vex-not-affected...") → VEX
  7. Padding: Duplicate leaf 5 to get 8 leaves (power of 2)

Tree Structure

                    ROOT
                   /    \
                  H1     H2
                 / \    / \
               H3   H4  H5  H6
              / \  / \ / \ / \
             L0 L1 L2 L3 L4 L5 L5 L5  (padded)

Output

sha256:7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069

Cross-Platform Verification

Test Vector

For cross-platform compatibility testing, use this known test vector:

Input:

{
  "sbomEntryId": "sha256:0000000000000000000000000000000000000000000000000000000000000001",
  "evidenceIds": [
    "sha256:0000000000000000000000000000000000000000000000000000000000000002",
    "sha256:0000000000000000000000000000000000000000000000000000000000000003"
  ],
  "reasoningId": "sha256:0000000000000000000000000000000000000000000000000000000000000004",
  "vexVerdictId": "sha256:0000000000000000000000000000000000000000000000000000000000000005"
}

All implementations (C#, Go, Rust, TypeScript) must produce the same root hash.

Verification

To verify a proof bundle:

  1. Obtain all constituent statements (SBOM, Evidence, Reasoning, VEX)
  2. Extract their content-addressed IDs
  3. Re-compute the merkle root using the algorithm above
  4. Compare with the claimed proofBundleId

If the roots match, the bundle is valid and all statements are bound to this proof.

API

C# Interface

public interface IProofSpineAssembler
{
    /// <summary>
    /// Assembles a proof spine from its constituent statements.
    /// </summary>
    ProofSpineResult Assemble(ProofSpineInput input);
}

public record ProofSpineInput
{
    public required string SbomEntryId { get; init; }
    public required IReadOnlyList<string> EvidenceIds { get; init; }
    public required string ReasoningId { get; init; }
    public required string VexVerdictId { get; init; }
}

public record ProofSpineResult
{
    public required string ProofBundleId { get; init; }
    public required byte[] MerkleRoot { get; init; }
    public required IReadOnlyList<byte[]> LeafHashes { get; init; }
}