|
| 1 | +// Package prooflevel defines the TrustDB L1-L5 proof ladder in one place. |
| 2 | +// |
| 3 | +// The package is intentionally pure: callers provide evidence that is already |
| 4 | +// present or already verified, and the evaluator returns the strongest level |
| 5 | +// reachable without inventing intermediate trust. |
| 6 | +package prooflevel |
| 7 | + |
| 8 | +type Level string |
| 9 | + |
| 10 | +const ( |
| 11 | + Unknown Level = "" |
| 12 | + L1 Level = "L1" |
| 13 | + L2 Level = "L2" |
| 14 | + L3 Level = "L3" |
| 15 | + L4 Level = "L4" |
| 16 | + L5 Level = "L5" |
| 17 | +) |
| 18 | + |
| 19 | +type Evidence struct { |
| 20 | + ContentHash bool |
| 21 | + ClientSignature bool |
| 22 | + AcceptedReceipt bool |
| 23 | + CommittedReceipt bool |
| 24 | + BatchProof bool |
| 25 | + GlobalLogProof bool |
| 26 | + STHAnchorResult bool |
| 27 | +} |
| 28 | + |
| 29 | +type Definition struct { |
| 30 | + Level Level |
| 31 | + Label string |
| 32 | + Requirement string |
| 33 | +} |
| 34 | + |
| 35 | +var ladder = []Definition{ |
| 36 | + {Level: L1, Label: "local content", Requirement: "content hash matches the signed client claim and the client signature is valid"}, |
| 37 | + {Level: L2, Label: "accepted", Requirement: "L1 plus a valid server AcceptedReceipt"}, |
| 38 | + {Level: L3, Label: "batch committed", Requirement: "L2 plus a valid CommittedReceipt and batch Merkle inclusion proof"}, |
| 39 | + {Level: L4, Label: "global log", Requirement: "L3 plus a valid BatchRoot -> SignedTreeHead global-log inclusion proof"}, |
| 40 | + {Level: L5, Label: "external anchor", Requirement: "L4 plus an STH/global-root external anchor result"}, |
| 41 | +} |
| 42 | + |
| 43 | +func Evaluate(e Evidence) Level { |
| 44 | + if !(e.ContentHash && e.ClientSignature) { |
| 45 | + return Unknown |
| 46 | + } |
| 47 | + if !e.AcceptedReceipt { |
| 48 | + return L1 |
| 49 | + } |
| 50 | + if !(e.CommittedReceipt && e.BatchProof) { |
| 51 | + return L2 |
| 52 | + } |
| 53 | + if !e.GlobalLogProof { |
| 54 | + return L3 |
| 55 | + } |
| 56 | + if !e.STHAnchorResult { |
| 57 | + return L4 |
| 58 | + } |
| 59 | + return L5 |
| 60 | +} |
| 61 | + |
| 62 | +func EvidenceFor(level Level) Evidence { |
| 63 | + evidence := Evidence{} |
| 64 | + if AtLeast(level, L1) { |
| 65 | + evidence.ContentHash = true |
| 66 | + evidence.ClientSignature = true |
| 67 | + } |
| 68 | + if AtLeast(level, L2) { |
| 69 | + evidence.AcceptedReceipt = true |
| 70 | + } |
| 71 | + if AtLeast(level, L3) { |
| 72 | + evidence.CommittedReceipt = true |
| 73 | + evidence.BatchProof = true |
| 74 | + } |
| 75 | + if AtLeast(level, L4) { |
| 76 | + evidence.GlobalLogProof = true |
| 77 | + } |
| 78 | + if AtLeast(level, L5) { |
| 79 | + evidence.STHAnchorResult = true |
| 80 | + } |
| 81 | + return evidence |
| 82 | +} |
| 83 | + |
| 84 | +func Definitions() []Definition { |
| 85 | + out := make([]Definition, len(ladder)) |
| 86 | + copy(out, ladder) |
| 87 | + return out |
| 88 | +} |
| 89 | + |
| 90 | +func Parse(raw string) (Level, bool) { |
| 91 | + switch Level(raw) { |
| 92 | + case L1, L2, L3, L4, L5: |
| 93 | + return Level(raw), true |
| 94 | + default: |
| 95 | + return Unknown, false |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +func Rank(level Level) int { |
| 100 | + switch level { |
| 101 | + case L1: |
| 102 | + return 1 |
| 103 | + case L2: |
| 104 | + return 2 |
| 105 | + case L3: |
| 106 | + return 3 |
| 107 | + case L4: |
| 108 | + return 4 |
| 109 | + case L5: |
| 110 | + return 5 |
| 111 | + default: |
| 112 | + return 0 |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +func AtLeast(level, target Level) bool { |
| 117 | + return Rank(level) >= Rank(target) && Rank(target) > 0 |
| 118 | +} |
| 119 | + |
| 120 | +func (l Level) String() string { |
| 121 | + return string(l) |
| 122 | +} |
0 commit comments