1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! Deterministic JSON canonicalization — the single source of the hash's
//! stability across all ten language bindings.
//!
//! The rules (each normative):
//! 1. Object keys are sorted ascending by Unicode code point (`BTreeMap`).
//! 2. No whitespace: `,` and `:` separators, nothing else.
//! 3. Every float is quantized to 1e-8 by decimal rounding (`{:.8}`), trailing
//! zeros trimmed. A whole-valued float collapses to its integer token
//! (`1.0` -> `"1"`), because JSON in most host languages (JavaScript above
//! all) cannot preserve the `.0`: `JSON.stringify` emits `1`, and the hash
//! must be byte-identical regardless of which language loaded the spec.
//! Integers stay integers by the same token. Magnitudes at or above
//! `2^52 * 1e-8` (where the f64 ULP reaches the grid) instead use the
//! shortest round-trippable form, keeping canonicalization a fixed point.
//! 4. `NaN` / `±inf` cannot occur: `serde_json` rejects them at parse time, so
//! every `Value` number is a finite integer or float by construction.
//! 5. Strings use `serde_json`'s standard escaping.
//! 6. Array order is preserved (it is meaning-bearing).
use crateResult;
use Value;
use BTreeMap;
use Write as _;
use ;
/// Format a float in a fixed, cross-language-stable, idempotent decimal form:
/// eight fractional digits, trailing zeros trimmed, and a whole value collapsed
/// to its bare integer token (`1.0` -> `"1"`). The integer collapse is essential:
/// a host language cannot distinguish `1.0` from `1` in JSON — `JSON.stringify`
/// emits `1` — so the only representation every language can reproduce for a
/// whole number is the integer one. Negative zero normalizes to `0`.
///
/// Quantization to 1e-8 is done purely by the `{:.8}` decimal rounding — no
/// separate binary-grid step. That matters for the moat's load-bearing property:
/// canonicalization must be a fixed point (canonicalize -> parse -> canonicalize
/// yields the same bytes). Rounding to eight decimals is a fixed point only while
/// the 1e-8 grid is coarser than the f64 ULP, i.e. `|x| < 2^52 * 1e-8`; a binary
/// `(x*1e8).round()/1e8` grid disagrees with the decimal one right at that
/// boundary and used to drift (found by the canonicalize fuzz target on inputs
/// like `44447444.444...` and `5e55`).
///
/// At or above that magnitude the 1e-8 grid is finer than f64 can represent, so
/// `{:.8}` is meaningless and unstable; emit the shortest round-trippable form
/// (`Display`, always positional for f64, never scientific) instead, which
/// re-parses to the same value under `serde_json`'s `float_roundtrip` parser.
/// Produce the canonical, whitespace-free, key-sorted string form of `value`.
/// Byte-identical across languages; the input to the blake3 hash.
///
/// The `Result` return keeps a uniform signature with the rest of the API and
/// the language bindings; canonicalization of a `serde_json::Value` is total.
/// The lowercase 64-hex blake3 of a canonical string (no prefix).
pub
/// The canonical hash of any JSON value: the blake3 of its canonical form.
///
/// This is the crate's only definition of "the hash". [`prove`](crate::prove)
/// reports both of its hashes through it, and [`hash_candles`] and
/// [`hash_report`] are it applied to the two shapes a caller outside the prover
/// needs. Anything that recomputes a hash independently -- a zkVM guest, a
/// language binding -- has to agree with this function, or the proof it
/// produces says nothing.
///
/// # Errors
/// Propagates a canonicalization failure. Canonicalizing a `Value` is total, so
/// the variant exists for signature uniformity with the rest of the API.
/// The canonical hash of a candle series -- the dataset commitment.
///
/// Binds a proof to the data it was computed over: the same candles in the same
/// order produce the same 64-hex string in every language, so a verifier can
/// tell whether two proofs used the same series without being shown it.
///
/// Note what this is *not*: [`prove`](crate::prove) hashes
/// `{strategy, dataset_ref, candles, engine_version}` as one block into
/// `inputs_hash`. This hashes the candles alone.
///
/// # Errors
/// Returns [`Error`](crate::Error) if the candles cannot be represented as JSON.
/// The canonical hash of a backtest report.
///
/// Byte-identical to the `report_hash` that [`prove`](crate::prove) reports for
/// the same report -- `prove` calls this rather than repeating it, so the two
/// cannot drift apart.
///
/// # Errors
/// Returns [`Error`](crate::Error) if the report cannot be represented as JSON.