voltage-verify 0.1.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.
- voltage_verify-0.1.0/.gitignore +11 -0
- voltage_verify-0.1.0/CHANGELOG.md +18 -0
- voltage_verify-0.1.0/LICENSE +21 -0
- voltage_verify-0.1.0/PKG-INFO +191 -0
- voltage_verify-0.1.0/README.md +136 -0
- voltage_verify-0.1.0/SECURITY.md +32 -0
- voltage_verify-0.1.0/docs/ATTEST_ON_VM.md +62 -0
- voltage_verify-0.1.0/docs/BUNDLE_FORMAT.md +69 -0
- voltage_verify-0.1.0/docs/WHAT_IT_PROVES.md +49 -0
- voltage_verify-0.1.0/pyproject.toml +74 -0
- voltage_verify-0.1.0/src/voltage_verify/__init__.py +4 -0
- voltage_verify-0.1.0/src/voltage_verify/__main__.py +9 -0
- voltage_verify-0.1.0/src/voltage_verify/attest.py +184 -0
- voltage_verify-0.1.0/src/voltage_verify/bundle.py +101 -0
- voltage_verify-0.1.0/src/voltage_verify/canonical.py +67 -0
- voltage_verify-0.1.0/src/voltage_verify/cli.py +184 -0
- voltage_verify-0.1.0/src/voltage_verify/data/intel_sgx_root_ca.pem +16 -0
- voltage_verify-0.1.0/src/voltage_verify/der.py +92 -0
- voltage_verify-0.1.0/src/voltage_verify/manifest.py +99 -0
- voltage_verify-0.1.0/src/voltage_verify/nvidia.py +196 -0
- voltage_verify-0.1.0/src/voltage_verify/pcs.py +322 -0
- voltage_verify-0.1.0/src/voltage_verify/registry.py +102 -0
- voltage_verify-0.1.0/src/voltage_verify/selftest.py +136 -0
- voltage_verify-0.1.0/src/voltage_verify/tdx.py +327 -0
- voltage_verify-0.1.0/src/voltage_verify/verify.py +263 -0
- voltage_verify-0.1.0/tests/conftest.py +37 -0
- voltage_verify-0.1.0/tests/fixtures/intel_collateral_90c06f000000_2026-09-12.json +15 -0
- voltage_verify-0.1.0/tests/fixtures/nras_h200_2026-09-04.json +1 -0
- voltage_verify-0.1.0/tests/fixtures/nras_jwks_2026-09-12.json +1 -0
- voltage_verify-0.1.0/tests/fixtures/nras_ppcie_8xh100_2026-09-10.json +1 -0
- voltage_verify-0.1.0/tests/fixtures/quote_h200_2026-09-04.bin +0 -0
- voltage_verify-0.1.0/tests/fixtures/report_data_h200_2026-09-04.bin +1 -0
- voltage_verify-0.1.0/tests/test_canonical_and_manifest.py +65 -0
- voltage_verify-0.1.0/tests/test_cli.py +47 -0
- voltage_verify-0.1.0/tests/test_example_bundle.py +38 -0
- voltage_verify-0.1.0/tests/test_nvidia.py +77 -0
- voltage_verify-0.1.0/tests/test_pcs.py +54 -0
- voltage_verify-0.1.0/tests/test_tdx.py +68 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-09-12)
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
* `manifest`: image digest resolution through the OCI registry API (no pull), artifact
|
|
8
|
+
hashing, free-form extras, verifier-side random challenge.
|
|
9
|
+
* `attest`: TDX quote through configfs TSM with `report_data = SHA-512(manifest)`, NVIDIA
|
|
10
|
+
NRAS attestation with `nonce = SHA-256(manifest)`, single-GPU and multi-GPU Protected PCIe
|
|
11
|
+
modes, Intel and NVIDIA collateral embedded for offline verification.
|
|
12
|
+
* `verify`: quote structure, attestation key signature, Quoting Enclave binding and signature,
|
|
13
|
+
PCK chain to the pinned Intel SGX Root CA, TCB level and TDX module identity against Intel's
|
|
14
|
+
signed TCB info, Quoting Enclave identity, CRLs, NRAS ES384 signatures, nonce, claims policy,
|
|
15
|
+
token freshness, challenge and image expectations.
|
|
16
|
+
* `selftest`: six negative tests (image digest, artifact, manifest field, challenge replay,
|
|
17
|
+
quote tampering, GPU claim tampering).
|
|
18
|
+
* Tests against real evidence captured on VoltageGPU Confidential VMs.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VOLTAGE EI (VoltageGPU), Julien Aubry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: voltage-verify
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bind an Intel TDX quote and an NVIDIA GPU attestation to the workload you meant to run, then verify the bundle without trusting the cloud provider.
|
|
5
|
+
Project-URL: Homepage, https://voltagegpu.com/blog/two-proofs-tdx-nvidia-h200-attestation-tenant
|
|
6
|
+
Project-URL: Documentation, https://docs.voltagegpu.com/pods/confidential-vm
|
|
7
|
+
Project-URL: Source, https://github.com/Jabsama/voltage-verify
|
|
8
|
+
Project-URL: Issues, https://github.com/Jabsama/voltage-verify/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/Jabsama/voltage-verify/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Mirror, https://voltagegpu.com/blog/two-proofs/voltage-verify/
|
|
11
|
+
Project-URL: Evidence, https://voltagegpu.com/blog/two-proofs/evidence/README.txt
|
|
12
|
+
Author-email: "VoltageGPU (VOLTAGE EI)" <contact@voltagegpu.com>
|
|
13
|
+
License: MIT License
|
|
14
|
+
|
|
15
|
+
Copyright (c) 2026 VOLTAGE EI (VoltageGPU), Julien Aubry
|
|
16
|
+
|
|
17
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
in the Software without restriction, including without limitation the rights
|
|
20
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
furnished to do so, subject to the following conditions:
|
|
23
|
+
|
|
24
|
+
The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
copies or substantial portions of the Software.
|
|
26
|
+
|
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
SOFTWARE.
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Keywords: attestation,confidential-computing,gpu,intel-tdx,nvidia,remote-attestation
|
|
36
|
+
Classifier: Development Status :: 3 - Alpha
|
|
37
|
+
Classifier: Environment :: Console
|
|
38
|
+
Classifier: Intended Audience :: Developers
|
|
39
|
+
Classifier: Intended Audience :: Information Technology
|
|
40
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
41
|
+
Classifier: Programming Language :: Python :: 3
|
|
42
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
43
|
+
Classifier: Topic :: Security :: Cryptography
|
|
44
|
+
Requires-Python: >=3.10
|
|
45
|
+
Requires-Dist: cryptography<47,>=42
|
|
46
|
+
Requires-Dist: pyjwt<3,>=2.7
|
|
47
|
+
Provides-Extra: attest
|
|
48
|
+
Requires-Dist: nv-attestation-sdk>=2.7; extra == 'attest'
|
|
49
|
+
Requires-Dist: nvidia-ml-py>=12; extra == 'attest'
|
|
50
|
+
Provides-Extra: dev
|
|
51
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
53
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
54
|
+
Description-Content-Type: text/markdown
|
|
55
|
+
|
|
56
|
+
# voltage-verify
|
|
57
|
+
|
|
58
|
+
Bind an Intel TDX quote and an NVIDIA GPU attestation to the workload you meant to run, then
|
|
59
|
+
verify the bundle on your own machine, without trusting the cloud provider.
|
|
60
|
+
|
|
61
|
+
`voltage-verify` is a small command line tool with three roles:
|
|
62
|
+
|
|
63
|
+
1. **On your machine**, it writes a *manifest*: the container image digest, the digests of the
|
|
64
|
+
model or files you care about, a free-text statement, and a fresh random challenge. Two
|
|
65
|
+
hashes of that manifest become the *commitments*.
|
|
66
|
+
2. **Inside the confidential VM**, it asks the hardware to sign those commitments: the Intel
|
|
67
|
+
TDX quote carries `SHA-512(manifest)` as its 64-byte `report_data`, and NVIDIA's Remote
|
|
68
|
+
Attestation Service (NRAS) signs GPU claims over the nonce `SHA-256(manifest)`. It writes
|
|
69
|
+
one JSON *bundle* with the quote, the NVIDIA tokens and the public collateral needed to
|
|
70
|
+
check them later.
|
|
71
|
+
3. **Back on your machine**, it verifies the bundle: Intel's signature chain to the pinned
|
|
72
|
+
Intel SGX Root CA, the platform's TCB status against Intel's published TCB info, the
|
|
73
|
+
Quoting Enclave identity, revocation lists, NVIDIA's ES384 signatures against NRAS's JWKS,
|
|
74
|
+
the per-GPU claims (measurements ok, secure boot on, debug off), and above all that both
|
|
75
|
+
proofs carry *your* commitments. Then it runs six negative tests to show that any change
|
|
76
|
+
to the manifest, the challenge, the quote or a GPU claim is rejected.
|
|
77
|
+
|
|
78
|
+
It was written by [VoltageGPU](https://voltagegpu.com) so that tenants of its Confidential VMs
|
|
79
|
+
can verify more than "this is a TDX VM with a confidential GPU": they can verify that the two
|
|
80
|
+
hardware proofs were produced *for the workload described in a manifest they wrote*, on a
|
|
81
|
+
challenge they chose. The trust chain ends at Intel and NVIDIA, never at VoltageGPU.
|
|
82
|
+
|
|
83
|
+
## What it proves, and what it does not
|
|
84
|
+
|
|
85
|
+
Verified means:
|
|
86
|
+
|
|
87
|
+
* the TDX quote was produced inside a genuine Intel TDX Trust Domain, on a platform whose
|
|
88
|
+
provisioning certificate chains to Intel's root, at an acceptable TCB level, by a genuine
|
|
89
|
+
Quoting Enclave, and it embeds `SHA-512` of your manifest;
|
|
90
|
+
* NVIDIA's service signed, over `SHA-256` of your manifest, that the GPU(s) in that VM passed
|
|
91
|
+
attestation with secure boot on and debugging off;
|
|
92
|
+
* both proofs were made after you issued the challenge, so they cannot be replayed from an
|
|
93
|
+
earlier session or copied from another tenant.
|
|
94
|
+
|
|
95
|
+
Verified does **not** mean:
|
|
96
|
+
|
|
97
|
+
* that the GPU *executed* the image or model named in the manifest. Binding a manifest to a
|
|
98
|
+
quote proves the hardware signed your description of the workload; proving that this exact
|
|
99
|
+
code ran needs a measured launcher (for instance the Confidential Containers project with
|
|
100
|
+
a key broker), which is outside this tool;
|
|
101
|
+
* anything about the VM's own software stack beyond what the TDX measurements (`MRTD`,
|
|
102
|
+
`RTMR0..3`) say. The tool prints them; comparing them against a reference image is your
|
|
103
|
+
policy, not the tool's;
|
|
104
|
+
* anything about a VM you did not attest yourself.
|
|
105
|
+
|
|
106
|
+
`docs/WHAT_IT_PROVES.md` goes through every check and its limit.
|
|
107
|
+
|
|
108
|
+
## Install
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
# verifier machine: Python 3.10+, cryptography, PyJWT
|
|
112
|
+
pip install voltage-verify
|
|
113
|
+
# inside the VM: the NVIDIA SDK first (it pins cryptography and PyJWT), then the tool
|
|
114
|
+
pip install nv-attestation-sdk nvidia-ml-py
|
|
115
|
+
pip install --no-deps voltage-verify
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Source and issues: https://github.com/Jabsama/voltage-verify. The same wheel and source
|
|
119
|
+
archive are mirrored with SHA-256 sums at https://voltagegpu.com/blog/two-proofs/voltage-verify/
|
|
120
|
+
for installs that must not touch PyPI (`pip install <wheel URL>`).
|
|
121
|
+
|
|
122
|
+
## Reference run
|
|
123
|
+
|
|
124
|
+
`examples/hello-workload/` holds a real bundle captured on 12 September 2026 on a VoltageGPU
|
|
125
|
+
`h100-xlarge` Confidential VM (8x H100, NVIDIA Protected PCIe mode), with its manifest and the
|
|
126
|
+
unedited run log. Replay the verification on your own machine:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
voltage-verify verify examples/hello-workload/bundle-8xh100-2026-09-12.json \
|
|
130
|
+
--challenge ef7f54c160627ee536a02b5e73896ac4b1ac2cdefdb7cfaaf2366a7d33cc8731 --hwmodel GH100 --gpus 8
|
|
131
|
+
voltage-verify selftest examples/hello-workload/bundle-8xh100-2026-09-12.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Expected: every check `PASS`, platform TCB `UpToDate`, Quoting Enclave `UpToDate`, eight
|
|
135
|
+
`GH100` devices with `measres success`, then six mutations rejected.
|
|
136
|
+
|
|
137
|
+
## Use
|
|
138
|
+
|
|
139
|
+
On your machine, describe the workload and generate a challenge:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
voltage-verify manifest --image ghcr.io/you/app:1.4.2 --artifact model.safetensors \
|
|
143
|
+
--statement "inference run for customer X" -o manifest.json
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Copy `manifest.json` into the VM (scp), then, as root inside the VM:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
sudo -E python -m voltage_verify attest --manifest manifest.json -o bundle.json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Copy `bundle.json` back, then:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
voltage-verify verify bundle.json --challenge <the challenge printed by `manifest`>
|
|
156
|
+
voltage-verify selftest bundle.json --challenge <same>
|
|
157
|
+
voltage-verify verify bundle.json --offline # same checks, from the collateral in the bundle
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Exit code 0 means verified, 1 means a required check failed, 2 means the bundle or arguments
|
|
161
|
+
are unusable. `--json` prints the machine-readable report.
|
|
162
|
+
|
|
163
|
+
## Bundle format
|
|
164
|
+
|
|
165
|
+
Documented in `docs/BUNDLE_FORMAT.md`. In short: the manifest verbatim, both commitments, the
|
|
166
|
+
raw TDX quote (base64), the NRAS token array as returned by the NVIDIA SDK, NRAS's JWKS and
|
|
167
|
+
Intel's TCB info, QE identity and CRLs as fetched at attestation time, plus a few facts about
|
|
168
|
+
the VM (kernel, driver, `nvidia-smi conf-compute -q`). The verifier trusts none of it: it
|
|
169
|
+
recomputes the commitments from the manifest and checks every signature.
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
python -m venv .venv && . .venv/bin/activate
|
|
175
|
+
pip install -e ".[dev]"
|
|
176
|
+
pytest
|
|
177
|
+
ruff check src tests
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The tests run offline against real evidence: a TDX quote captured on a VoltageGPU H200 VM on
|
|
181
|
+
4 September 2026, NRAS tokens from 4 and 10 September 2026 (single H200, 8x H100 node in
|
|
182
|
+
NVIDIA Protected PCIe mode), and a snapshot of Intel's collateral and NVIDIA's JWKS.
|
|
183
|
+
|
|
184
|
+
## Security
|
|
185
|
+
|
|
186
|
+
See `SECURITY.md`. In one line: report anything that would make `verify` say yes when it
|
|
187
|
+
should say no to contact@voltagegpu.com, and expect an answer within two working days.
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT. Copyright 2026 VOLTAGE EI (VoltageGPU).
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# voltage-verify
|
|
2
|
+
|
|
3
|
+
Bind an Intel TDX quote and an NVIDIA GPU attestation to the workload you meant to run, then
|
|
4
|
+
verify the bundle on your own machine, without trusting the cloud provider.
|
|
5
|
+
|
|
6
|
+
`voltage-verify` is a small command line tool with three roles:
|
|
7
|
+
|
|
8
|
+
1. **On your machine**, it writes a *manifest*: the container image digest, the digests of the
|
|
9
|
+
model or files you care about, a free-text statement, and a fresh random challenge. Two
|
|
10
|
+
hashes of that manifest become the *commitments*.
|
|
11
|
+
2. **Inside the confidential VM**, it asks the hardware to sign those commitments: the Intel
|
|
12
|
+
TDX quote carries `SHA-512(manifest)` as its 64-byte `report_data`, and NVIDIA's Remote
|
|
13
|
+
Attestation Service (NRAS) signs GPU claims over the nonce `SHA-256(manifest)`. It writes
|
|
14
|
+
one JSON *bundle* with the quote, the NVIDIA tokens and the public collateral needed to
|
|
15
|
+
check them later.
|
|
16
|
+
3. **Back on your machine**, it verifies the bundle: Intel's signature chain to the pinned
|
|
17
|
+
Intel SGX Root CA, the platform's TCB status against Intel's published TCB info, the
|
|
18
|
+
Quoting Enclave identity, revocation lists, NVIDIA's ES384 signatures against NRAS's JWKS,
|
|
19
|
+
the per-GPU claims (measurements ok, secure boot on, debug off), and above all that both
|
|
20
|
+
proofs carry *your* commitments. Then it runs six negative tests to show that any change
|
|
21
|
+
to the manifest, the challenge, the quote or a GPU claim is rejected.
|
|
22
|
+
|
|
23
|
+
It was written by [VoltageGPU](https://voltagegpu.com) so that tenants of its Confidential VMs
|
|
24
|
+
can verify more than "this is a TDX VM with a confidential GPU": they can verify that the two
|
|
25
|
+
hardware proofs were produced *for the workload described in a manifest they wrote*, on a
|
|
26
|
+
challenge they chose. The trust chain ends at Intel and NVIDIA, never at VoltageGPU.
|
|
27
|
+
|
|
28
|
+
## What it proves, and what it does not
|
|
29
|
+
|
|
30
|
+
Verified means:
|
|
31
|
+
|
|
32
|
+
* the TDX quote was produced inside a genuine Intel TDX Trust Domain, on a platform whose
|
|
33
|
+
provisioning certificate chains to Intel's root, at an acceptable TCB level, by a genuine
|
|
34
|
+
Quoting Enclave, and it embeds `SHA-512` of your manifest;
|
|
35
|
+
* NVIDIA's service signed, over `SHA-256` of your manifest, that the GPU(s) in that VM passed
|
|
36
|
+
attestation with secure boot on and debugging off;
|
|
37
|
+
* both proofs were made after you issued the challenge, so they cannot be replayed from an
|
|
38
|
+
earlier session or copied from another tenant.
|
|
39
|
+
|
|
40
|
+
Verified does **not** mean:
|
|
41
|
+
|
|
42
|
+
* that the GPU *executed* the image or model named in the manifest. Binding a manifest to a
|
|
43
|
+
quote proves the hardware signed your description of the workload; proving that this exact
|
|
44
|
+
code ran needs a measured launcher (for instance the Confidential Containers project with
|
|
45
|
+
a key broker), which is outside this tool;
|
|
46
|
+
* anything about the VM's own software stack beyond what the TDX measurements (`MRTD`,
|
|
47
|
+
`RTMR0..3`) say. The tool prints them; comparing them against a reference image is your
|
|
48
|
+
policy, not the tool's;
|
|
49
|
+
* anything about a VM you did not attest yourself.
|
|
50
|
+
|
|
51
|
+
`docs/WHAT_IT_PROVES.md` goes through every check and its limit.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
# verifier machine: Python 3.10+, cryptography, PyJWT
|
|
57
|
+
pip install voltage-verify
|
|
58
|
+
# inside the VM: the NVIDIA SDK first (it pins cryptography and PyJWT), then the tool
|
|
59
|
+
pip install nv-attestation-sdk nvidia-ml-py
|
|
60
|
+
pip install --no-deps voltage-verify
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Source and issues: https://github.com/Jabsama/voltage-verify. The same wheel and source
|
|
64
|
+
archive are mirrored with SHA-256 sums at https://voltagegpu.com/blog/two-proofs/voltage-verify/
|
|
65
|
+
for installs that must not touch PyPI (`pip install <wheel URL>`).
|
|
66
|
+
|
|
67
|
+
## Reference run
|
|
68
|
+
|
|
69
|
+
`examples/hello-workload/` holds a real bundle captured on 12 September 2026 on a VoltageGPU
|
|
70
|
+
`h100-xlarge` Confidential VM (8x H100, NVIDIA Protected PCIe mode), with its manifest and the
|
|
71
|
+
unedited run log. Replay the verification on your own machine:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
voltage-verify verify examples/hello-workload/bundle-8xh100-2026-09-12.json \
|
|
75
|
+
--challenge ef7f54c160627ee536a02b5e73896ac4b1ac2cdefdb7cfaaf2366a7d33cc8731 --hwmodel GH100 --gpus 8
|
|
76
|
+
voltage-verify selftest examples/hello-workload/bundle-8xh100-2026-09-12.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Expected: every check `PASS`, platform TCB `UpToDate`, Quoting Enclave `UpToDate`, eight
|
|
80
|
+
`GH100` devices with `measres success`, then six mutations rejected.
|
|
81
|
+
|
|
82
|
+
## Use
|
|
83
|
+
|
|
84
|
+
On your machine, describe the workload and generate a challenge:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
voltage-verify manifest --image ghcr.io/you/app:1.4.2 --artifact model.safetensors \
|
|
88
|
+
--statement "inference run for customer X" -o manifest.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Copy `manifest.json` into the VM (scp), then, as root inside the VM:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
sudo -E python -m voltage_verify attest --manifest manifest.json -o bundle.json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Copy `bundle.json` back, then:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
voltage-verify verify bundle.json --challenge <the challenge printed by `manifest`>
|
|
101
|
+
voltage-verify selftest bundle.json --challenge <same>
|
|
102
|
+
voltage-verify verify bundle.json --offline # same checks, from the collateral in the bundle
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Exit code 0 means verified, 1 means a required check failed, 2 means the bundle or arguments
|
|
106
|
+
are unusable. `--json` prints the machine-readable report.
|
|
107
|
+
|
|
108
|
+
## Bundle format
|
|
109
|
+
|
|
110
|
+
Documented in `docs/BUNDLE_FORMAT.md`. In short: the manifest verbatim, both commitments, the
|
|
111
|
+
raw TDX quote (base64), the NRAS token array as returned by the NVIDIA SDK, NRAS's JWKS and
|
|
112
|
+
Intel's TCB info, QE identity and CRLs as fetched at attestation time, plus a few facts about
|
|
113
|
+
the VM (kernel, driver, `nvidia-smi conf-compute -q`). The verifier trusts none of it: it
|
|
114
|
+
recomputes the commitments from the manifest and checks every signature.
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
python -m venv .venv && . .venv/bin/activate
|
|
120
|
+
pip install -e ".[dev]"
|
|
121
|
+
pytest
|
|
122
|
+
ruff check src tests
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The tests run offline against real evidence: a TDX quote captured on a VoltageGPU H200 VM on
|
|
126
|
+
4 September 2026, NRAS tokens from 4 and 10 September 2026 (single H200, 8x H100 node in
|
|
127
|
+
NVIDIA Protected PCIe mode), and a snapshot of Intel's collateral and NVIDIA's JWKS.
|
|
128
|
+
|
|
129
|
+
## Security
|
|
130
|
+
|
|
131
|
+
See `SECURITY.md`. In one line: report anything that would make `verify` say yes when it
|
|
132
|
+
should say no to contact@voltagegpu.com, and expect an answer within two working days.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT. Copyright 2026 VOLTAGE EI (VoltageGPU).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
`voltage-verify` is a verifier. The bugs that matter are the ones that make it accept
|
|
4
|
+
evidence it should reject: a signature check that can be skipped, a commitment that can be
|
|
5
|
+
recomputed without the hardware noticing, a policy claim that is read but not enforced, a
|
|
6
|
+
collateral document accepted without its signature.
|
|
7
|
+
|
|
8
|
+
## Reporting
|
|
9
|
+
|
|
10
|
+
Write to contact@voltagegpu.com with the subject `voltage-verify security`. Include the bundle
|
|
11
|
+
or the minimal input that triggers the behaviour, the version (`voltage-verify --version`) and
|
|
12
|
+
what you expected. You will get a human answer within two working days, a fix or a documented
|
|
13
|
+
limitation within thirty, and credit in the changelog if you want it.
|
|
14
|
+
|
|
15
|
+
Please do not open a public issue for a bypass before it is fixed.
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
In scope: everything under `src/voltage_verify`, the bundle format, the documented checks in
|
|
20
|
+
`docs/WHAT_IT_PROVES.md`.
|
|
21
|
+
|
|
22
|
+
Out of scope: the security of Intel TDX or NVIDIA confidential computing themselves, the
|
|
23
|
+
availability of Intel's PCS or NVIDIA's NRAS, and the `attest` command running on a machine
|
|
24
|
+
that is already compromised at the hypervisor level (that is what the hardware proofs detect).
|
|
25
|
+
|
|
26
|
+
## What the tool pins
|
|
27
|
+
|
|
28
|
+
* Intel SGX Root CA, by SHA-256 fingerprint, shipped in the package
|
|
29
|
+
(`src/voltage_verify/data/intel_sgx_root_ca.pem`).
|
|
30
|
+
* NVIDIA NRAS issuer `https://nras.attestation.nvidia.com` and its JWKS, fetched over TLS or
|
|
31
|
+
embedded in the bundle at attestation time.
|
|
32
|
+
* Accepted JWT algorithms: ES384 and ES256 only. `none`, HMAC and RSA are rejected.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Running `attest` inside a Confidential VM
|
|
2
|
+
|
|
3
|
+
`attest` needs three things the VM must expose: the TDX guest device and configfs TSM
|
|
4
|
+
(`/sys/kernel/config/tsm/report`), an NVIDIA GPU in confidential-computing mode with the
|
|
5
|
+
driver's attestation support, and outbound HTTPS to NVIDIA (NRAS, OCSP, RIM) and Intel (PCS).
|
|
6
|
+
On a VoltageGPU Confidential VM all three are there at boot.
|
|
7
|
+
|
|
8
|
+
## One-time setup in the VM
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
sudo apt-get update
|
|
12
|
+
sudo apt-get install -y python3-venv python3-pip
|
|
13
|
+
python3 -m venv ~/vv
|
|
14
|
+
. ~/vv/bin/activate
|
|
15
|
+
pip install nv-attestation-sdk nvidia-ml-py
|
|
16
|
+
pip install --no-deps voltage-verify
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Install the NVIDIA SDK first: it pins `cryptography==43.0.1` and `PyJWT 2.7`, both inside the
|
|
20
|
+
ranges this tool accepts, and pulls the NVIDIA local verifier and `nvidia-ml-py`. The first
|
|
21
|
+
install takes a minute. `pip install "voltage-verify[attest]"` in one step also works, but
|
|
22
|
+
letting pip resolve both at once is slower on the VM than the two commands above. Without
|
|
23
|
+
PyPI access, install the wheel mirrored at
|
|
24
|
+
https://voltagegpu.com/blog/two-proofs/voltage-verify/ with `--no-deps`.
|
|
25
|
+
|
|
26
|
+
## Multi-GPU nodes (NVIDIA Protected PCIe mode)
|
|
27
|
+
|
|
28
|
+
On an 8-GPU Hopper node the GPUs run in NVIDIA's multi-GPU *Protected PCIe* mode. `nvidia-smi
|
|
29
|
+
conf-compute -q` shows `CC State: OFF` next to `Multi-GPU Mode: Protected PCIe`; that is the
|
|
30
|
+
normal reading for that mode, not a failure. Two things differ from a single-GPU VM:
|
|
31
|
+
|
|
32
|
+
* the ready state has to be set once after boot: `sudo nvidia-smi conf-compute -srs 1`;
|
|
33
|
+
* the NVIDIA SDK refuses "standalone" attestation on such a node, so `attest` calls it with
|
|
34
|
+
`ppcie_mode=False` (this SDK flag means "not standalone"). `--mode auto` picks this when
|
|
35
|
+
more than one GPU is present.
|
|
36
|
+
|
|
37
|
+
## Produce the bundle
|
|
38
|
+
|
|
39
|
+
Copy the manifest your verifier produced, then run as root (TSM needs it):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
sudo -E ~/vv/bin/python -m voltage_verify attest --manifest manifest.json -o bundle.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
What happens, in order:
|
|
46
|
+
|
|
47
|
+
1. the manifest is validated and both commitments are computed;
|
|
48
|
+
2. `report_data = SHA-512(manifest)` is written to a fresh entry under
|
|
49
|
+
`/sys/kernel/config/tsm/report/`, the quote is read from `outblob` (retry only on
|
|
50
|
+
`EINVAL`, which signals a concurrent request; any other error stops);
|
|
51
|
+
3. the NVIDIA SDK is called with `nonce = SHA-256(manifest)` against NRAS;
|
|
52
|
+
4. NRAS's JWKS and Intel's TCB info, QE identity and CRLs are fetched and embedded;
|
|
53
|
+
5. `bundle.json` is written. Nothing secret is in it: quote, public tokens, public collateral,
|
|
54
|
+
and a few `nvidia-smi` lines.
|
|
55
|
+
|
|
56
|
+
Copy `bundle.json` back to your machine and verify it there. The VM's own opinion of the
|
|
57
|
+
bundle is worth nothing; that is the point.
|
|
58
|
+
|
|
59
|
+
## Timing and cost
|
|
60
|
+
|
|
61
|
+
On a single-H200 VM the whole `attest` step takes about one minute after the SDK is installed.
|
|
62
|
+
Release the VM when you have the bundle; the evidence does not depend on the VM staying up.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Bundle format `voltage-verify-bundle/1`
|
|
2
|
+
|
|
3
|
+
A bundle is one JSON document. Keys are sorted when written; readers must not rely on order.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"format": "voltage-verify-bundle/1",
|
|
8
|
+
"tool": {"name": "voltage-verify", "version": "0.1.0"},
|
|
9
|
+
"created_at": "2026-09-12T01:02:03+00:00",
|
|
10
|
+
"manifest": {
|
|
11
|
+
"format": "voltage-verify-manifest/1",
|
|
12
|
+
"created_at": "2026-09-12T00:58:11+00:00",
|
|
13
|
+
"challenge": "<64 hex chars, chosen by the verifier>",
|
|
14
|
+
"workload": {
|
|
15
|
+
"image": {"reference": "ghcr.io/you/app:1.4.2", "digest": "sha256:<64 hex>"},
|
|
16
|
+
"artifacts": [{"name": "model.safetensors", "sha256": "<64 hex>", "size": 123456}],
|
|
17
|
+
"extra": {"any": "string"}
|
|
18
|
+
},
|
|
19
|
+
"statement": "free text or null"
|
|
20
|
+
},
|
|
21
|
+
"commitments": {"sha256": "<64 hex>", "sha512": "<128 hex>"},
|
|
22
|
+
"tdx": {"quote_b64": "<base64 of the raw quote, padding removed>", "report_data_hex": "<128 hex>"},
|
|
23
|
+
"nvidia": {
|
|
24
|
+
"mode": "single-gpu | multi-gpu-ppcie",
|
|
25
|
+
"nras": [["JWT", "<overall>"], {"REMOTE_GPU_CLAIMS": [["JWT", "<verifier>"], {"GPU-0": "<jwt>"}]}],
|
|
26
|
+
"jwks": {"keys": [ ... ]}
|
|
27
|
+
},
|
|
28
|
+
"collateral": {
|
|
29
|
+
"intel": {
|
|
30
|
+
"tcb_info": {"kind": "tcb_info", "body": "<exact PCS response>", "issuer_chain_pem": "<PEM chain>"},
|
|
31
|
+
"qe_identity": {"kind": "qe_identity", "body": "<exact PCS response>", "issuer_chain_pem": "<PEM chain>"},
|
|
32
|
+
"pck_crl_pem": "<PEM CRL or null>",
|
|
33
|
+
"root_crl_der_b64": "<base64 DER CRL or null>",
|
|
34
|
+
"fetched_at": "2026-09-12T01:02:00+00:00"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"environment": {"kernel": "...", "gpus": "...", "conf_compute": "..."}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Commitments
|
|
42
|
+
|
|
43
|
+
`canonical = JSON(manifest)` with keys sorted by code point, separators `,` and `:` with no
|
|
44
|
+
spaces, UTF-8, non-ASCII characters kept as is, no floats anywhere. This matches RFC 8785 for
|
|
45
|
+
the value types a manifest contains.
|
|
46
|
+
|
|
47
|
+
* `commitments.sha256 = SHA-256(canonical)`, hex. This is the NVIDIA nonce: the SDK passes it
|
|
48
|
+
to NRAS, which returns it in the verifier token as `eat_nonce`.
|
|
49
|
+
* `commitments.sha512 = SHA-512(canonical)`, hex. This is the TDX `report_data`: written to
|
|
50
|
+
the configfs TSM `inblob`, returned verbatim at byte offset 568 of the quote.
|
|
51
|
+
|
|
52
|
+
A verifier recomputes both from `manifest` and ignores the stored values except to flag a
|
|
53
|
+
mismatch. Everything binding is inside the signed evidence.
|
|
54
|
+
|
|
55
|
+
## Why the collateral travels with the bundle
|
|
56
|
+
|
|
57
|
+
Intel's TCB info and QE identity are re-issued regularly and NVIDIA rotates its JWKS keys
|
|
58
|
+
within days. A bundle verified six months later would otherwise fail for reasons unrelated
|
|
59
|
+
to the evidence. The embedded copies are signed by Intel (ECDSA P-256 over the exact response
|
|
60
|
+
body, issuer chain to the pinned Intel SGX Root CA) and by NVIDIA (x5c chain in the JWKS),
|
|
61
|
+
so `verify --offline` still ends at a hardware vendor's key. `verify` without `--offline`
|
|
62
|
+
refetches everything and reports which source it used.
|
|
63
|
+
|
|
64
|
+
## Compatibility rules
|
|
65
|
+
|
|
66
|
+
* A reader must reject any `format` it does not know.
|
|
67
|
+
* Fields may be added in later minor formats; unknown fields are ignored.
|
|
68
|
+
* `nras` is stored exactly as the NVIDIA SDK returns it, so any change in the SDK layout
|
|
69
|
+
shows up as a verification failure rather than a silent reinterpretation.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# What each check proves, and what it does not
|
|
2
|
+
|
|
3
|
+
`voltage-verify verify` prints one line per check. This page is the honest reading of each.
|
|
4
|
+
|
|
5
|
+
## Manifest
|
|
6
|
+
|
|
7
|
+
| Check | Passes when | Proves | Does not prove |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `manifest.format` | the manifest has the expected shape | the bundle is parseable | anything |
|
|
10
|
+
| `manifest.commitments` | SHA-256 and SHA-512 of the canonical manifest equal the stored values | bookkeeping is consistent | anything: an attacker can recompute them |
|
|
11
|
+
| `manifest.challenge` | the challenge equals the one you passed with `--challenge` | the bundle was made for this session | anything without the TDX and NVIDIA checks below |
|
|
12
|
+
| `manifest.image` | the image digest equals `--image-digest` | the manifest names the image you expect | that the image ran |
|
|
13
|
+
|
|
14
|
+
## Intel TDX
|
|
15
|
+
|
|
16
|
+
| Check | Passes when | Proves | Does not prove |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `tdx.structure` | version 4 quote, TEE type TDX, ECDSA-P256 key, QE report and PCK chain present | it is a TDX quote | anything about its origin |
|
|
19
|
+
| `tdx.report_data` | the quote's 64-byte `report_data` equals `SHA-512(manifest)` | the quote was requested with your manifest hash, so after your challenge | who requested it |
|
|
20
|
+
| `tdx.signatures` | attestation key signs header+report; QE report binds the key; PCK certificate signs the QE report; PCK chain verifies to the pinned Intel SGX Root CA and is within validity | the quote was produced by a genuine Intel TDX Quoting Enclave on Intel-provisioned hardware | that the platform's firmware is current |
|
|
21
|
+
| `tdx.collateral` | TCB info and QE identity carry Intel's signature and chain to the root | the collateral is Intel's | freshness (see `tdx.collateral_fresh`) |
|
|
22
|
+
| `tdx.tcb` | the platform's SVNs (from the PCK certificate and the quote's `tee_tcb_svn`) reach a level Intel rates `UpToDate` or `SWHardeningNeeded`; the TDX module identity matches; the Quoting Enclave identity matches and is `UpToDate` | the platform is patched to a level Intel accepts | that no unknown vulnerability exists |
|
|
23
|
+
| `tdx.revocation` | the PCK certificate and its CA are absent from Intel's CRLs | Intel has not revoked this platform's provisioning identity | anything if CRLs are missing (then the line says NOT checked) |
|
|
24
|
+
|
|
25
|
+
The quote's `MRTD` and `RTMR0..3` are printed as facts. They measure the VM's initial state
|
|
26
|
+
and boot chain. This tool does not compare them to a reference: whether a given `MRTD` is the
|
|
27
|
+
image you expect is a policy decision that belongs to you.
|
|
28
|
+
|
|
29
|
+
## NVIDIA
|
|
30
|
+
|
|
31
|
+
| Check | Passes when | Proves | Does not prove |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `nvidia.jwks` | a JWKS is available (live or embedded) | keys can be looked up | anything |
|
|
34
|
+
| `nvidia.signatures` | the verifier token and every device token verify (ES384) with a key from NVIDIA's JWKS, issuer is NRAS | NVIDIA issued these claims | when, until `nvidia.freshness` |
|
|
35
|
+
| `nvidia.nonce` | `eat_nonce` equals `SHA-256(manifest)` | the claims were issued for your manifest hash, after your challenge | which VM: the TDX side does that |
|
|
36
|
+
| `nvidia.policy` | overall result true; every GPU: `measres` success, `secboot` true, `dbgstat` disabled, nonce matched, report signature verified, certificate chain validated; optional `--hwmodel` and `--gpus` | NVIDIA's service accepted the GPU's measurements and configuration | that the GPU executed your workload |
|
|
37
|
+
| `nvidia.freshness` | the verifier token's `iat` is within 15 minutes of the bundle's `created_at` | the token belongs to this attestation session | anything if the VM clock is wrong (the check then fails, which is the safe direction) |
|
|
38
|
+
|
|
39
|
+
On a multi-GPU node in NVIDIA Protected PCIe mode, the GPUs are attested as a set through the
|
|
40
|
+
same flow (`nvidia.mode = multi-gpu-ppcie`). NVSwitch attestation is not part of the bundle.
|
|
41
|
+
|
|
42
|
+
## The gap this tool does not close
|
|
43
|
+
|
|
44
|
+
Both proofs are bound to a description of the workload. Neither proof says that the
|
|
45
|
+
described image or model was what the GPU computed on. Closing that gap requires a measured
|
|
46
|
+
launch: a component inside the VM that measures the container image and the model before
|
|
47
|
+
starting them and extends a TDX runtime measurement (`RTMR`) with the result, so that the
|
|
48
|
+
quote itself carries the measurement. The Confidential Containers project (Kata + Trustee)
|
|
49
|
+
and similar stacks do this. `voltage-verify` stops one step earlier on purpose, and says so.
|