zcc-verify 0.1.0__py3-none-any.whl
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/__init__.py +416 -0
- zcc_verify/__main__.py +4 -0
- zcc_verify-0.1.0.dist-info/METADATA +179 -0
- zcc_verify-0.1.0.dist-info/RECORD +8 -0
- zcc_verify-0.1.0.dist-info/WHEEL +5 -0
- zcc_verify-0.1.0.dist-info/entry_points.txt +2 -0
- zcc_verify-0.1.0.dist-info/licenses/LICENSE +22 -0
- zcc_verify-0.1.0.dist-info/top_level.txt +1 -0
zcc_verify/__init__.py
ADDED
|
@@ -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())
|
zcc_verify/__main__.py
ADDED
|
@@ -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,8 @@
|
|
|
1
|
+
zcc_verify/__init__.py,sha256=H-4pZfzSD1XzSJ1serK_Ra5__yLnh0KSJXzOA2lKjHU,14356
|
|
2
|
+
zcc_verify/__main__.py,sha256=egqAJxQgU-h2yxcfHxQBkTQCiyXJFcGM2OIU0PZsWh8,100
|
|
3
|
+
zcc_verify-0.1.0.dist-info/licenses/LICENSE,sha256=41brFj4dDCxsWVo3XaQEAJpA6QHm0Ev3o3ZaeqOxfjw,1142
|
|
4
|
+
zcc_verify-0.1.0.dist-info/METADATA,sha256=q2PVGlx4I0hLMImLKpldBHOLVDhz0VhsmA_mUx5mMOk,8306
|
|
5
|
+
zcc_verify-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
6
|
+
zcc_verify-0.1.0.dist-info/entry_points.txt,sha256=6VIPqHzfpKahIbKlsjCYlFRPRcg4XADbwF3EuWuZ610,47
|
|
7
|
+
zcc_verify-0.1.0.dist-info/top_level.txt,sha256=E-KiKfLhZpVhS2sjAsICY5wIKKyTlDxLMrdPAOJBXKk,11
|
|
8
|
+
zcc_verify-0.1.0.dist-info/RECORD,,
|
|
@@ -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 @@
|
|
|
1
|
+
zcc_verify
|