zcc-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.
- zcc_verify-0.1.0/LICENSE +22 -0
- zcc_verify-0.1.0/PKG-INFO +179 -0
- zcc_verify-0.1.0/README.md +151 -0
- zcc_verify-0.1.0/pyproject.toml +52 -0
- zcc_verify-0.1.0/setup.cfg +4 -0
- zcc_verify-0.1.0/tests/test_verify.py +194 -0
- zcc_verify-0.1.0/zcc_verify/__init__.py +416 -0
- zcc_verify-0.1.0/zcc_verify/__main__.py +4 -0
- zcc_verify-0.1.0/zcc_verify.egg-info/PKG-INFO +179 -0
- zcc_verify-0.1.0/zcc_verify.egg-info/SOURCES.txt +11 -0
- zcc_verify-0.1.0/zcc_verify.egg-info/dependency_links.txt +1 -0
- zcc_verify-0.1.0/zcc_verify.egg-info/entry_points.txt +2 -0
- zcc_verify-0.1.0/zcc_verify.egg-info/top_level.txt +1 -0
zcc_verify-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ZKSF.org (Zero Kelvin Simulation Foundry)
|
|
4
|
+
Copyright (c) 2026 Digital Venture Labs LLC
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zcc-verify
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Independent consistency checker for ZCC-v0.1 / ZHF-v0.1 quantum simulation accuracy certificates
|
|
5
|
+
Author-email: ZKSF <info@zksf.org>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zksf.org
|
|
8
|
+
Project-URL: Source, https://github.com/official-dvl/zksf-zcc-verify
|
|
9
|
+
Project-URL: Issues, https://github.com/official-dvl/zksf-zcc-verify/issues
|
|
10
|
+
Project-URL: Specification, https://doi.org/10.5281/zenodo.21851381
|
|
11
|
+
Project-URL: Protocol, https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md
|
|
12
|
+
Project-URL: SDK, https://pypi.org/project/qsim-sdk/
|
|
13
|
+
Keywords: quantum,quantum computing,quantum circuit simulator,certification,verification,error bounds,reproducibility,ZCC,ZHF
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# zcc-verify
|
|
30
|
+
|
|
31
|
+
[](https://github.com/official-dvl/zksf-zcc-verify/actions/workflows/ci.yml)
|
|
32
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
33
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
[](https://doi.org/10.5281/zenodo.21851381)
|
|
36
|
+
|
|
37
|
+
Independent consistency checker for **ZCC-v0.1** and **ZHF-v0.1** quantum simulation
|
|
38
|
+
accuracy certificates.
|
|
39
|
+
|
|
40
|
+
No dependencies. Python 3.10+.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install zcc-verify
|
|
44
|
+
zcc-verify fe529e21d7404ff3
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
certificate fe529e21d7404ff3 (ZCC-v0.1)
|
|
49
|
+
[ok ] required fields present
|
|
50
|
+
[ok ] protocol recognised: ZCC-v0.1
|
|
51
|
+
[ok ] carries no account or circuit data
|
|
52
|
+
[ok ] circuit identified by SHA-256
|
|
53
|
+
[ok ] issued-at timestamp parses: 2026-07-09T13:20:03+00:00
|
|
54
|
+
[ok ] shot count: 512
|
|
55
|
+
[ok ] measured outcomes: 2 outcomes, 512 shots shown
|
|
56
|
+
[ok ] bound is a probability: 2.1073424255447017e-08
|
|
57
|
+
[ok ] bound recomputed from the measurement: sqrt(2 x 2.22045e-16) = 2.10734e-08
|
|
58
|
+
[ok ] converged flag consistent with the bound: True
|
|
59
|
+
consistent: the stated bound follows from the stated measurement
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Exit status is 0 when every check passes and 1 when any fails, so it drops into CI.
|
|
63
|
+
|
|
64
|
+
## Why this exists
|
|
65
|
+
|
|
66
|
+
Classical simulation of quantum circuits is exact only in a narrow regime. Exact
|
|
67
|
+
statevector methods terminate near 30 to 32 qubits, because state size grows as `2^n`.
|
|
68
|
+
Beyond that every practical method is approximate: tensor networks truncate the bond
|
|
69
|
+
dimension, Pauli propagation truncates operator weight, and real hardware substitutes
|
|
70
|
+
device noise for the ideal distribution.
|
|
71
|
+
|
|
72
|
+
An approximate result without an error statement is not a measurement, it is an
|
|
73
|
+
assertion. **ZCC-v0.1** and **ZHF-v0.1** are small versioned protocols that attach a
|
|
74
|
+
machine-checkable accuracy statement to a result. This tool is the checker: it takes a
|
|
75
|
+
certificate and confirms the claim it makes follows from the measurement it reports.
|
|
76
|
+
|
|
77
|
+
The protocols are specified in a citable paper:
|
|
78
|
+
|
|
79
|
+
> Reporting the Accuracy of Approximate Quantum Circuit Simulation: A Machine-Checkable
|
|
80
|
+
> Certificate Format. [doi.org/10.5281/zenodo.21851381](https://doi.org/10.5281/zenodo.21851381)
|
|
81
|
+
|
|
82
|
+
## What this establishes
|
|
83
|
+
|
|
84
|
+
The load-bearing check recomputes the declared bound from the measured quantity the
|
|
85
|
+
certificate itself reports, and requires the two to agree:
|
|
86
|
+
|
|
87
|
+
| Method | Reported quantity | Bound must equal |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| Matrix product state | discarded SVD weight `eps` | `min(1, sqrt(2 * eps))` |
|
|
90
|
+
| Pauli propagation | discarded coefficient mass | the mass itself (additive) |
|
|
91
|
+
| Exact / stabilizer | nothing discarded | zero |
|
|
92
|
+
| Hardware (ZHF-v0.1) | Hellinger fidelity vs. the exact ideal | within `[0, 1]`, or explicitly declined |
|
|
93
|
+
|
|
94
|
+
It also checks that the record is well formed, that the `converged` flag agrees with the
|
|
95
|
+
bound (the two methods use different thresholds), that outcome counts do not exceed the
|
|
96
|
+
shot count, and that no account data or circuit source is present.
|
|
97
|
+
|
|
98
|
+
A certificate whose stated bound does not follow from its own stated inputs fails here,
|
|
99
|
+
whoever issued it.
|
|
100
|
+
|
|
101
|
+
## What this does not establish
|
|
102
|
+
|
|
103
|
+
**It does not establish that the measurement was honest.** The discarded weight in a
|
|
104
|
+
tensor-network certificate, and the coefficient mass in a Pauli one, are produced by
|
|
105
|
+
whoever ran the simulation. No arithmetic on the record can confirm that the number
|
|
106
|
+
reported is the number that was measured.
|
|
107
|
+
|
|
108
|
+
Verifying a certificate is not the same as trusting the issuer. What it gives you is
|
|
109
|
+
narrower and still worth having: the claim is well formed, self-consistent, and stated
|
|
110
|
+
in a form somebody else can check.
|
|
111
|
+
|
|
112
|
+
## Use as a library
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from zcc_verify import fetch, verify
|
|
116
|
+
|
|
117
|
+
report = verify(fetch("df1d4c698a954051"))
|
|
118
|
+
print(report.ok) # True
|
|
119
|
+
print([c.name for c in report.failures]) # []
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`fetch()` reads the public record at `https://api.zksf.org/certify/<id>/json`. It needs
|
|
123
|
+
no authentication and no account. `verify()` takes a plain dict, so a record from any
|
|
124
|
+
source, including a local file or a different issuer, can be checked:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
zcc-verify ./certificate.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Four live certificates to try, covering every accuracy regime the protocols describe:
|
|
131
|
+
|
|
132
|
+
| Certificate | Run |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `d904e28af0b441e0` | 3-qubit GHZ, exact stabilizer simulation |
|
|
135
|
+
| `fe529e21d7404ff3` | 12-qubit GHZ, tensor network, measured bound of 2.11e-08 |
|
|
136
|
+
| `5b8b2c4309d44d41` | 192-qubit GHZ, Pauli propagation |
|
|
137
|
+
| `df1d4c698a954051` | Bell state on IonQ Forte-1 hardware, 0.977 fidelity |
|
|
138
|
+
|
|
139
|
+
## On the limits of the bound
|
|
140
|
+
|
|
141
|
+
The certified bound is an empirical result rather than a theorem. It held across 334
|
|
142
|
+
runs at sizes where the exact answer is computable, 290 of them constructed specifically
|
|
143
|
+
to break it, approaching at closest 49 percent of its value. Above 20 qubits it cannot
|
|
144
|
+
be checked by direct comparison and no such evidence exists. Where a hard ceiling is
|
|
145
|
+
required, use an exact or stabilizer engine.
|
|
146
|
+
|
|
147
|
+
The paper is explicit about the case in which the motivating derivation does not extend:
|
|
148
|
+
in deep sequential circuits the accumulated truncation weight has been measured
|
|
149
|
+
understating the true infidelity by up to a factor of seven. It also shows, by explicit
|
|
150
|
+
counterexample, that a natural tightening of the bound is unsound.
|
|
151
|
+
|
|
152
|
+
## Where these certificates come from
|
|
153
|
+
|
|
154
|
+
[ZKSF (Zero Kelvin Simulation Foundry)](https://zksf.org) runs quantum circuits on
|
|
155
|
+
classical simulators, GPU accelerators, or real quantum processors, and attaches one of
|
|
156
|
+
these accuracy statements to every approximate result.
|
|
157
|
+
|
|
158
|
+
- **Python SDK** — [`qsim-sdk`](https://pypi.org/project/qsim-sdk/) on PyPI, source at
|
|
159
|
+
[official-dvl/zksf](https://github.com/official-dvl/zksf), DOI
|
|
160
|
+
[10.5281/zenodo.21836619](https://doi.org/10.5281/zenodo.21836619). Accepts Qiskit
|
|
161
|
+
circuits directly, and Cirq, PennyLane, pyQuil or Braket circuits via an optional
|
|
162
|
+
transpiler.
|
|
163
|
+
- **Try it without an account** — the
|
|
164
|
+
[Colab quickstart](https://colab.research.google.com/github/official-dvl/zksf/blob/main/examples/quickstart.ipynb)
|
|
165
|
+
reads real completed certificates from the public API before it asks you for anything.
|
|
166
|
+
- **Android app** — submit a circuit and read the result from a phone, including runs on
|
|
167
|
+
real quantum hardware:
|
|
168
|
+
[Google Play](https://play.google.com/store/apps/details?id=com.quantumcomputing.app).
|
|
169
|
+
- **Protocol reference** —
|
|
170
|
+
[CERTIFICATION.md](https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md)
|
|
171
|
+
- **Documentation** — [zksf.org/docs](https://zksf.org/docs)
|
|
172
|
+
|
|
173
|
+
This checker is deliberately independent of all of the above: it has no dependency on
|
|
174
|
+
the SDK, needs no account, and will check a certificate issued by anyone who emits the
|
|
175
|
+
format.
|
|
176
|
+
|
|
177
|
+
## Licence
|
|
178
|
+
|
|
179
|
+
MIT.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# zcc-verify
|
|
2
|
+
|
|
3
|
+
[](https://github.com/official-dvl/zksf-zcc-verify/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
5
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://doi.org/10.5281/zenodo.21851381)
|
|
8
|
+
|
|
9
|
+
Independent consistency checker for **ZCC-v0.1** and **ZHF-v0.1** quantum simulation
|
|
10
|
+
accuracy certificates.
|
|
11
|
+
|
|
12
|
+
No dependencies. Python 3.10+.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install zcc-verify
|
|
16
|
+
zcc-verify fe529e21d7404ff3
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
certificate fe529e21d7404ff3 (ZCC-v0.1)
|
|
21
|
+
[ok ] required fields present
|
|
22
|
+
[ok ] protocol recognised: ZCC-v0.1
|
|
23
|
+
[ok ] carries no account or circuit data
|
|
24
|
+
[ok ] circuit identified by SHA-256
|
|
25
|
+
[ok ] issued-at timestamp parses: 2026-07-09T13:20:03+00:00
|
|
26
|
+
[ok ] shot count: 512
|
|
27
|
+
[ok ] measured outcomes: 2 outcomes, 512 shots shown
|
|
28
|
+
[ok ] bound is a probability: 2.1073424255447017e-08
|
|
29
|
+
[ok ] bound recomputed from the measurement: sqrt(2 x 2.22045e-16) = 2.10734e-08
|
|
30
|
+
[ok ] converged flag consistent with the bound: True
|
|
31
|
+
consistent: the stated bound follows from the stated measurement
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Exit status is 0 when every check passes and 1 when any fails, so it drops into CI.
|
|
35
|
+
|
|
36
|
+
## Why this exists
|
|
37
|
+
|
|
38
|
+
Classical simulation of quantum circuits is exact only in a narrow regime. Exact
|
|
39
|
+
statevector methods terminate near 30 to 32 qubits, because state size grows as `2^n`.
|
|
40
|
+
Beyond that every practical method is approximate: tensor networks truncate the bond
|
|
41
|
+
dimension, Pauli propagation truncates operator weight, and real hardware substitutes
|
|
42
|
+
device noise for the ideal distribution.
|
|
43
|
+
|
|
44
|
+
An approximate result without an error statement is not a measurement, it is an
|
|
45
|
+
assertion. **ZCC-v0.1** and **ZHF-v0.1** are small versioned protocols that attach a
|
|
46
|
+
machine-checkable accuracy statement to a result. This tool is the checker: it takes a
|
|
47
|
+
certificate and confirms the claim it makes follows from the measurement it reports.
|
|
48
|
+
|
|
49
|
+
The protocols are specified in a citable paper:
|
|
50
|
+
|
|
51
|
+
> Reporting the Accuracy of Approximate Quantum Circuit Simulation: A Machine-Checkable
|
|
52
|
+
> Certificate Format. [doi.org/10.5281/zenodo.21851381](https://doi.org/10.5281/zenodo.21851381)
|
|
53
|
+
|
|
54
|
+
## What this establishes
|
|
55
|
+
|
|
56
|
+
The load-bearing check recomputes the declared bound from the measured quantity the
|
|
57
|
+
certificate itself reports, and requires the two to agree:
|
|
58
|
+
|
|
59
|
+
| Method | Reported quantity | Bound must equal |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| Matrix product state | discarded SVD weight `eps` | `min(1, sqrt(2 * eps))` |
|
|
62
|
+
| Pauli propagation | discarded coefficient mass | the mass itself (additive) |
|
|
63
|
+
| Exact / stabilizer | nothing discarded | zero |
|
|
64
|
+
| Hardware (ZHF-v0.1) | Hellinger fidelity vs. the exact ideal | within `[0, 1]`, or explicitly declined |
|
|
65
|
+
|
|
66
|
+
It also checks that the record is well formed, that the `converged` flag agrees with the
|
|
67
|
+
bound (the two methods use different thresholds), that outcome counts do not exceed the
|
|
68
|
+
shot count, and that no account data or circuit source is present.
|
|
69
|
+
|
|
70
|
+
A certificate whose stated bound does not follow from its own stated inputs fails here,
|
|
71
|
+
whoever issued it.
|
|
72
|
+
|
|
73
|
+
## What this does not establish
|
|
74
|
+
|
|
75
|
+
**It does not establish that the measurement was honest.** The discarded weight in a
|
|
76
|
+
tensor-network certificate, and the coefficient mass in a Pauli one, are produced by
|
|
77
|
+
whoever ran the simulation. No arithmetic on the record can confirm that the number
|
|
78
|
+
reported is the number that was measured.
|
|
79
|
+
|
|
80
|
+
Verifying a certificate is not the same as trusting the issuer. What it gives you is
|
|
81
|
+
narrower and still worth having: the claim is well formed, self-consistent, and stated
|
|
82
|
+
in a form somebody else can check.
|
|
83
|
+
|
|
84
|
+
## Use as a library
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from zcc_verify import fetch, verify
|
|
88
|
+
|
|
89
|
+
report = verify(fetch("df1d4c698a954051"))
|
|
90
|
+
print(report.ok) # True
|
|
91
|
+
print([c.name for c in report.failures]) # []
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`fetch()` reads the public record at `https://api.zksf.org/certify/<id>/json`. It needs
|
|
95
|
+
no authentication and no account. `verify()` takes a plain dict, so a record from any
|
|
96
|
+
source, including a local file or a different issuer, can be checked:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
zcc-verify ./certificate.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Four live certificates to try, covering every accuracy regime the protocols describe:
|
|
103
|
+
|
|
104
|
+
| Certificate | Run |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `d904e28af0b441e0` | 3-qubit GHZ, exact stabilizer simulation |
|
|
107
|
+
| `fe529e21d7404ff3` | 12-qubit GHZ, tensor network, measured bound of 2.11e-08 |
|
|
108
|
+
| `5b8b2c4309d44d41` | 192-qubit GHZ, Pauli propagation |
|
|
109
|
+
| `df1d4c698a954051` | Bell state on IonQ Forte-1 hardware, 0.977 fidelity |
|
|
110
|
+
|
|
111
|
+
## On the limits of the bound
|
|
112
|
+
|
|
113
|
+
The certified bound is an empirical result rather than a theorem. It held across 334
|
|
114
|
+
runs at sizes where the exact answer is computable, 290 of them constructed specifically
|
|
115
|
+
to break it, approaching at closest 49 percent of its value. Above 20 qubits it cannot
|
|
116
|
+
be checked by direct comparison and no such evidence exists. Where a hard ceiling is
|
|
117
|
+
required, use an exact or stabilizer engine.
|
|
118
|
+
|
|
119
|
+
The paper is explicit about the case in which the motivating derivation does not extend:
|
|
120
|
+
in deep sequential circuits the accumulated truncation weight has been measured
|
|
121
|
+
understating the true infidelity by up to a factor of seven. It also shows, by explicit
|
|
122
|
+
counterexample, that a natural tightening of the bound is unsound.
|
|
123
|
+
|
|
124
|
+
## Where these certificates come from
|
|
125
|
+
|
|
126
|
+
[ZKSF (Zero Kelvin Simulation Foundry)](https://zksf.org) runs quantum circuits on
|
|
127
|
+
classical simulators, GPU accelerators, or real quantum processors, and attaches one of
|
|
128
|
+
these accuracy statements to every approximate result.
|
|
129
|
+
|
|
130
|
+
- **Python SDK** — [`qsim-sdk`](https://pypi.org/project/qsim-sdk/) on PyPI, source at
|
|
131
|
+
[official-dvl/zksf](https://github.com/official-dvl/zksf), DOI
|
|
132
|
+
[10.5281/zenodo.21836619](https://doi.org/10.5281/zenodo.21836619). Accepts Qiskit
|
|
133
|
+
circuits directly, and Cirq, PennyLane, pyQuil or Braket circuits via an optional
|
|
134
|
+
transpiler.
|
|
135
|
+
- **Try it without an account** — the
|
|
136
|
+
[Colab quickstart](https://colab.research.google.com/github/official-dvl/zksf/blob/main/examples/quickstart.ipynb)
|
|
137
|
+
reads real completed certificates from the public API before it asks you for anything.
|
|
138
|
+
- **Android app** — submit a circuit and read the result from a phone, including runs on
|
|
139
|
+
real quantum hardware:
|
|
140
|
+
[Google Play](https://play.google.com/store/apps/details?id=com.quantumcomputing.app).
|
|
141
|
+
- **Protocol reference** —
|
|
142
|
+
[CERTIFICATION.md](https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md)
|
|
143
|
+
- **Documentation** — [zksf.org/docs](https://zksf.org/docs)
|
|
144
|
+
|
|
145
|
+
This checker is deliberately independent of all of the above: it has no dependency on
|
|
146
|
+
the SDK, needs no account, and will check a certificate issued by anyone who emits the
|
|
147
|
+
format.
|
|
148
|
+
|
|
149
|
+
## Licence
|
|
150
|
+
|
|
151
|
+
MIT.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zcc-verify"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Independent consistency checker for ZCC-v0.1 / ZHF-v0.1 quantum simulation accuracy certificates"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "ZKSF", email = "info@zksf.org" }]
|
|
9
|
+
keywords = [
|
|
10
|
+
"quantum",
|
|
11
|
+
"quantum computing",
|
|
12
|
+
"quantum circuit simulator",
|
|
13
|
+
"certification",
|
|
14
|
+
"verification",
|
|
15
|
+
"error bounds",
|
|
16
|
+
"reproducibility",
|
|
17
|
+
"ZCC",
|
|
18
|
+
"ZHF",
|
|
19
|
+
]
|
|
20
|
+
# No dependencies, deliberately. A validator that requires a dependency tree to
|
|
21
|
+
# run is one a sceptical third party will not run.
|
|
22
|
+
dependencies = []
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 4 - Beta",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"License :: OSI Approved :: MIT License",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
zcc-verify = "zcc_verify:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://zksf.org"
|
|
41
|
+
Source = "https://github.com/official-dvl/zksf-zcc-verify"
|
|
42
|
+
Issues = "https://github.com/official-dvl/zksf-zcc-verify/issues"
|
|
43
|
+
Specification = "https://doi.org/10.5281/zenodo.21851381"
|
|
44
|
+
Protocol = "https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md"
|
|
45
|
+
SDK = "https://pypi.org/project/qsim-sdk/"
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["setuptools>=68"]
|
|
49
|
+
build-backend = "setuptools.build_meta"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
include = ["zcc_verify*"]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""A checker that passes everything is worth nothing, so most of these tests
|
|
2
|
+
tamper with a valid record and assert that the tampering is caught."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from zcc_verify import verify
|
|
10
|
+
|
|
11
|
+
# A real ZCC-v0.1 certificate: 12-qubit GHZ on the MPS engine with a measured
|
|
12
|
+
# discarded-weight bound. Fetched from api.zksf.org/certify/fe529e21d7404ff3/json.
|
|
13
|
+
MPS = {
|
|
14
|
+
"cert_id": "fe529e21d7404ff3",
|
|
15
|
+
"engine": "mps.quimb.cpu",
|
|
16
|
+
"method": "MPS (quimb), rigorous discarded-weight bound",
|
|
17
|
+
"shots": 512,
|
|
18
|
+
"circuit_sha256": "0c1e6d9a6f4b5f2e8a3d7c5b1e9f4a2d6c8b0e3f7a1d5c9b2e6f0a4d8c3b7e1f",
|
|
19
|
+
"created_at": "2026-07-09T13:20:03+00:00",
|
|
20
|
+
"verify_url": "https://api.zksf.org/certify/fe529e21d7404ff3",
|
|
21
|
+
"top_outcomes": [["000000000000", 268], ["111111111111", 244]],
|
|
22
|
+
"protocol": "ZCC-v0.1",
|
|
23
|
+
"certificate_type": "Simulation Accuracy",
|
|
24
|
+
"exact": False,
|
|
25
|
+
"truncation_weight": 2.220446049250313e-16,
|
|
26
|
+
"error_bound": 2.1073424255447017e-08,
|
|
27
|
+
"converged": True,
|
|
28
|
+
"certified": True,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# A real ZHF-v0.1 certificate: Bell state on IonQ Forte-1 hardware.
|
|
32
|
+
HARDWARE = {
|
|
33
|
+
"cert_id": "df1d4c698a954051",
|
|
34
|
+
"engine": "qpu.ionq",
|
|
35
|
+
"method": "quantum hardware (IonQ Forte-1 (trapped ion))",
|
|
36
|
+
"shots": 100,
|
|
37
|
+
"circuit_sha256": "3b3e9bc07d222a2ef79e6f3f4cb0f34332e355d68c3b5e194171e1ba13c80447",
|
|
38
|
+
"created_at": "2026-07-09T14:29:29+00:00",
|
|
39
|
+
"verify_url": "https://api.zksf.org/certify/df1d4c698a954051",
|
|
40
|
+
"top_outcomes": [["00", 54], ["11", 44], ["01", 2]],
|
|
41
|
+
"protocol": "ZHF-v0.1",
|
|
42
|
+
"certificate_type": "Hardware Fidelity",
|
|
43
|
+
"device": "Forte-1",
|
|
44
|
+
"fidelity": 0.977442,
|
|
45
|
+
"fidelity_mode": "direct",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
PAULI = {
|
|
49
|
+
"cert_id": "5b8b2c4309d44d41",
|
|
50
|
+
"engine": "pauli.cpu",
|
|
51
|
+
"method": "Pauli propagation (Heisenberg picture)",
|
|
52
|
+
"shots": 1000,
|
|
53
|
+
"circuit_sha256": "a" * 64,
|
|
54
|
+
"created_at": "2026-07-12T20:58:18+00:00",
|
|
55
|
+
"verify_url": "https://api.zksf.org/certify/5b8b2c4309d44d41",
|
|
56
|
+
"protocol": "ZCC-v0.1",
|
|
57
|
+
"certificate_type": "Simulation Accuracy",
|
|
58
|
+
"exact": False,
|
|
59
|
+
"truncated_coefficient_mass": 0.0,
|
|
60
|
+
"error_bound": 0.0,
|
|
61
|
+
"converged": True,
|
|
62
|
+
"certified": True,
|
|
63
|
+
"expectation": 1.0,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def failed(rec) -> list[str]:
|
|
68
|
+
return [c.name for c in verify(rec).failures]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def tampered(base: dict, **changes) -> dict:
|
|
72
|
+
rec = copy.deepcopy(base)
|
|
73
|
+
rec.update(changes)
|
|
74
|
+
return rec
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# --------------------------------------------------------------- valid records
|
|
78
|
+
|
|
79
|
+
@pytest.mark.parametrize("rec", [MPS, HARDWARE, PAULI], ids=["mps", "hardware", "pauli"])
|
|
80
|
+
def test_real_certificates_are_consistent(rec):
|
|
81
|
+
assert verify(rec).ok, failed(rec)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_exact_run_with_no_bound_is_consistent():
|
|
85
|
+
rec = tampered(MPS, exact=True, truncation_weight=0.0, error_bound=0.0)
|
|
86
|
+
assert verify(rec).ok, failed(rec)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_hardware_may_decline_to_claim_a_fidelity():
|
|
90
|
+
"""Too large to simulate classically is an honest answer, provided no
|
|
91
|
+
figure is invented to fill the gap."""
|
|
92
|
+
rec = tampered(HARDWARE, fidelity_mode="unavailable", fidelity=None)
|
|
93
|
+
assert verify(rec).ok, failed(rec)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# ------------------------------------------------------------ caught tampering
|
|
97
|
+
|
|
98
|
+
def test_bound_that_does_not_follow_from_the_weight_is_rejected():
|
|
99
|
+
"""The load-bearing check: a bound quietly shrunk to look better."""
|
|
100
|
+
rec = tampered(MPS, error_bound=1e-12)
|
|
101
|
+
assert "bound recomputed from the measurement" in failed(rec)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_weight_altered_without_the_bound_is_rejected():
|
|
105
|
+
rec = tampered(MPS, truncation_weight=1e-4)
|
|
106
|
+
assert "bound recomputed from the measurement" in failed(rec)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_pauli_bound_must_equal_the_discarded_mass():
|
|
110
|
+
rec = tampered(PAULI, truncated_coefficient_mass=1e-3, error_bound=1e-9)
|
|
111
|
+
assert "bound recomputed from the measurement" in failed(rec)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_exact_claim_with_a_nonzero_bound_is_rejected():
|
|
115
|
+
rec = tampered(MPS, exact=True)
|
|
116
|
+
assert "exact run declares no approximation error" in failed(rec)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_bound_above_one_is_rejected():
|
|
120
|
+
"""A bound on a probability cannot exceed 1: two distributions differ by
|
|
121
|
+
at most that much."""
|
|
122
|
+
rec = tampered(MPS, error_bound=1.5)
|
|
123
|
+
assert "bound is a probability" in failed(rec)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_converged_flag_is_checked_against_the_bound():
|
|
127
|
+
rec = tampered(MPS, truncation_weight=0.5, error_bound=1.0, converged=True)
|
|
128
|
+
assert "converged flag consistent with the bound" in failed(rec)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_pauli_uses_its_own_convergence_threshold():
|
|
132
|
+
"""1e-8 is converged for MPS but not for Pauli propagation, so a checker
|
|
133
|
+
applying one threshold to both would miss this."""
|
|
134
|
+
rec = tampered(PAULI, truncated_coefficient_mass=1e-8, error_bound=1e-8, converged=True)
|
|
135
|
+
assert "converged flag consistent with the bound" in failed(rec)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_account_data_is_rejected():
|
|
139
|
+
rec = tampered(MPS, user_sub="us-east-1:9f3c", charged_micro=4200)
|
|
140
|
+
assert "carries no account or circuit data" in failed(rec)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_embedded_circuit_is_rejected():
|
|
144
|
+
"""The circuit is the user's, and a certificate identifies it by hash."""
|
|
145
|
+
rec = tampered(MPS, qasm2="OPENQASM 2.0; qreg q[12];")
|
|
146
|
+
assert "carries no account or circuit data" in failed(rec)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_bad_digest_is_rejected():
|
|
150
|
+
assert "circuit identified by SHA-256" in failed(tampered(MPS, circuit_sha256="deadbeef"))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_unknown_protocol_is_not_waved_through():
|
|
154
|
+
"""A later revision may carry invariants this version cannot check, so it
|
|
155
|
+
is reported rather than assumed sound."""
|
|
156
|
+
assert "protocol recognised" in failed(tampered(MPS, protocol="ZCC-v9.9"))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_missing_required_field_is_rejected():
|
|
160
|
+
rec = copy.deepcopy(MPS)
|
|
161
|
+
del rec["verify_url"]
|
|
162
|
+
assert "required fields present" in failed(rec)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_unparseable_timestamp_is_rejected():
|
|
166
|
+
assert "issued-at timestamp parses" in failed(tampered(MPS, created_at="last Tuesday"))
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_fidelity_outside_the_unit_interval_is_rejected():
|
|
170
|
+
assert "fidelity within [0, 1]" in failed(tampered(HARDWARE, fidelity=1.4))
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_fidelity_claimed_without_a_reference_is_rejected():
|
|
174
|
+
"""Declaring verification unavailable and then reporting a number anyway
|
|
175
|
+
is the specific dishonesty ZHF-v0.1 exists to prevent."""
|
|
176
|
+
rec = tampered(HARDWARE, fidelity_mode="unavailable", fidelity=0.99)
|
|
177
|
+
assert "no fidelity claimed without a reference" in failed(rec)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_unknown_fidelity_mode_is_rejected():
|
|
181
|
+
assert "fidelity mode declared" in failed(tampered(HARDWARE, fidelity_mode="trust me"))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_outcomes_exceeding_the_shot_count_are_rejected():
|
|
185
|
+
rec = tampered(HARDWARE, top_outcomes=[["00", 900], ["11", 400]])
|
|
186
|
+
assert "measured outcomes" in failed(rec)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_non_bitstring_outcome_labels_are_rejected():
|
|
190
|
+
assert "measured outcomes" in failed(tampered(HARDWARE, top_outcomes=[["yes", 54]]))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_negative_shot_count_is_rejected():
|
|
194
|
+
assert "shot count" in failed(tampered(MPS, shots=-1))
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"""Independent checker for ZCC-v0.1 / ZHF-v0.1 accuracy certificates.
|
|
2
|
+
|
|
3
|
+
from zcc_verify import fetch, verify
|
|
4
|
+
print(verify(fetch("fe529e21d7404ff3")))
|
|
5
|
+
|
|
6
|
+
What this establishes, and what it does not, stated plainly because the
|
|
7
|
+
distinction is the whole point of the format:
|
|
8
|
+
|
|
9
|
+
**It checks that a certificate is well formed and internally consistent.** The
|
|
10
|
+
declared error bound is recomputed from the measured quantity the certificate
|
|
11
|
+
reports, and the two must agree. A certificate whose stated bound does not
|
|
12
|
+
follow from its own stated inputs fails here, whoever issued it.
|
|
13
|
+
|
|
14
|
+
**It does not establish that the measurement was honest.** The discarded weight
|
|
15
|
+
in an MPS certificate, or the coefficient mass in a Pauli one, is produced by
|
|
16
|
+
whoever ran the simulation. No amount of arithmetic on the record can confirm
|
|
17
|
+
that the number reported is the number that was measured. Verifying a
|
|
18
|
+
certificate is not the same as trusting the issuer.
|
|
19
|
+
|
|
20
|
+
The specification is published at
|
|
21
|
+
https://doi.org/10.5281/zenodo.21851381, and the protocol reference is
|
|
22
|
+
https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md.
|
|
23
|
+
|
|
24
|
+
Standard library only, on purpose: a validator that a third party has to install
|
|
25
|
+
a dependency tree to run is one they will not run. Vendor this file if it helps.
|
|
26
|
+
"""
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import math
|
|
31
|
+
import re
|
|
32
|
+
import urllib.request
|
|
33
|
+
from dataclasses import dataclass, field
|
|
34
|
+
from datetime import datetime
|
|
35
|
+
|
|
36
|
+
__version__ = "0.1.0"
|
|
37
|
+
|
|
38
|
+
DEFAULT_BASE_URL = "https://api.zksf.org"
|
|
39
|
+
|
|
40
|
+
# Protocols this checker understands. An unknown protocol is reported rather
|
|
41
|
+
# than assumed to be fine: a future ZCC-v0.2 may carry invariants this version
|
|
42
|
+
# knows nothing about, and silently passing it would be the wrong answer.
|
|
43
|
+
KNOWN_PROTOCOLS = {"ZCC-v0.1", "ZHF-v0.1", "ZCC-Estimate-v0.1"}
|
|
44
|
+
|
|
45
|
+
REQUIRED_FIELDS = (
|
|
46
|
+
"cert_id",
|
|
47
|
+
"protocol",
|
|
48
|
+
"certificate_type",
|
|
49
|
+
"engine",
|
|
50
|
+
"method",
|
|
51
|
+
"circuit_sha256",
|
|
52
|
+
"created_at",
|
|
53
|
+
"verify_url",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Fields that must never appear. A certificate is meant to be publishable
|
|
57
|
+
# without exposing the account that produced it or the circuit that was run,
|
|
58
|
+
# so a third party should be able to confirm that for themselves.
|
|
59
|
+
FORBIDDEN_FIELDS = (
|
|
60
|
+
"user_sub",
|
|
61
|
+
"charged_micro",
|
|
62
|
+
"qasm2",
|
|
63
|
+
"email",
|
|
64
|
+
"balance_usd",
|
|
65
|
+
"braket_task_arn",
|
|
66
|
+
"runpod_job_id",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
PASS, FAIL, SKIP = "pass", "fail", "skip"
|
|
70
|
+
|
|
71
|
+
_SHA256_RE = re.compile(r"\A[0-9a-f]{64}\Z")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass(frozen=True)
|
|
75
|
+
class Check:
|
|
76
|
+
name: str
|
|
77
|
+
status: str
|
|
78
|
+
detail: str = ""
|
|
79
|
+
|
|
80
|
+
def __str__(self) -> str:
|
|
81
|
+
mark = {PASS: "ok ", FAIL: "FAIL", SKIP: " - "}[self.status]
|
|
82
|
+
return f"[{mark}] {self.name}" + (f": {self.detail}" if self.detail else "")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class Report:
|
|
87
|
+
cert_id: str
|
|
88
|
+
protocol: str
|
|
89
|
+
checks: list[Check] = field(default_factory=list)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def ok(self) -> bool:
|
|
93
|
+
return all(c.status != FAIL for c in self.checks)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def failures(self) -> list[Check]:
|
|
97
|
+
return [c for c in self.checks if c.status == FAIL]
|
|
98
|
+
|
|
99
|
+
def __str__(self) -> str:
|
|
100
|
+
head = f"certificate {self.cert_id} ({self.protocol})"
|
|
101
|
+
body = "\n".join(f" {c}" for c in self.checks)
|
|
102
|
+
tail = (
|
|
103
|
+
" consistent: the stated bound follows from the stated measurement"
|
|
104
|
+
if self.ok
|
|
105
|
+
else f" INCONSISTENT: {len(self.failures)} check(s) failed"
|
|
106
|
+
)
|
|
107
|
+
return f"{head}\n{body}\n{tail}"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def fetch(cert_id: str, base_url: str = DEFAULT_BASE_URL, timeout: float = 30.0) -> dict:
|
|
111
|
+
"""Read a public certificate record. No authentication, no account."""
|
|
112
|
+
url = f"{base_url.rstrip('/')}/certify/{cert_id}/json"
|
|
113
|
+
with urllib.request.urlopen(url, timeout=timeout) as resp: # noqa: S310
|
|
114
|
+
return json.load(resp)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _close(a: float, b: float) -> bool:
|
|
118
|
+
# Both sides come from the same float arithmetic, so exact agreement is the
|
|
119
|
+
# normal case; the tolerance is for records that made a round trip through
|
|
120
|
+
# a JSON encoder that shortened the representation.
|
|
121
|
+
return math.isclose(a, b, rel_tol=1e-9, abs_tol=1e-15)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def verify(rec: dict) -> Report:
|
|
125
|
+
"""Check a certificate record against the invariants of its own protocol."""
|
|
126
|
+
report = Report(
|
|
127
|
+
cert_id=str(rec.get("cert_id", "<missing>")),
|
|
128
|
+
protocol=str(rec.get("protocol", "<missing>")),
|
|
129
|
+
)
|
|
130
|
+
add = report.checks.append
|
|
131
|
+
|
|
132
|
+
missing = [f for f in REQUIRED_FIELDS if not rec.get(f)]
|
|
133
|
+
add(
|
|
134
|
+
Check("required fields present", FAIL, f"missing {', '.join(missing)}")
|
|
135
|
+
if missing
|
|
136
|
+
else Check("required fields present", PASS)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
protocol = rec.get("protocol")
|
|
140
|
+
add(
|
|
141
|
+
Check("protocol recognised", PASS, str(protocol))
|
|
142
|
+
if protocol in KNOWN_PROTOCOLS
|
|
143
|
+
else Check(
|
|
144
|
+
"protocol recognised",
|
|
145
|
+
FAIL,
|
|
146
|
+
f"{protocol!r} is not one of {sorted(KNOWN_PROTOCOLS)}; this checker "
|
|
147
|
+
f"cannot confirm invariants it does not know",
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
leaked = [f for f in FORBIDDEN_FIELDS if f in rec]
|
|
152
|
+
add(
|
|
153
|
+
Check("carries no account or circuit data", FAIL, f"found {', '.join(leaked)}")
|
|
154
|
+
if leaked
|
|
155
|
+
else Check("carries no account or circuit data", PASS)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
digest = rec.get("circuit_sha256", "")
|
|
159
|
+
add(
|
|
160
|
+
Check("circuit identified by SHA-256", PASS)
|
|
161
|
+
if _SHA256_RE.match(str(digest))
|
|
162
|
+
else Check("circuit identified by SHA-256", FAIL, f"not a SHA-256 digest: {digest!r}")
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
datetime.fromisoformat(str(rec.get("created_at", "")))
|
|
167
|
+
add(Check("issued-at timestamp parses", PASS, str(rec.get("created_at"))))
|
|
168
|
+
except ValueError:
|
|
169
|
+
add(Check("issued-at timestamp parses", FAIL, repr(rec.get("created_at"))))
|
|
170
|
+
|
|
171
|
+
shots = rec.get("shots")
|
|
172
|
+
if shots is None:
|
|
173
|
+
add(Check("shot count", SKIP, "no shots recorded (expectation-value run)"))
|
|
174
|
+
elif isinstance(shots, int) and shots > 0:
|
|
175
|
+
add(Check("shot count", PASS, str(shots)))
|
|
176
|
+
else:
|
|
177
|
+
add(Check("shot count", FAIL, f"not a positive integer: {shots!r}"))
|
|
178
|
+
|
|
179
|
+
_check_outcomes(rec, add)
|
|
180
|
+
|
|
181
|
+
if protocol == "ZHF-v0.1":
|
|
182
|
+
_check_hardware(rec, add)
|
|
183
|
+
else:
|
|
184
|
+
_check_simulation(rec, add)
|
|
185
|
+
|
|
186
|
+
return report
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _check_outcomes(rec: dict, add) -> None:
|
|
190
|
+
outcomes = rec.get("top_outcomes")
|
|
191
|
+
if not outcomes:
|
|
192
|
+
add(Check("measured outcomes", SKIP, "none recorded"))
|
|
193
|
+
return
|
|
194
|
+
try:
|
|
195
|
+
total = sum(int(count) for _, count in outcomes)
|
|
196
|
+
labels = [str(bits) for bits, _ in outcomes]
|
|
197
|
+
except (TypeError, ValueError):
|
|
198
|
+
add(Check("measured outcomes", FAIL, "malformed top_outcomes"))
|
|
199
|
+
return
|
|
200
|
+
if any(not set(b) <= {"0", "1"} for b in labels):
|
|
201
|
+
add(Check("measured outcomes", FAIL, "outcome labels are not bitstrings"))
|
|
202
|
+
return
|
|
203
|
+
shots = rec.get("shots")
|
|
204
|
+
# top_outcomes is a truncated list, so it can hold fewer shots than were
|
|
205
|
+
# taken, but never more.
|
|
206
|
+
if isinstance(shots, int) and total > shots:
|
|
207
|
+
add(
|
|
208
|
+
Check(
|
|
209
|
+
"measured outcomes",
|
|
210
|
+
FAIL,
|
|
211
|
+
f"reported outcomes total {total} shots but the run took {shots}",
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
return
|
|
215
|
+
add(Check("measured outcomes", PASS, f"{len(labels)} outcomes, {total} shots shown"))
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _check_hardware(rec: dict, add) -> None:
|
|
219
|
+
"""ZHF-v0.1: a fidelity against the exact ideal, or an explicit statement
|
|
220
|
+
that direct verification was not available. Never a silent absence."""
|
|
221
|
+
mode = rec.get("fidelity_mode")
|
|
222
|
+
if mode not in {"direct", "unavailable"}:
|
|
223
|
+
add(Check("fidelity mode declared", FAIL, f"unexpected mode {mode!r}"))
|
|
224
|
+
return
|
|
225
|
+
add(Check("fidelity mode declared", PASS, str(mode)))
|
|
226
|
+
|
|
227
|
+
fidelity = rec.get("fidelity")
|
|
228
|
+
if mode == "unavailable":
|
|
229
|
+
# The honest case: too large to verify classically. It must then decline
|
|
230
|
+
# to report a figure rather than produce one.
|
|
231
|
+
if fidelity is None:
|
|
232
|
+
add(Check("no fidelity claimed without a reference", PASS, str(rec.get("note", ""))[:80]))
|
|
233
|
+
else:
|
|
234
|
+
add(
|
|
235
|
+
Check(
|
|
236
|
+
"no fidelity claimed without a reference",
|
|
237
|
+
FAIL,
|
|
238
|
+
f"mode is 'unavailable' yet a fidelity of {fidelity} is reported",
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
return
|
|
242
|
+
|
|
243
|
+
if not isinstance(fidelity, (int, float)):
|
|
244
|
+
add(Check("fidelity is a number", FAIL, repr(fidelity)))
|
|
245
|
+
elif 0.0 <= fidelity <= 1.0:
|
|
246
|
+
add(Check("fidelity within [0, 1]", PASS, f"{fidelity}"))
|
|
247
|
+
else:
|
|
248
|
+
add(Check("fidelity within [0, 1]", FAIL, f"{fidelity} is outside the valid range"))
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _check_simulation(rec: dict, add) -> None:
|
|
252
|
+
"""ZCC-v0.1: recompute the declared bound from the measured quantity.
|
|
253
|
+
|
|
254
|
+
This is the check that does real work. Everything else confirms the record
|
|
255
|
+
is well formed; this one confirms the arithmetic it asserts.
|
|
256
|
+
"""
|
|
257
|
+
bound = rec.get("error_bound")
|
|
258
|
+
|
|
259
|
+
if rec.get("exact"):
|
|
260
|
+
# An exact engine approximates nothing, so a nonzero bound would
|
|
261
|
+
# contradict the claim being made.
|
|
262
|
+
if bound in (None, 0, 0.0):
|
|
263
|
+
add(Check("exact run declares no approximation error", PASS))
|
|
264
|
+
else:
|
|
265
|
+
add(
|
|
266
|
+
Check(
|
|
267
|
+
"exact run declares no approximation error",
|
|
268
|
+
FAIL,
|
|
269
|
+
f"claims to be exact yet reports an error bound of {bound}",
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
if rec.get("estimated"):
|
|
275
|
+
# ZCC-Estimate: an extrapolated value with an uncertainty. There is no
|
|
276
|
+
# closed-form relation to recompute, by construction.
|
|
277
|
+
add(
|
|
278
|
+
Check(
|
|
279
|
+
"bound recomputed from the measurement",
|
|
280
|
+
SKIP,
|
|
281
|
+
"extrapolated estimate: an uncertainty, not a derived bound",
|
|
282
|
+
)
|
|
283
|
+
)
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
if bound is None:
|
|
287
|
+
add(Check("bound recomputed from the measurement", SKIP, "no bound reported"))
|
|
288
|
+
elif not isinstance(bound, (int, float)) or not 0.0 <= bound <= 1.0:
|
|
289
|
+
add(
|
|
290
|
+
Check(
|
|
291
|
+
"bound is a probability",
|
|
292
|
+
FAIL,
|
|
293
|
+
f"{bound!r} is not a value in [0, 1]; a bound on an outcome "
|
|
294
|
+
f"probability cannot exceed 1",
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
return
|
|
298
|
+
else:
|
|
299
|
+
add(Check("bound is a probability", PASS, f"{bound}"))
|
|
300
|
+
|
|
301
|
+
weight = rec.get("truncation_weight")
|
|
302
|
+
mass = rec.get("truncated_coefficient_mass")
|
|
303
|
+
|
|
304
|
+
if weight is not None:
|
|
305
|
+
# MPS: bound = min(1, sqrt(2*eps)), eps read off the unnormalized state.
|
|
306
|
+
expected = min(1.0, math.sqrt(2.0 * float(weight)))
|
|
307
|
+
if bound is not None and _close(float(bound), expected):
|
|
308
|
+
add(
|
|
309
|
+
Check(
|
|
310
|
+
"bound recomputed from the measurement",
|
|
311
|
+
PASS,
|
|
312
|
+
f"sqrt(2 x {weight:g}) = {expected:g}",
|
|
313
|
+
)
|
|
314
|
+
)
|
|
315
|
+
else:
|
|
316
|
+
add(
|
|
317
|
+
Check(
|
|
318
|
+
"bound recomputed from the measurement",
|
|
319
|
+
FAIL,
|
|
320
|
+
f"discarded weight {weight!r} implies a bound of {expected:g}, "
|
|
321
|
+
f"but {bound!r} is reported",
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
_check_converged(rec, add, threshold=1e-6)
|
|
325
|
+
|
|
326
|
+
elif mass is not None:
|
|
327
|
+
# Pauli propagation: the bound is the discarded mass itself, by the
|
|
328
|
+
# triangle inequality over the truncated terms.
|
|
329
|
+
if bound is not None and _close(float(bound), float(mass)):
|
|
330
|
+
add(
|
|
331
|
+
Check(
|
|
332
|
+
"bound recomputed from the measurement",
|
|
333
|
+
PASS,
|
|
334
|
+
f"discarded coefficient mass {mass:g}, additive",
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
else:
|
|
338
|
+
add(
|
|
339
|
+
Check(
|
|
340
|
+
"bound recomputed from the measurement",
|
|
341
|
+
FAIL,
|
|
342
|
+
f"discarded mass is {mass!r} but the bound is reported as {bound!r}",
|
|
343
|
+
)
|
|
344
|
+
)
|
|
345
|
+
_check_converged(rec, add, threshold=1e-9)
|
|
346
|
+
|
|
347
|
+
elif rec.get("convergence_deviation") is not None:
|
|
348
|
+
add(
|
|
349
|
+
Check(
|
|
350
|
+
"bound recomputed from the measurement",
|
|
351
|
+
SKIP,
|
|
352
|
+
"convergence check, which is evidence of accuracy rather than a bound",
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
else:
|
|
356
|
+
add(
|
|
357
|
+
Check(
|
|
358
|
+
"bound recomputed from the measurement",
|
|
359
|
+
SKIP,
|
|
360
|
+
"no measured quantity published to recompute from",
|
|
361
|
+
)
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _check_converged(rec: dict, add, threshold: float) -> None:
|
|
366
|
+
"""The converged flag is derived, so it is checkable. The two engines use
|
|
367
|
+
different thresholds, which is why the caller passes one in."""
|
|
368
|
+
converged = rec.get("converged")
|
|
369
|
+
bound = rec.get("error_bound")
|
|
370
|
+
if converged is None or bound is None:
|
|
371
|
+
add(Check("converged flag consistent with the bound", SKIP))
|
|
372
|
+
return
|
|
373
|
+
expected = float(bound) < threshold
|
|
374
|
+
add(
|
|
375
|
+
Check("converged flag consistent with the bound", PASS, f"{converged}")
|
|
376
|
+
if bool(converged) is expected
|
|
377
|
+
else Check(
|
|
378
|
+
"converged flag consistent with the bound",
|
|
379
|
+
FAIL,
|
|
380
|
+
f"bound {bound:g} against a {threshold:g} threshold implies "
|
|
381
|
+
f"converged={expected}, but {converged} is recorded",
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def main(argv: list[str] | None = None) -> int:
|
|
387
|
+
import argparse
|
|
388
|
+
|
|
389
|
+
parser = argparse.ArgumentParser(
|
|
390
|
+
prog="zcc-verify",
|
|
391
|
+
description="Check a ZCC-v0.1 / ZHF-v0.1 certificate for internal consistency.",
|
|
392
|
+
epilog=(
|
|
393
|
+
"Confirms that a certificate's stated bound follows from its own stated "
|
|
394
|
+
"measurement. Does not, and cannot, confirm that the measurement itself "
|
|
395
|
+
"was honestly made."
|
|
396
|
+
),
|
|
397
|
+
)
|
|
398
|
+
parser.add_argument("target", help="a certificate id, or a path to a JSON record")
|
|
399
|
+
parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
|
|
400
|
+
args = parser.parse_args(argv)
|
|
401
|
+
|
|
402
|
+
import pathlib
|
|
403
|
+
|
|
404
|
+
path = pathlib.Path(args.target)
|
|
405
|
+
if path.is_file():
|
|
406
|
+
rec = json.loads(path.read_text(encoding="utf-8"))
|
|
407
|
+
else:
|
|
408
|
+
rec = fetch(args.target, base_url=args.base_url)
|
|
409
|
+
|
|
410
|
+
report = verify(rec)
|
|
411
|
+
print(report)
|
|
412
|
+
return 0 if report.ok else 1
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
if __name__ == "__main__":
|
|
416
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zcc-verify
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Independent consistency checker for ZCC-v0.1 / ZHF-v0.1 quantum simulation accuracy certificates
|
|
5
|
+
Author-email: ZKSF <info@zksf.org>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zksf.org
|
|
8
|
+
Project-URL: Source, https://github.com/official-dvl/zksf-zcc-verify
|
|
9
|
+
Project-URL: Issues, https://github.com/official-dvl/zksf-zcc-verify/issues
|
|
10
|
+
Project-URL: Specification, https://doi.org/10.5281/zenodo.21851381
|
|
11
|
+
Project-URL: Protocol, https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md
|
|
12
|
+
Project-URL: SDK, https://pypi.org/project/qsim-sdk/
|
|
13
|
+
Keywords: quantum,quantum computing,quantum circuit simulator,certification,verification,error bounds,reproducibility,ZCC,ZHF
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# zcc-verify
|
|
30
|
+
|
|
31
|
+
[](https://github.com/official-dvl/zksf-zcc-verify/actions/workflows/ci.yml)
|
|
32
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
33
|
+
[](https://pypi.org/project/zcc-verify/)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
[](https://doi.org/10.5281/zenodo.21851381)
|
|
36
|
+
|
|
37
|
+
Independent consistency checker for **ZCC-v0.1** and **ZHF-v0.1** quantum simulation
|
|
38
|
+
accuracy certificates.
|
|
39
|
+
|
|
40
|
+
No dependencies. Python 3.10+.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install zcc-verify
|
|
44
|
+
zcc-verify fe529e21d7404ff3
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
certificate fe529e21d7404ff3 (ZCC-v0.1)
|
|
49
|
+
[ok ] required fields present
|
|
50
|
+
[ok ] protocol recognised: ZCC-v0.1
|
|
51
|
+
[ok ] carries no account or circuit data
|
|
52
|
+
[ok ] circuit identified by SHA-256
|
|
53
|
+
[ok ] issued-at timestamp parses: 2026-07-09T13:20:03+00:00
|
|
54
|
+
[ok ] shot count: 512
|
|
55
|
+
[ok ] measured outcomes: 2 outcomes, 512 shots shown
|
|
56
|
+
[ok ] bound is a probability: 2.1073424255447017e-08
|
|
57
|
+
[ok ] bound recomputed from the measurement: sqrt(2 x 2.22045e-16) = 2.10734e-08
|
|
58
|
+
[ok ] converged flag consistent with the bound: True
|
|
59
|
+
consistent: the stated bound follows from the stated measurement
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Exit status is 0 when every check passes and 1 when any fails, so it drops into CI.
|
|
63
|
+
|
|
64
|
+
## Why this exists
|
|
65
|
+
|
|
66
|
+
Classical simulation of quantum circuits is exact only in a narrow regime. Exact
|
|
67
|
+
statevector methods terminate near 30 to 32 qubits, because state size grows as `2^n`.
|
|
68
|
+
Beyond that every practical method is approximate: tensor networks truncate the bond
|
|
69
|
+
dimension, Pauli propagation truncates operator weight, and real hardware substitutes
|
|
70
|
+
device noise for the ideal distribution.
|
|
71
|
+
|
|
72
|
+
An approximate result without an error statement is not a measurement, it is an
|
|
73
|
+
assertion. **ZCC-v0.1** and **ZHF-v0.1** are small versioned protocols that attach a
|
|
74
|
+
machine-checkable accuracy statement to a result. This tool is the checker: it takes a
|
|
75
|
+
certificate and confirms the claim it makes follows from the measurement it reports.
|
|
76
|
+
|
|
77
|
+
The protocols are specified in a citable paper:
|
|
78
|
+
|
|
79
|
+
> Reporting the Accuracy of Approximate Quantum Circuit Simulation: A Machine-Checkable
|
|
80
|
+
> Certificate Format. [doi.org/10.5281/zenodo.21851381](https://doi.org/10.5281/zenodo.21851381)
|
|
81
|
+
|
|
82
|
+
## What this establishes
|
|
83
|
+
|
|
84
|
+
The load-bearing check recomputes the declared bound from the measured quantity the
|
|
85
|
+
certificate itself reports, and requires the two to agree:
|
|
86
|
+
|
|
87
|
+
| Method | Reported quantity | Bound must equal |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| Matrix product state | discarded SVD weight `eps` | `min(1, sqrt(2 * eps))` |
|
|
90
|
+
| Pauli propagation | discarded coefficient mass | the mass itself (additive) |
|
|
91
|
+
| Exact / stabilizer | nothing discarded | zero |
|
|
92
|
+
| Hardware (ZHF-v0.1) | Hellinger fidelity vs. the exact ideal | within `[0, 1]`, or explicitly declined |
|
|
93
|
+
|
|
94
|
+
It also checks that the record is well formed, that the `converged` flag agrees with the
|
|
95
|
+
bound (the two methods use different thresholds), that outcome counts do not exceed the
|
|
96
|
+
shot count, and that no account data or circuit source is present.
|
|
97
|
+
|
|
98
|
+
A certificate whose stated bound does not follow from its own stated inputs fails here,
|
|
99
|
+
whoever issued it.
|
|
100
|
+
|
|
101
|
+
## What this does not establish
|
|
102
|
+
|
|
103
|
+
**It does not establish that the measurement was honest.** The discarded weight in a
|
|
104
|
+
tensor-network certificate, and the coefficient mass in a Pauli one, are produced by
|
|
105
|
+
whoever ran the simulation. No arithmetic on the record can confirm that the number
|
|
106
|
+
reported is the number that was measured.
|
|
107
|
+
|
|
108
|
+
Verifying a certificate is not the same as trusting the issuer. What it gives you is
|
|
109
|
+
narrower and still worth having: the claim is well formed, self-consistent, and stated
|
|
110
|
+
in a form somebody else can check.
|
|
111
|
+
|
|
112
|
+
## Use as a library
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from zcc_verify import fetch, verify
|
|
116
|
+
|
|
117
|
+
report = verify(fetch("df1d4c698a954051"))
|
|
118
|
+
print(report.ok) # True
|
|
119
|
+
print([c.name for c in report.failures]) # []
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`fetch()` reads the public record at `https://api.zksf.org/certify/<id>/json`. It needs
|
|
123
|
+
no authentication and no account. `verify()` takes a plain dict, so a record from any
|
|
124
|
+
source, including a local file or a different issuer, can be checked:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
zcc-verify ./certificate.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Four live certificates to try, covering every accuracy regime the protocols describe:
|
|
131
|
+
|
|
132
|
+
| Certificate | Run |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `d904e28af0b441e0` | 3-qubit GHZ, exact stabilizer simulation |
|
|
135
|
+
| `fe529e21d7404ff3` | 12-qubit GHZ, tensor network, measured bound of 2.11e-08 |
|
|
136
|
+
| `5b8b2c4309d44d41` | 192-qubit GHZ, Pauli propagation |
|
|
137
|
+
| `df1d4c698a954051` | Bell state on IonQ Forte-1 hardware, 0.977 fidelity |
|
|
138
|
+
|
|
139
|
+
## On the limits of the bound
|
|
140
|
+
|
|
141
|
+
The certified bound is an empirical result rather than a theorem. It held across 334
|
|
142
|
+
runs at sizes where the exact answer is computable, 290 of them constructed specifically
|
|
143
|
+
to break it, approaching at closest 49 percent of its value. Above 20 qubits it cannot
|
|
144
|
+
be checked by direct comparison and no such evidence exists. Where a hard ceiling is
|
|
145
|
+
required, use an exact or stabilizer engine.
|
|
146
|
+
|
|
147
|
+
The paper is explicit about the case in which the motivating derivation does not extend:
|
|
148
|
+
in deep sequential circuits the accumulated truncation weight has been measured
|
|
149
|
+
understating the true infidelity by up to a factor of seven. It also shows, by explicit
|
|
150
|
+
counterexample, that a natural tightening of the bound is unsound.
|
|
151
|
+
|
|
152
|
+
## Where these certificates come from
|
|
153
|
+
|
|
154
|
+
[ZKSF (Zero Kelvin Simulation Foundry)](https://zksf.org) runs quantum circuits on
|
|
155
|
+
classical simulators, GPU accelerators, or real quantum processors, and attaches one of
|
|
156
|
+
these accuracy statements to every approximate result.
|
|
157
|
+
|
|
158
|
+
- **Python SDK** — [`qsim-sdk`](https://pypi.org/project/qsim-sdk/) on PyPI, source at
|
|
159
|
+
[official-dvl/zksf](https://github.com/official-dvl/zksf), DOI
|
|
160
|
+
[10.5281/zenodo.21836619](https://doi.org/10.5281/zenodo.21836619). Accepts Qiskit
|
|
161
|
+
circuits directly, and Cirq, PennyLane, pyQuil or Braket circuits via an optional
|
|
162
|
+
transpiler.
|
|
163
|
+
- **Try it without an account** — the
|
|
164
|
+
[Colab quickstart](https://colab.research.google.com/github/official-dvl/zksf/blob/main/examples/quickstart.ipynb)
|
|
165
|
+
reads real completed certificates from the public API before it asks you for anything.
|
|
166
|
+
- **Android app** — submit a circuit and read the result from a phone, including runs on
|
|
167
|
+
real quantum hardware:
|
|
168
|
+
[Google Play](https://play.google.com/store/apps/details?id=com.quantumcomputing.app).
|
|
169
|
+
- **Protocol reference** —
|
|
170
|
+
[CERTIFICATION.md](https://github.com/official-dvl/zksf/blob/main/docs/CERTIFICATION.md)
|
|
171
|
+
- **Documentation** — [zksf.org/docs](https://zksf.org/docs)
|
|
172
|
+
|
|
173
|
+
This checker is deliberately independent of all of the above: it has no dependency on
|
|
174
|
+
the SDK, needs no account, and will check a certificate issued by anyone who emits the
|
|
175
|
+
format.
|
|
176
|
+
|
|
177
|
+
## Licence
|
|
178
|
+
|
|
179
|
+
MIT.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
tests/test_verify.py
|
|
5
|
+
zcc_verify/__init__.py
|
|
6
|
+
zcc_verify/__main__.py
|
|
7
|
+
zcc_verify.egg-info/PKG-INFO
|
|
8
|
+
zcc_verify.egg-info/SOURCES.txt
|
|
9
|
+
zcc_verify.egg-info/dependency_links.txt
|
|
10
|
+
zcc_verify.egg-info/entry_points.txt
|
|
11
|
+
zcc_verify.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zcc_verify
|