trustflash-verify 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trustflash_verify-0.4.0/LICENSE +22 -0
- trustflash_verify-0.4.0/PKG-INFO +234 -0
- trustflash_verify-0.4.0/README.md +194 -0
- trustflash_verify-0.4.0/setup.cfg +4 -0
- trustflash_verify-0.4.0/setup.py +56 -0
- trustflash_verify-0.4.0/tests/test_verifier.py +996 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/PKG-INFO +234 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/SOURCES.txt +11 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/dependency_links.txt +1 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/entry_points.txt +2 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/requires.txt +4 -0
- trustflash_verify-0.4.0/trustflash_verify.egg-info/top_level.txt +1 -0
- trustflash_verify-0.4.0/trustflash_verify.py +1576 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Northgate Strategic LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
6
|
+
copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included
|
|
14
|
+
in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
17
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trustflash-verify
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Open-source forensic verifier for TrustSHIELD/AIREC TrustFlash audit-export bundles. Verifies Ed25519 checkpoint signatures, the SHA-256 event hash chain, checkpoint-to-event binding, and the signed Forensic Confidence score offline, no platform access required.
|
|
5
|
+
Home-page: https://github.com/northgate-strategic/trustflash-verifier
|
|
6
|
+
Author: Northgate Strategic LLC
|
|
7
|
+
Author-email: support@northgatestrategic.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: audit forensic verification ed25519 sha256 ai-governance trustshield
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Information Technology
|
|
12
|
+
Classifier: Intended Audience :: Legal Industry
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Security :: Cryptography
|
|
20
|
+
Classifier: Topic :: System :: Logging
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: cryptography>=41.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: keywords
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
Dynamic: provides-extra
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
40
|
+
|
|
41
|
+
# trustflash-verify
|
|
42
|
+
|
|
43
|
+
Open-source forensic verifier for TrustSHIELD/AIREC TrustFlash export
|
|
44
|
+
bundles (PF21 patent — TrustFlash Behavioral Audit Black Box).
|
|
45
|
+
|
|
46
|
+
## Why this exists
|
|
47
|
+
|
|
48
|
+
Auditors don't trust "we have a database with hash columns." They want
|
|
49
|
+
**cryptographic evidence they can verify themselves, offline, without
|
|
50
|
+
access to the platform's infrastructure**.
|
|
51
|
+
|
|
52
|
+
A TrustFlash forensic export bundle is a single JSON file containing:
|
|
53
|
+
|
|
54
|
+
- The platform's Ed25519 public key (PEM-encoded)
|
|
55
|
+
- Recent Ed25519-signed checkpoints over the audit chain head
|
|
56
|
+
- Recent enforcement events with their per-event hash chain
|
|
57
|
+
- Step-by-step verification instructions
|
|
58
|
+
|
|
59
|
+
This tool **independently verifies** that bundle. It depends only on
|
|
60
|
+
the `cryptography` library (the same one Python's TLS stack uses); the
|
|
61
|
+
verifier itself is a single Python file you can read, audit, fork, or
|
|
62
|
+
re-implement in any language.
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install cryptography
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then either:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Run directly:
|
|
74
|
+
python trustflash_verify.py /path/to/bundle.json
|
|
75
|
+
|
|
76
|
+
# Or symlink onto your PATH:
|
|
77
|
+
chmod +x trustflash_verify.py
|
|
78
|
+
ln -s "$(pwd)/trustflash_verify.py" ~/.local/bin/trustflash-verify
|
|
79
|
+
trustflash-verify /path/to/bundle.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Verify a bundle, human-readable summary
|
|
86
|
+
trustflash-verify bundle.json
|
|
87
|
+
|
|
88
|
+
# JSON output for tooling
|
|
89
|
+
trustflash-verify bundle.json --json
|
|
90
|
+
|
|
91
|
+
# Use a separately-trusted public key (e.g., one Northgate Strategic
|
|
92
|
+
# published on a different channel) instead of the key embedded in
|
|
93
|
+
# the bundle. This is the strongest guarantee: it proves the bundle
|
|
94
|
+
# was signed by the entity whose key fingerprint you trust, even if
|
|
95
|
+
# the bundle itself was tampered to swap keys.
|
|
96
|
+
trustflash-verify bundle.json --public-key /path/to/key.pem
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## What the tool checks
|
|
100
|
+
|
|
101
|
+
For each **checkpoint** in the bundle:
|
|
102
|
+
|
|
103
|
+
1. Select the verification key by the checkpoint's `key_id` from the
|
|
104
|
+
bundle's `public_keys` array — a bundle that spans a key rotation
|
|
105
|
+
carries every key it was signed under. Falls back to the top-level
|
|
106
|
+
`public_key_pem` for checkpoints with no `key_id` or an unlisted one
|
|
107
|
+
(and for older single-key bundles that predate `public_keys`).
|
|
108
|
+
2. Recompute canonical signed bytes:
|
|
109
|
+
`trustflash/v1|<tenant_id>|<chain_head_hash>|<event_count>|<checkpoint_at>|<prev_checkpoint_id_or_GENESIS>`
|
|
110
|
+
3. Verify Ed25519 signature against the selected public key.
|
|
111
|
+
4. Report `valid` / `signature mismatch` / `decode error`.
|
|
112
|
+
|
|
113
|
+
For each **event** in the bundle:
|
|
114
|
+
|
|
115
|
+
1. Recompute canonical hash input from row fields:
|
|
116
|
+
`<id>|<tenant_id>|<user_id>|<module_name>|<decision>|<action>|<severity>|<trust_score>|<violation_type>|<endpoint>|<request_id>|<timestamp>|<prev_event_hash>`
|
|
117
|
+
2. Compute `SHA256` of that canonical input.
|
|
118
|
+
3. Compare against the row's stored `event_hash`.
|
|
119
|
+
4. Verify `prev_event_hash` links to the previous event's `event_hash`
|
|
120
|
+
(or `GENESIS` for the first event).
|
|
121
|
+
|
|
122
|
+
**Checkpoint→event binding** (tool v0.4.0):
|
|
123
|
+
|
|
124
|
+
A valid signature proves a checkpoint record was signed; a self-consistent
|
|
125
|
+
event chain proves internal linkage. Neither alone proves the signer signed
|
|
126
|
+
*these* events. For every checkpoint whose `event_count` falls inside the
|
|
127
|
+
exported slice, the event at that `chain_position` must carry
|
|
128
|
+
`event_hash == chain_head_hash`. A mismatch is a hard failure (exit 6) —
|
|
129
|
+
the events were rebuilt, or the checkpoint belongs to a different chain. A
|
|
130
|
+
signed position with no event in the slice is reported as a warning (not a
|
|
131
|
+
failure): historical write-race forks and export-slice boundaries produce
|
|
132
|
+
that shape on healthy data, and the server-side full-chain verifier is the
|
|
133
|
+
authority there.
|
|
134
|
+
|
|
135
|
+
**Forensic Confidence recompute** (tool v0.4.0):
|
|
136
|
+
|
|
137
|
+
If the bundle carries a `forensic_confidence` block, the platform's 0-100 /
|
|
138
|
+
A-F Forensic Confidence score is recomputable offline from the bundle
|
|
139
|
+
alone. The tool:
|
|
140
|
+
|
|
141
|
+
1. Verifies the Ed25519 signature over the **exact** bytes of
|
|
142
|
+
`payload_canonical` (key selected by `key_id`, same registry as
|
|
143
|
+
checkpoints; `--public-key` pins it).
|
|
144
|
+
2. Requires the human-readable `payload` copy to equal the signed copy.
|
|
145
|
+
3. Requires the attestation's `chain_head_hash` to equal the event hash of
|
|
146
|
+
the highest-`chain_position` event in the bundle — the attestation is
|
|
147
|
+
bound to *this* chain and cannot be replayed against rebuilt events.
|
|
148
|
+
4. Recomputes all five component scores from the attested integer inputs
|
|
149
|
+
(chain continuity, signature validity, override anomaly rate, reflex
|
|
150
|
+
distribution, egress balance), the weighted composite, and the letter
|
|
151
|
+
grade, and compares them to the attested values. A component with a
|
|
152
|
+
zero denominator is a *disclosed* vacuous pass ("no data in window",
|
|
153
|
+
`insufficient_data: true`) — an undisclosed one is a failure.
|
|
154
|
+
|
|
155
|
+
Every attested value is an aggregate: integer counts, scores, weights, a
|
|
156
|
+
grade, a window length, a timestamp, and hashes already present in the
|
|
157
|
+
bundle. No user identifier, email, or content fragment appears in the
|
|
158
|
+
attestation. A bundle **without** the block predates the feature and is
|
|
159
|
+
reported as "score recompute not available" — never as a failure.
|
|
160
|
+
|
|
161
|
+
## Exit codes
|
|
162
|
+
|
|
163
|
+
| Code | Meaning |
|
|
164
|
+
|------|---------|
|
|
165
|
+
| 0 | All checkpoints + events verified clean |
|
|
166
|
+
| 1 | One or more checkpoint signatures invalid |
|
|
167
|
+
| 2 | One or more events have broken hash chain |
|
|
168
|
+
| 3 | Bundle file or schema error |
|
|
169
|
+
| 4 | cryptography import error |
|
|
170
|
+
| 5 | Bundle cannot be hash-verified (see below) — **not** a tamper finding |
|
|
171
|
+
| 6 | Checkpoint→event binding mismatch — the signer did not sign these events |
|
|
172
|
+
| 7 | Forensic Confidence attestation invalid, or the score does not recompute |
|
|
173
|
+
|
|
174
|
+
### Exit 5 — UNVERIFIABLE
|
|
175
|
+
|
|
176
|
+
A bundle exported before canonical v1 omits four of the thirteen fields the
|
|
177
|
+
database hashes (`user_id`, `violation_type`, `endpoint`, `request_id`) and
|
|
178
|
+
re-renders the timestamp in a different format, so event hashes cannot be
|
|
179
|
+
recomputed from it. The tool reports that as its own verdict rather than
|
|
180
|
+
calling the data tampered, because a false tamper alarm on healthy data is
|
|
181
|
+
worse than no answer — it teaches operators to disregard real alarms.
|
|
182
|
+
|
|
183
|
+
Chain **linkage** is still fully verified on these bundles, and a genuine
|
|
184
|
+
linkage break still returns exit 2. To verify hashes, re-export from a
|
|
185
|
+
server running canonical v1 (`"canonical_version": 1` appears at the top
|
|
186
|
+
level of the bundle JSON).
|
|
187
|
+
|
|
188
|
+
If you are scripting this tool, treat 0 as pass, 5 as "inconclusive, get a
|
|
189
|
+
better export", and 1/2/6/7 as findings.
|
|
190
|
+
|
|
191
|
+
## Trust model
|
|
192
|
+
|
|
193
|
+
The tool's verification is sound iff:
|
|
194
|
+
|
|
195
|
+
- The `cryptography` library is honest about Ed25519 verification.
|
|
196
|
+
This is the same library Python's TLS stack uses; it's reviewed by
|
|
197
|
+
NIST and widely audited.
|
|
198
|
+
- The bundle's public key is what the bundle claims it is. If a
|
|
199
|
+
relying party wants stronger assurance of the public-key provenance,
|
|
200
|
+
they compare its fingerprint against a key fingerprint published by
|
|
201
|
+
Northgate Strategic out-of-band, then run with `--public-key`.
|
|
202
|
+
|
|
203
|
+
The tool itself is a single Python file you can read in 10 minutes.
|
|
204
|
+
There is no hidden network call, no telemetry, no callback to
|
|
205
|
+
Northgate Strategic. Bundle in → verdict out.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT — anyone can audit, modify, or redistribute. The verifier is the
|
|
210
|
+
trust anchor; the platform's trustworthiness depends on this tool
|
|
211
|
+
being independently scrutinizable.
|
|
212
|
+
|
|
213
|
+
## Sample output
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
trustflash-verify v0.4.0
|
|
217
|
+
schema: trustflash/v1
|
|
218
|
+
tenant: northgate-strategic
|
|
219
|
+
key fp: 3ecb62b07e0b0984
|
|
220
|
+
|
|
221
|
+
✓ Checkpoints: 12/12 valid
|
|
222
|
+
[ok] cp_a846e749 — ok
|
|
223
|
+
[ok] cp_b912f3e2 — ok
|
|
224
|
+
...
|
|
225
|
+
|
|
226
|
+
✓ Events: 2612/2612 valid
|
|
227
|
+
All events verified.
|
|
228
|
+
|
|
229
|
+
✓ Checkpoint→event binding: 12/12 checkpoints bound to exported events
|
|
230
|
+
|
|
231
|
+
✓ Forensic Confidence: attested 91.3 (A-) — recomputed 91.3 (A-) from the signed signal inputs
|
|
232
|
+
|
|
233
|
+
Verdict: CLEAN (exit code 0)
|
|
234
|
+
```
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# trustflash-verify
|
|
2
|
+
|
|
3
|
+
Open-source forensic verifier for TrustSHIELD/AIREC TrustFlash export
|
|
4
|
+
bundles (PF21 patent — TrustFlash Behavioral Audit Black Box).
|
|
5
|
+
|
|
6
|
+
## Why this exists
|
|
7
|
+
|
|
8
|
+
Auditors don't trust "we have a database with hash columns." They want
|
|
9
|
+
**cryptographic evidence they can verify themselves, offline, without
|
|
10
|
+
access to the platform's infrastructure**.
|
|
11
|
+
|
|
12
|
+
A TrustFlash forensic export bundle is a single JSON file containing:
|
|
13
|
+
|
|
14
|
+
- The platform's Ed25519 public key (PEM-encoded)
|
|
15
|
+
- Recent Ed25519-signed checkpoints over the audit chain head
|
|
16
|
+
- Recent enforcement events with their per-event hash chain
|
|
17
|
+
- Step-by-step verification instructions
|
|
18
|
+
|
|
19
|
+
This tool **independently verifies** that bundle. It depends only on
|
|
20
|
+
the `cryptography` library (the same one Python's TLS stack uses); the
|
|
21
|
+
verifier itself is a single Python file you can read, audit, fork, or
|
|
22
|
+
re-implement in any language.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install cryptography
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then either:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Run directly:
|
|
34
|
+
python trustflash_verify.py /path/to/bundle.json
|
|
35
|
+
|
|
36
|
+
# Or symlink onto your PATH:
|
|
37
|
+
chmod +x trustflash_verify.py
|
|
38
|
+
ln -s "$(pwd)/trustflash_verify.py" ~/.local/bin/trustflash-verify
|
|
39
|
+
trustflash-verify /path/to/bundle.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Verify a bundle, human-readable summary
|
|
46
|
+
trustflash-verify bundle.json
|
|
47
|
+
|
|
48
|
+
# JSON output for tooling
|
|
49
|
+
trustflash-verify bundle.json --json
|
|
50
|
+
|
|
51
|
+
# Use a separately-trusted public key (e.g., one Northgate Strategic
|
|
52
|
+
# published on a different channel) instead of the key embedded in
|
|
53
|
+
# the bundle. This is the strongest guarantee: it proves the bundle
|
|
54
|
+
# was signed by the entity whose key fingerprint you trust, even if
|
|
55
|
+
# the bundle itself was tampered to swap keys.
|
|
56
|
+
trustflash-verify bundle.json --public-key /path/to/key.pem
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## What the tool checks
|
|
60
|
+
|
|
61
|
+
For each **checkpoint** in the bundle:
|
|
62
|
+
|
|
63
|
+
1. Select the verification key by the checkpoint's `key_id` from the
|
|
64
|
+
bundle's `public_keys` array — a bundle that spans a key rotation
|
|
65
|
+
carries every key it was signed under. Falls back to the top-level
|
|
66
|
+
`public_key_pem` for checkpoints with no `key_id` or an unlisted one
|
|
67
|
+
(and for older single-key bundles that predate `public_keys`).
|
|
68
|
+
2. Recompute canonical signed bytes:
|
|
69
|
+
`trustflash/v1|<tenant_id>|<chain_head_hash>|<event_count>|<checkpoint_at>|<prev_checkpoint_id_or_GENESIS>`
|
|
70
|
+
3. Verify Ed25519 signature against the selected public key.
|
|
71
|
+
4. Report `valid` / `signature mismatch` / `decode error`.
|
|
72
|
+
|
|
73
|
+
For each **event** in the bundle:
|
|
74
|
+
|
|
75
|
+
1. Recompute canonical hash input from row fields:
|
|
76
|
+
`<id>|<tenant_id>|<user_id>|<module_name>|<decision>|<action>|<severity>|<trust_score>|<violation_type>|<endpoint>|<request_id>|<timestamp>|<prev_event_hash>`
|
|
77
|
+
2. Compute `SHA256` of that canonical input.
|
|
78
|
+
3. Compare against the row's stored `event_hash`.
|
|
79
|
+
4. Verify `prev_event_hash` links to the previous event's `event_hash`
|
|
80
|
+
(or `GENESIS` for the first event).
|
|
81
|
+
|
|
82
|
+
**Checkpoint→event binding** (tool v0.4.0):
|
|
83
|
+
|
|
84
|
+
A valid signature proves a checkpoint record was signed; a self-consistent
|
|
85
|
+
event chain proves internal linkage. Neither alone proves the signer signed
|
|
86
|
+
*these* events. For every checkpoint whose `event_count` falls inside the
|
|
87
|
+
exported slice, the event at that `chain_position` must carry
|
|
88
|
+
`event_hash == chain_head_hash`. A mismatch is a hard failure (exit 6) —
|
|
89
|
+
the events were rebuilt, or the checkpoint belongs to a different chain. A
|
|
90
|
+
signed position with no event in the slice is reported as a warning (not a
|
|
91
|
+
failure): historical write-race forks and export-slice boundaries produce
|
|
92
|
+
that shape on healthy data, and the server-side full-chain verifier is the
|
|
93
|
+
authority there.
|
|
94
|
+
|
|
95
|
+
**Forensic Confidence recompute** (tool v0.4.0):
|
|
96
|
+
|
|
97
|
+
If the bundle carries a `forensic_confidence` block, the platform's 0-100 /
|
|
98
|
+
A-F Forensic Confidence score is recomputable offline from the bundle
|
|
99
|
+
alone. The tool:
|
|
100
|
+
|
|
101
|
+
1. Verifies the Ed25519 signature over the **exact** bytes of
|
|
102
|
+
`payload_canonical` (key selected by `key_id`, same registry as
|
|
103
|
+
checkpoints; `--public-key` pins it).
|
|
104
|
+
2. Requires the human-readable `payload` copy to equal the signed copy.
|
|
105
|
+
3. Requires the attestation's `chain_head_hash` to equal the event hash of
|
|
106
|
+
the highest-`chain_position` event in the bundle — the attestation is
|
|
107
|
+
bound to *this* chain and cannot be replayed against rebuilt events.
|
|
108
|
+
4. Recomputes all five component scores from the attested integer inputs
|
|
109
|
+
(chain continuity, signature validity, override anomaly rate, reflex
|
|
110
|
+
distribution, egress balance), the weighted composite, and the letter
|
|
111
|
+
grade, and compares them to the attested values. A component with a
|
|
112
|
+
zero denominator is a *disclosed* vacuous pass ("no data in window",
|
|
113
|
+
`insufficient_data: true`) — an undisclosed one is a failure.
|
|
114
|
+
|
|
115
|
+
Every attested value is an aggregate: integer counts, scores, weights, a
|
|
116
|
+
grade, a window length, a timestamp, and hashes already present in the
|
|
117
|
+
bundle. No user identifier, email, or content fragment appears in the
|
|
118
|
+
attestation. A bundle **without** the block predates the feature and is
|
|
119
|
+
reported as "score recompute not available" — never as a failure.
|
|
120
|
+
|
|
121
|
+
## Exit codes
|
|
122
|
+
|
|
123
|
+
| Code | Meaning |
|
|
124
|
+
|------|---------|
|
|
125
|
+
| 0 | All checkpoints + events verified clean |
|
|
126
|
+
| 1 | One or more checkpoint signatures invalid |
|
|
127
|
+
| 2 | One or more events have broken hash chain |
|
|
128
|
+
| 3 | Bundle file or schema error |
|
|
129
|
+
| 4 | cryptography import error |
|
|
130
|
+
| 5 | Bundle cannot be hash-verified (see below) — **not** a tamper finding |
|
|
131
|
+
| 6 | Checkpoint→event binding mismatch — the signer did not sign these events |
|
|
132
|
+
| 7 | Forensic Confidence attestation invalid, or the score does not recompute |
|
|
133
|
+
|
|
134
|
+
### Exit 5 — UNVERIFIABLE
|
|
135
|
+
|
|
136
|
+
A bundle exported before canonical v1 omits four of the thirteen fields the
|
|
137
|
+
database hashes (`user_id`, `violation_type`, `endpoint`, `request_id`) and
|
|
138
|
+
re-renders the timestamp in a different format, so event hashes cannot be
|
|
139
|
+
recomputed from it. The tool reports that as its own verdict rather than
|
|
140
|
+
calling the data tampered, because a false tamper alarm on healthy data is
|
|
141
|
+
worse than no answer — it teaches operators to disregard real alarms.
|
|
142
|
+
|
|
143
|
+
Chain **linkage** is still fully verified on these bundles, and a genuine
|
|
144
|
+
linkage break still returns exit 2. To verify hashes, re-export from a
|
|
145
|
+
server running canonical v1 (`"canonical_version": 1` appears at the top
|
|
146
|
+
level of the bundle JSON).
|
|
147
|
+
|
|
148
|
+
If you are scripting this tool, treat 0 as pass, 5 as "inconclusive, get a
|
|
149
|
+
better export", and 1/2/6/7 as findings.
|
|
150
|
+
|
|
151
|
+
## Trust model
|
|
152
|
+
|
|
153
|
+
The tool's verification is sound iff:
|
|
154
|
+
|
|
155
|
+
- The `cryptography` library is honest about Ed25519 verification.
|
|
156
|
+
This is the same library Python's TLS stack uses; it's reviewed by
|
|
157
|
+
NIST and widely audited.
|
|
158
|
+
- The bundle's public key is what the bundle claims it is. If a
|
|
159
|
+
relying party wants stronger assurance of the public-key provenance,
|
|
160
|
+
they compare its fingerprint against a key fingerprint published by
|
|
161
|
+
Northgate Strategic out-of-band, then run with `--public-key`.
|
|
162
|
+
|
|
163
|
+
The tool itself is a single Python file you can read in 10 minutes.
|
|
164
|
+
There is no hidden network call, no telemetry, no callback to
|
|
165
|
+
Northgate Strategic. Bundle in → verdict out.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT — anyone can audit, modify, or redistribute. The verifier is the
|
|
170
|
+
trust anchor; the platform's trustworthiness depends on this tool
|
|
171
|
+
being independently scrutinizable.
|
|
172
|
+
|
|
173
|
+
## Sample output
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
trustflash-verify v0.4.0
|
|
177
|
+
schema: trustflash/v1
|
|
178
|
+
tenant: northgate-strategic
|
|
179
|
+
key fp: 3ecb62b07e0b0984
|
|
180
|
+
|
|
181
|
+
✓ Checkpoints: 12/12 valid
|
|
182
|
+
[ok] cp_a846e749 — ok
|
|
183
|
+
[ok] cp_b912f3e2 — ok
|
|
184
|
+
...
|
|
185
|
+
|
|
186
|
+
✓ Events: 2612/2612 valid
|
|
187
|
+
All events verified.
|
|
188
|
+
|
|
189
|
+
✓ Checkpoint→event binding: 12/12 checkpoints bound to exported events
|
|
190
|
+
|
|
191
|
+
✓ Forensic Confidence: attested 91.3 (A-) — recomputed 91.3 (A-) from the signed signal inputs
|
|
192
|
+
|
|
193
|
+
Verdict: CLEAN (exit code 0)
|
|
194
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Setup for trustflash-verify.
|
|
2
|
+
|
|
3
|
+
Distributable as `pip install trustflash-verify`. Single-script tool;
|
|
4
|
+
console_scripts entry point makes `trustflash-verify` available on PATH
|
|
5
|
+
after install.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from setuptools import setup
|
|
9
|
+
|
|
10
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
11
|
+
long_description = f.read()
|
|
12
|
+
|
|
13
|
+
setup(
|
|
14
|
+
name="trustflash-verify",
|
|
15
|
+
version="0.4.0",
|
|
16
|
+
description=(
|
|
17
|
+
"Open-source forensic verifier for TrustSHIELD/AIREC TrustFlash "
|
|
18
|
+
"audit-export bundles. Verifies Ed25519 checkpoint signatures, the "
|
|
19
|
+
"SHA-256 event hash chain, checkpoint-to-event binding, and the "
|
|
20
|
+
"signed Forensic Confidence score offline, no platform access "
|
|
21
|
+
"required."
|
|
22
|
+
),
|
|
23
|
+
long_description=long_description,
|
|
24
|
+
long_description_content_type="text/markdown",
|
|
25
|
+
author="Northgate Strategic LLC",
|
|
26
|
+
author_email="support@northgatestrategic.com",
|
|
27
|
+
url="https://github.com/northgate-strategic/trustflash-verifier",
|
|
28
|
+
license="MIT",
|
|
29
|
+
py_modules=["trustflash_verify"],
|
|
30
|
+
python_requires=">=3.10",
|
|
31
|
+
install_requires=[
|
|
32
|
+
"cryptography>=41.0.0",
|
|
33
|
+
],
|
|
34
|
+
extras_require={
|
|
35
|
+
"dev": ["pytest>=7"],
|
|
36
|
+
},
|
|
37
|
+
entry_points={
|
|
38
|
+
"console_scripts": [
|
|
39
|
+
"trustflash-verify=trustflash_verify:main",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
classifiers=[
|
|
43
|
+
"Development Status :: 4 - Beta",
|
|
44
|
+
"Intended Audience :: Information Technology",
|
|
45
|
+
"Intended Audience :: Legal Industry",
|
|
46
|
+
"License :: OSI Approved :: MIT License",
|
|
47
|
+
"Operating System :: OS Independent",
|
|
48
|
+
"Programming Language :: Python :: 3",
|
|
49
|
+
"Programming Language :: Python :: 3.10",
|
|
50
|
+
"Programming Language :: Python :: 3.11",
|
|
51
|
+
"Programming Language :: Python :: 3.12",
|
|
52
|
+
"Topic :: Security :: Cryptography",
|
|
53
|
+
"Topic :: System :: Logging",
|
|
54
|
+
],
|
|
55
|
+
keywords="audit forensic verification ed25519 sha256 ai-governance trustshield",
|
|
56
|
+
)
|