diff --git a/Taskfile.yml b/Taskfile.yml index 61630864b..4c526fe83 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -6,15 +6,25 @@ env: tasks: build:zk-cache: - desc: Generate verifier circuit caches (main + v1 + fp8, one-time) + desc: Generate verifier circuit caches (main + v1 + fp8 + fp16, one-time) run: once dir: zk-pow + env: + # The FP16 wrapper verifier cache is embedded via include_bytes! by the Go + # binding's `embedded_cache` feature, so fp16_cache.bin must exist for the + # binding to compile. FP16_CACHE_SAMPLE=1 builds the single smallest legal + # profile — a cheap bootstrap blob that makes the crate compile and exercises + # the load path. The full per-profile FP16 envelope is a heavy (multi-GB, + # minutes-per-profile) offline build required only before V5 is activated on a + # network; drop this env (or run build_cache with the explicit fp16 path) for it. + FP16_CACHE_SAMPLE: "1" status: - test -s src/v2/circuit/v2_cache.bin - test -s src/v1/v1_cache.bin - test -s src/api/fp8/fp8_cache.bin + - test -s src/api/fp16/fp16_cache.bin cmds: - - cargo run --release --no-default-features --bin build_cache src/api/fp8/fp8_cache.bin src/v2/circuit/v2_cache.bin src/v1/v1_cache.bin + - cargo run --release --no-default-features --bin build_cache src/api/fp8/fp8_cache.bin src/v2/circuit/v2_cache.bin src/v1/v1_cache.bin src/api/fp16/fp16_cache.bin build:zk-gobind: desc: Build the Rust ZK verification library for Go FFI @@ -92,7 +102,7 @@ tasks: cmds: - rm -rf bin - rm -f xmss/libxmss.a - - rm -f zk-pow/src/api/fp8/fp8_cache.bin zk-pow/src/v2/circuit/v2_cache.bin zk-pow/src/v1/v1_cache.bin + - rm -f zk-pow/src/api/fp8/fp8_cache.bin zk-pow/src/v2/circuit/v2_cache.bin zk-pow/src/v1/v1_cache.bin zk-pow/src/api/fp16/fp16_cache.bin - rm -rf pearl-blake3/target py-pearl-mining/target zk-pow/target zk-pow/bindings/go/target - find . -name coverage.txt -type f -delete diff --git a/docs/fp16_scheme/.gitignore b/docs/fp16_scheme/.gitignore new file mode 100644 index 000000000..1ede06be0 --- /dev/null +++ b/docs/fp16_scheme/.gitignore @@ -0,0 +1,12 @@ +*.aux +*.log +*.out +*.toc +*.fls +*.fdb_latexmk +*.synctex.gz + +# hardware capture build artifact +validation/a100_hmma_capture +validation/attack_cost_benchmark +validation/__pycache__/ diff --git a/docs/fp16_scheme/README.md b/docs/fp16_scheme/README.md new file mode 100644 index 000000000..0d8532a37 --- /dev/null +++ b/docs/fp16_scheme/README.md @@ -0,0 +1,32 @@ +# Pearl FP16 scheme specification + +`fp16_scheme.tex` specifies an alternative Pearl proof-of-useful-work instantiation whose unit +of work is **FP16** matrix multiplication on NVIDIA A100 (GA100, `sm_80`) tensor cores. It +extends the FP8 certificate-v4 specification rather than replacing it: commitments, seed chain, +state window, ticket, target, MoE extension, and the ZK split are shared, and FP8 remains a +separate `Quant` value. + +The new idea: hardness comes from the **nonlinearity of the device's accumulation**, not from a +coarse rounding grid. The A100 tensor core truncates each product onto a per-group alignment +grid *before* summing (groups of 8, 24-bit window, round-toward-zero per group). That per-product +truncation does not commute with the reduction, so it cannot be expressed as a matrix +multiplication — the same obstruction that makes the integer transcript scheme hard, applied for +free on every MAC. This lets recovered products carry FP16-level accuracy instead of +FP8-residual accuracy. + +The experiments the spec's appendices summarize are reproduced by the committed harness in +[`validation/`](validation/) (A100 HMMA accumulation-model capture + model-vs-silicon cross-check, +RZ-vs-RNE resolution, policy `f_bp`/`rho` calibration, and the truncation-attack cost benchmark). +See [`validation/README.md`](validation/README.md) for how to run it on `sm_80` silicon and the +recorded results. + +## Building the PDF + +The checked-in `fp16_scheme.pdf` is the authoritative rendering. To rebuild: + +```sh +# Any LaTeX engine works; the doc uses only amsmath/amssymb/booktabs/hyperref. +tectonic fp16_scheme.tex # self-contained, recommended +# or +latexmk -pdf fp16_scheme.tex +``` diff --git a/docs/fp16_scheme/fp16_scheme.pdf b/docs/fp16_scheme/fp16_scheme.pdf new file mode 100644 index 000000000..902ceeb82 Binary files /dev/null and b/docs/fp16_scheme/fp16_scheme.pdf differ diff --git a/docs/fp16_scheme/fp16_scheme.tex b/docs/fp16_scheme/fp16_scheme.tex new file mode 100644 index 000000000..6122527a0 --- /dev/null +++ b/docs/fp16_scheme/fp16_scheme.tex @@ -0,0 +1,510 @@ +\documentclass[11pt]{article} +\usepackage[margin=1in]{geometry} +\usepackage{amsmath,amssymb,amsthm} +\usepackage{mathtools} +\usepackage{enumitem} +\usepackage{booktabs} +\usepackage{hyperref} +\usepackage{xcolor} +\hypersetup{colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue} + +\newcommand{\Quant}{\textsf{Quant}} +\newcommand{\Device}{\textsf{Device}} +\newcommand{\Ticket}{\textsf{Ticket}} +\newcommand{\Extract}{\textsf{Extract}} +\newcommand{\Rows}{\textsf{Rows}} +\newcommand{\Hb}{\mathsf{H}} +\newcommand{\MatMul}{\textsf{MatMul}} +\newcommand{\NoisyQuantize}{\textsf{NoisyQuantize}} +\newcommand{\SampleLine}{\textsf{SampleLine}} +\newcommand{\Trunc}{\textsf{Trunc}} +\newcommand{\RZ}{\textsf{RZ}} +\newcommand{\RNE}{\textsf{RNE}} +\newcommand{\ulp}{\textsf{ulp}} +\newcommand{\ufp}{\textsf{ufp}} +\newcommand{\eps}{\varepsilon} +\newcommand{\sg}{\mathrm{sgn}} +\newcommand{\Ct}{\widetilde{C}} +\newcommand{\At}{\widetilde{A}} +\newcommand{\Bt}{\widetilde{B}} +\newcommand{\T}{\mathsf{T}} +\newcommand{\R}{\mathbb{R}} +\newcommand{\FP}[1]{\textsf{FP#1}} +\newcommand{\sigmin}{\sigma_{\min}} + +\newtheorem{assumption}{Assumption} +\newtheorem{conjecture}{Conjecture} +\newtheorem{definition}{Definition} +\newtheorem{remark}{Remark} + +\title{\textbf{Pearl Floating-Point Scheme Specification:\\ FP16 Accumulation-Hardness Variant}} +\author{Jon Pry\\ \texttt{jonpry@gmail.com}} +\date{October 2026} + +\begin{document} +\maketitle + +\begin{abstract} +This document specifies an alternative instantiation of the Pearl proof-of-useful-work +protocol in which the unit of mining work is \FP{16} matrix multiplication on GPUs, with +NVIDIA A100 (GA100) tensor cores as the first whitelisted device. It extends the \FP{8} +certificate-v4 specification rather than replacing it: the commitment structure, seed chain, +state window, ticket, target, mixture-of-experts extension, and zero-knowledge split are +unchanged, and the \FP{8} scheme remains available as a separate \Quant{} value. The new +content is a \emph{hardness source that does not rely on coarse quantization}. Where the +\FP{8} scheme makes the lottery product hard to shortcut by rounding onto a coarse grid, the +\FP{16} scheme derives hardness from the \emph{nonlinearity of the device's own accumulation}: +the A100 tensor core truncates each product onto a per-group alignment grid before summing, +an operation that does not commute with the reduction and therefore cannot be expressed as a +matrix multiplication. We give the bit-exact A100 accumulation model (validated against +silicon), a policy check---\emph{unpredictable accumulation steps}---that the verifier +evaluates during its tile replay, and an analysis of the attack surface. The practical payoff +is that recovered products carry \FP{16}-level accuracy rather than \FP{8}-residual accuracy, +at the cost of a new, device-specific hardness assumption. We find \FP{16} robust and +\textsf{BF16} too close to linear to admit the same argument. +\end{abstract} + +\tableofcontents + +\section{Introduction}\label{sec:intro} + +Proof-of-useful-work (PoUW) replaces the artificial puzzle of classical proof of work with a +computation someone already wants performed. The Pearl protocol instantiates the PoUW of +Komargodski and Weinstein~\cite{KW25} for matrix multiplication: a miner multiplies matrices +of its own choosing and every tile of the product doubles as a lottery ticket. The obstacle +is permissionlessness---the miner chooses its inputs, so the protocol must guarantee that no +choice of inputs, however degenerate, makes valid tickets cheaper than the prescribed amount +of work. + +The original integer protocol~\cite{KW25} achieves this by hashing the \emph{transcript} of +the computation: the product is formed in $r\times r$ blocks and a random oracle is applied to +all $(n/r)^3$ intermediate blocks, so that even the all-zeroes product is as hard as a generic +one. The Pearl \FP{8} specification~\cite{PearlFP8} instead hashes only output tiles and +recovers hardness from quantization: because entrywise quantization is nonlinear, the low-rank +noise injected before quantization destroys the low-rank shortcut, and tiles can be hashed +directly. This is cheaper than transcript hashing, but its security depends on the rounding +being coarse: the quantization error must be large enough that its contribution to the output +survives the accumulator. At \FP{8} this holds comfortably; as the target format becomes more +precise, the quantization error shrinks and the margin vanishes. + +This document describes a third point in the design space, aimed at \FP{16}. We keep output- +tile hashing---so the miner runs its ordinary GEMM with no in-kernel hashing---but we obtain +hardness from a different nonlinearity. Modern tensor cores do not accumulate in exact +arithmetic. On the A100, each product is truncated toward zero onto an alignment grid shared by +a group of eight products, the group is summed, and the running accumulator is rounded after +every group. The truncation is applied \emph{per product, before the reduction}. This is the +same structural device that makes transcript hashing hard---a per-summand operation that a +single contraction cannot reproduce---except that it is performed by the hardware for free, on +every multiply-accumulate the miner already issues. An honest miner's output therefore encodes, +at no extra cost, a quantity that an adversary with the low-rank shortcut cannot cheaply +reconstruct. + +\paragraph{Organization.} Section~\ref{sec:abstract} recalls the abstract protocol and states +the new hardness premise. Section~\ref{sec:prelim} fixes notation and the work model. +Section~\ref{sec:device} gives the bit-exact A100 accumulation model---the technical core of +this variant. Section~\ref{sec:hardness} states the hardness argument and assumption. +Section~\ref{sec:policy} specifies the jackpot policy, including the unpredictable-accumulation- +steps check. Section~\ref{sec:attacks} surveys attack vectors. Section~\ref{sec:miner} +describes the honest miner. Section~\ref{sec:compare} compares \FP{16}, \FP{8} and \textsf{BF16}. +The appendices give the A100 arithmetic specification, the \FP{16} commit type, the noise and +quantization procedures, the certified-work ratio, and a summary of the empirical validation. + +\section{The abstract protocol}\label{sec:abstract} + +Let $A\in\R^{m\times k}$ and $B\in\R^{n\times k}$, with useful product $C:=AB^\T$. As in the +\FP{8} scheme, the protocol derives seed-dependent rank-$r$ noise matrices $N_A\in\R^{m\times k}$ +and $N_B\in\R^{n\times k}$ and computes +\begin{equation} +\Ct := Q(A+N_A)\,Q(B+N_B)^\T, +\end{equation} +where $Q$ is the protocol's quantization into the committed storage format and the +multiplication is carried out by the committed device's native kernel. Each noise matrix is +unpredictable before the inputs are committed. The product $\Ct$ drives the lottery; the honest +miner recovers the useful product by the cheap low-rank correction +$\widehat C := \Ct - A N_B^\T - N_A B^\T - N_A N_B^\T$, exactly as in~\cite{KW25,PearlFP8}. + +The difference from the \FP{8} scheme is in \emph{what makes $\Ct$ hard to shortcut}. Setting +$A=B=0$ isolates the lottery product as $Q(N_A)\,Q(N_B)^\T$. The \FP{8} premise is that +entrywise quantization raises the rank of $Q(N_A)$ enough that this product is as hard as a +generic quantized product. The \FP{16} premise is weaker on quantization and stronger on the +device: at \FP{16} the quantization barely raises the rank, but the device does not compute the +exact product $Q(N_A)Q(N_B)^\T$---it computes a \emph{per-product-truncated} version of it, +tile by tile, and it is that version the ticket hashes. + +\paragraph{The central object.} For operands stored in a format with $p$-bit significands, write +the device dot product of row $i$ of $\At:=Q(A+N_A)$ with row $j$ of $\Bt:=Q(B+N_B)$ as +\begin{equation}\label{eq:dotdevice} +D_{ij} \;=\; \textsf{Acc}\big(\At_{i,0}\Bt_{j,0},\,\dots,\,\At_{i,k-1}\Bt_{j,k-1}\big), +\end{equation} +where $\textsf{Acc}$ is the device accumulation of Section~\ref{sec:device}, \emph{not} the +exact sum. The exact sum $S_{ij}=\sum_u \At_{iu}\Bt_{ju}$ is, for low-rank-plus-noise operands, +computable by an adversary in $O(r)$ work per cell through the low-rank structure. The quantity +$D_{ij}$ differs from $\RZ(S_{ij})$ by the accumulated per-product truncation remainders, and +reconstructing those remainders is what the protocol charges for. Section~\ref{sec:hardness} +makes this precise. + +\section{Preliminaries}\label{sec:prelim} + +\paragraph{Notation.} Matrices are over the reals, stored in a committed floating-point format. +$C:=AB^\T\in\R^{m\times n}$; $C_{ij}$ is the inner product of row $i$ of $A$ with row $j$ of $B$. +For selected row-index sets $I_A,I_B$ (chosen by periodic partitions $\mathcal P_A,\mathcal P_B$, +as in the \FP{8} scheme), $\Ct_{I_A,I_B}:=\At_{I_A}(\Bt_{I_B})^\T$ is the recomputed tile. The +seeds $\texttt{noise\_seed}_A,\texttt{noise\_seed}_B$ determine the noise. The ticket digest is a +keyed function $\Ticket$ from tiles to $\{0,1\}^\lambda$, $\lambda=256$: +\[ +\Ticket(\Ct_{I_A,I_B}) := \Hb_{\text{``jackpot''}}\big(\Extract(\Ct_{I_A,I_B},\mathcal P_A,\mathcal P_B);\,\texttt{noise\_seed}_A\big). +\] +All of $\Ticket$, $\Extract$, the seed chain, the state window of depth $D$, the domain-separated +BLAKE3 hashing, and the commitment format are shared with the \FP{8} specification~\cite{PearlFP8} +and are not restated here except where \FP{16} changes them (Appendix~\ref{app:commit}). + +\paragraph{Work model.} Work is measured in multiply-accumulate operations (MACs). The direct +cost of the selected tile is $T_{\text{tile}}:=|I_A|\cdot|I_B|\cdot k$. As in~\cite{PearlFP8} the +MAC count fixes scale only; it excludes quantization, noise generation, hashing, and memory +movement. The novelty of this variant is that the quantity securing the tile is produced +\emph{inside} these MACs by the device, so no work beyond the GEMM is charged to the miner. + +\paragraph{Device and Quant.} $\Device$ and $\Quant$ are consensus-allowed enumerations. This +document adds $\Device=\textsf{A100}$ with the accumulation model of Section~\ref{sec:device}, and +a $\Quant$ value whose storage type is \FP{16} and whose commit type is the \FP{16} block format +of Appendix~\ref{app:commit}. The \FP{8} values remain available unchanged. + +\section{The A100 accumulation model}\label{sec:device} + +We specify the arithmetic of the A100 \texttt{HMMA.16816.F32} instruction (and the +equivalent \texttt{m16n8k8}/\texttt{m16n8k16} and \texttt{wmma} forms, which chain identically) +for \FP{16} and \textsf{BF16} inputs with \FP{32} accumulation. The model is validated bit-exact +against silicon in Appendix~\ref{app:validation}. The verifier's implementation is authoritative; +the description below is phrased in exact arithmetic. + +Let the $k$-axis be partitioned into \emph{groups} of $G=8$ consecutive products, processed in +order (two groups per \texttt{k16} instruction). The internal accumulator precision is +$W=24$ significant bits (full \FP{32} significand). For a stored value $x$, let $\eps(x)$ be its +unbiased stored exponent, with subnormal inputs taking the format minimum ($-14$ for \FP{16}, +$-126$ for \textsf{BF16}). For a nonzero \FP{32} accumulator $c$, let $\eps(c):=\max(\lfloor\log_2|c|\rfloor,-126)$. +Let $\Trunc(x,g)$ denote truncation of $x$ toward zero onto the grid $2^{g}$ (sign-magnitude). + +\paragraph{One group step.} With incoming accumulator $c$ and group products $p_u=\At_{iu}\Bt_{ju}$ +(each exact; its exponent is $\eps(\At_{iu})+\eps(\Bt_{ju})$): +\begin{enumerate}[nosep] +\item If the group has no nonzero product and $c$ is unchanged, the step is a no-op. +\item Compute the alignment exponent + $\eta := \max\big(\{\eps(\At_{iu})+\eps(\Bt_{ju}) : p_u\neq0\}\cup\{\eps(c)\}\big)$, + where $c=0$ does not participate and a subnormal $c$ contributes $-126$. +\item Truncate every product and the accumulator onto the grid $2^{\eta-W}$: + $\bar p_u := \Trunc(p_u,\eta-W)$, $\bar c := \Trunc(c,\eta-W)$. +\item Sum the integers exactly: $S := \bar c + \sum_u \bar p_u$. +\item Round $S$ toward zero to \FP{32}: $c' := \RZ_{\FP{32}}(S)$, i.e.\ keep the top $24$ + significant bits, place subnormal results on the $2^{-149}$ grid, and map $|S|\ge 2^{128}$ + to $\pm\infty$. +\end{enumerate} +The final accumulator after all groups is $D_{ij}$. Boundary behavior: a zero result is always +$+0$; $\infty$ and NaN follow IEEE-754 on the inputs (NaN sign and payload are unspecified); an +overflowed accumulator is \emph{sticky}---a later opposite-sign overflow does not produce NaN, +and the first overflow's sign is retained. The verifier rejects any tile whose operands or +intermediates are non-finite (Appendix~\ref{app:arith}). + +\paragraph{The key feature.} Step 3 truncates each product \emph{individually} before step 4 +sums them. Write $p'$ for the product significand width (the product of two $p$-bit significands +carries $p'=2p$ significant bits: $p'=22$ for \FP{16}, $p'=16$ for \textsf{BF16}). Once the running +accumulator exceeds a group's products by more than about $W-p'$ bits---roughly a factor +$2^{W-p'}$---the low bits of each product fall below the grid $2^{\eta-W}$ and are discarded. For +\FP{16}, $p'=22$ and $W=24$, so a product loses bits as soon as the accumulator is more than +$\sim\!4\times$ ($2^{W-p'}=2^2$) its magnitude; for a realistic dot product this happens for the +majority of products. For \textsf{BF16}, $p'=16$, so products survive the window unless they are +more than $W-p'=8$ binades below $\eta$; far fewer are truncated (Section~\ref{sec:compare}). + +\paragraph{Breakpoints.} Call a group step a \emph{breakpoint} if the accumulator truncation in +step 3 or the round in step 5 discards a nonzero bit, i.e.\ if $\bar c\neq c$ or +$\RZ_{\FP{32}}(S)\neq S$. Per-product truncations ($\bar p_u\neq p_u$) are \emph{not} breakpoints; +they are counted separately as $N_{\text{pt}}$ (Section~\ref{sec:policy}), which is why $N_{\text{pt}}$ +is well defined as the truncated products in non-breakpoint steps. The density of breakpoints over a +tile, $f_{\text{bp}}$, measures how much of the accumulation is irrecoverable from the exact sum +alone; it is the quantity the policy of Section~\ref{sec:policy} bounds from below. + +\section{Hardness}\label{sec:hardness} + +\paragraph{Exact decomposition.} For any inputs, the device output admits the exact decomposition +\begin{equation}\label{eq:decomp} +D_{ij} \;=\; \mathcal R\Big(\, S_{ij} \;-\; \sum_{g}\sum_{u\in g}\rho_u \;-\; \sum_g \gamma_g \,\Big), +\end{equation} +where $S_{ij}=\sum_u p_u$ is the exact sum, $\rho_u = p_u - \Trunc(p_u,\eta_g-W)$ is the +per-product truncation remainder in group $g$, $\gamma_g$ is the accumulator re-truncation and +per-group rounding remainder, and $\mathcal R$ denotes the per-group $\RZ$ chain. (This +reproduces the model of Section~\ref{sec:device} bit-for-bit; see Appendix~\ref{app:validation}.) +For low-rank-plus-noise operands the adversary obtains $S_{ij}$---and prefix sums of it, hence +every $\eta_g$---in $O(r)$ work per cell. The hardness therefore rests entirely on the correction +terms $\sum_u\rho_u$ and $\sum_g\gamma_g$. + +\paragraph{Non-contractibility.} The decisive property is that the correction is a +\emph{per-product nonlinearity applied before the reduction}. The map $p_u\mapsto\Trunc(p_u,\eta_g-W)$ +does not commute with summation: +\[ +\sum_u \Trunc(p_u,\eta_g-W) \;\neq\; \Trunc\Big(\sum_u p_u,\ \eta_g-W\Big)\quad\text{in general.} +\] +Consequently $\sum_u\rho_u$ is not a function of the contracted sum $S_{ij}$, and it is not +itself a bilinear form in the operand rows. No matrix multiplication---\FP{16}, integer, or +binary---evaluates it: a contraction can produce $\sum_u p_u$ or any fixed linear image of the +products, but not the sum of a nonlinear, exponent-dependent function applied to each product. +The corrections must be computed elementwise, on the $mk$ (resp.\ $nk$) products, outside the +tensor-core datapath. This is the same obstruction that makes the integer transcript scheme +hard~\cite{KW25}; here the device applies it automatically to every MAC. + +\paragraph{Assumption.} We formalize the resulting premise, in the style +of~\cite[Assumption~6.4]{KW25} and the \FP{8} transcript-unpredictability assumption. + +\begin{assumption}[Accumulation-unpredictability]\label{asm:acc} +Fix $\Device=\textsf{A100}$, $\Quant$ with \FP{16} storage, noise rank $r=32$, and admissible +tile dimensions. For operands drawn as in Appendix~\ref{app:noise} (low-rank noise added before +quantization, any miner-chosen $A,B$ admitted by the policy of Section~\ref{sec:policy}), no +algorithm reconstructs the device tile $\{D_{ij}\}$ bit-exactly in expected time substantially +below the honest cost $|I_A|\,|I_B|\,k$ MACs. In particular the corrections +$\sum_u\rho_u,\sum_g\gamma_g$ of \eqref{eq:decomp} cannot be batched onto any tensor-core path. +\end{assumption} + +\paragraph{Evidence.} Appendix~\ref{app:validation} summarizes the experiments supporting +Assumption~\ref{asm:acc}: (i) the exact model is validated on A100 silicon over $>10^7$ dot +products; (ii) for every input strategy tried, including sixteen adversarial constructions, the +\FP{16} breakpoint density stays in $[0.36,0.51]$ and a deliberately attacker-favorable +certified-work ratio (Appendix~\ref{app:rho}) stays $\ge 1.38$; (iii) the cheapest shortcut +predictors (exact sum rounded to \FP{32}; group sums without per-product truncation) reproduce +at most a few percent of cells; (iv) the truncation-correction attack, costed concretely, is +$6\text{--}13\times$ honest even under compute-bound-optimistic assumptions, because the +corrections run on CUDA cores rather than tensor cores. Assumption~\ref{asm:acc} is a +device-specific hardness conjecture and should be treated as such. + +\section{Jackpot policy}\label{sec:policy} + +Beyond the idealized setting, the miner may choose $A,B$ to make the accumulation cheaply +predictable---chiefly by arranging that few products are truncated. The verifier defends with a +pointwise policy evaluated \emph{during the bit-exact tile replay} of Section~\ref{sec:device}, +when all intermediate $\eta_g$, $\bar p_u$, $\bar c$, and $S$ are available at no extra cost. The +policy approves exactly when every check below passes; it runs after the Infinity/NaN rejection. + +\paragraph{Recorded during replay.} For each cell $(i,j)$ and group $g$ the verifier records: +\begin{itemize}[nosep] +\item $\textsf{bp}_{ijg}\in\{0,1\}$: whether the step is a breakpoint (Section~\ref{sec:device}); +\item $\textsf{ptc}_{ijg}\in\{0,\dots,G\}$: the number of products in the group with a nonzero + truncation remainder $\rho_u$. +\end{itemize} + +\paragraph{Shared checks.} The \FP{8} entry-liveness and noise-floor checks carry over to bound +degenerate operands: +\[ +\sigma_i^A\ge\sigmin\ (\forall i\in I_A),\qquad \sigma_j^B\ge\sigmin\ (\forall j\in I_B), +\qquad |\mathcal D_A|\le\eps_{\text{idle}}|I_A|k,\quad |\mathcal D_B|\le\eps_{\text{idle}}|I_B|k, +\] +with $\sigmin=1$, $\eps_{\text{idle}}=1/64$, $\tau_{\text{idle}}=8$ and the idle sets $\mathcal D_X$ +as in~\cite{PearlFP8}. These keep every opened row carrying at least one quantized unit of noise +and bound the fraction of noise-dominated entries. + +\paragraph{Unpredictable accumulation steps (new).} Define the tile breakpoint density and the +certified-work ratio +\[ +f_{\text{bp}} := \frac{1}{|I_A||I_B|\,G^{-1}k}\sum_{i,j,g}\textsf{bp}_{ijg}, +\qquad +\rho := \frac{1}{|I_A||I_B|\,k}\sum_{i,j}\Big[\,G\cdot N^{ij}_{\text{bp}} + r\cdot N^{ij}_{\text{run}} + N^{ij}_{\text{pt}}\,\Big], +\] +where $N^{ij}_{\text{bp}}$ is the number of breakpoint steps in cell $(i,j)$, $N^{ij}_{\text{run}}$ +is the number of maximal runs of non-breakpoint steps, and $N^{ij}_{\text{pt}}=\sum_g\textsf{ptc}_{ijg}$ +counts truncated products outside breakpoints. The ratio $\rho$ is the attacker-favorable +lower bound on reconstruction cost derived in Appendix~\ref{app:rho}. The check requires +\begin{equation}\label{eq:policyfp16} +f_{\text{bp}}\ \ge\ 0.30,\qquad \rho\ \ge\ 1.2. +\end{equation} + +\paragraph{Calibration.} On A100 \FP{16}, honest and realistic workloads sit at +$f_{\text{bp}}\in[0.44,0.48]$ and $\rho\in[1.64,1.83]$, with $f_{\text{bp}}$ concentrating to +within $0.003$ across noise draws, so \eqref{eq:policyfp16} is a safety net rather than an active +constraint: every adversarial construction tested also passes it, the worst observed being +$f_{\text{bp}}=0.357$, $\rho=1.38$ (Appendix~\ref{app:validation}). Because the check is a density +gate over the whole tile, honest tiles do not fail on fluctuations, and because it concentrates, +grinding noise draws yields no advantage on honest-like data. \textsf{BF16} does not admit a +separating threshold of this form at $k\le 1024$ (Section~\ref{sec:compare}); the \FP{16} +thresholds \eqref{eq:policyfp16} apply only to the \FP{16} $\Quant$ value. + +\section{Attack vectors}\label{sec:attacks} + +\paragraph{Low-rank inputs.} A miner may choose low-rank $A,B$ so that $S_{ij}$ is cheap. This is +allowed; hardness does not depend on the exact sum being hard. By \eqref{eq:decomp} the device +output still requires the per-product corrections, which are non-contractible. + +\paragraph{Truncation / bit-slice correction.} The corrections $\rho_u$ are shallow (median +$\sim\!4$ discarded bits per \FP{16} product), which suggests batching them on binary or int8 +tensor cores via bit-planes. This fails for the structural reason of Section~\ref{sec:hardness}: +bit-planes accelerate \emph{contractions}, and the correction is not a contraction. Even granting +the adversary free exact prefix sums and a free oracle for which steps are breakpoints, the +corrections must be evaluated elementwise on CUDA cores, costing $6\text{--}13\times$ honest work +under compute-bound-optimistic accounting and far more when memory-bound +(Appendix~\ref{app:validation}). + +\paragraph{Exact-sum shortcut.} Computing $\RZ_{\FP{32}}(S_{ij})$ and returning it reproduces the +device output in a negligible fraction of cells ($\le 1.6\%$ in all \FP{16} tests), because the +per-product truncation changes almost every cell. + +\paragraph{Minimizing truncation.} The miner may seek operands with flat exponents or few +significant bits to reduce $f_{\text{bp}}$. For \FP{16} this is self-defeating: the mandated noise +(rank $r=32$, relative scale $\delta=1/2$) spreads product exponents enough that truncation +remains dense, and the policy \eqref{eq:policyfp16} rejects any tile that nonetheless falls into a +low-truncation regime. For \textsf{BF16} the same strategy succeeds, which is why \textsf{BF16} is +excluded (Section~\ref{sec:compare}). + +\paragraph{Device emulation and ASICs.} Reproducing A100 accumulation on another GPU requires +emulating the $G=8$ grouping and per-product truncation, which that device's tensor cores cannot +do cheaply; it must fall back to the same elementwise path as any attacker. A custom ASIC could +implement the per-product correction more cheaply than a full \FP{16} multiplier, so the argument +is against commodity GPUs, not arbitrary silicon; this is the same economic question raised +for the \FP{8} scheme and in the Pearl open-problems note. + +\paragraph{Seed and commitment grinding.} The noise is seed-derived after commitment; grinding +seeds only yields additional lottery tickets, bounded by the usual Fiat--Shamir argument. + +\section{Honest miner overview}\label{sec:miner} + +The intended miner mines with \FP{16} multiplications it wants computed anyway. +\begin{enumerate}[nosep] +\item \textbf{Prequantize.} Encode $A,B$ in the \FP{16} commit format (Appendix~\ref{app:commit}). +\item \textbf{Commit.} Hash $B$ under a recent header and derive $\texttt{noise\_seed}_B$; commit + $A$ under the proposed header and derive $\texttt{noise\_seed}_A$. +\item \textbf{Noise and quantize.} Derive the rank-$r$ noise and compute + $\At=\NoisyQuantize(A,\dots)$, $\Bt=\NoisyQuantize(B,\dots)$ in $O((m+n)kr)$ MACs + (Appendix~\ref{app:noise}). +\item \textbf{Multiply.} Run the A100 \FP{16} kernel once on the noised operands---$mnk$ MACs, the + dominant cost, identical to the kernel the job would run without the protocol. +\item \textbf{Scan for winners.} Cut the output into tiles, compute $\Extract$ and the jackpot + hash per tile, and compare against the scaled target. +\item \textbf{Open on a win.} For a winning tile admitted by the policy, assemble the proof. +\end{enumerate} +Recovering the useful product costs the low-rank correction plus the $O((mn+mk+nk)r)$ overhead of +hashing, noising and scanning, for a $1+o(1)$ total overhead when $m,n,k\gg r$. The recovered +product carries \FP{16}-level accuracy: the device truncation that secures the tile is of the same +order as---and is reconstructed together with---the quantization error, so no accuracy beyond +ordinary \FP{16} rounding is sacrificed. Critically, the miner's kernel must use the committed +instruction order with no split-$k$ or atomic accumulation, since any reordering changes the +bit-exact output (Appendix~\ref{app:arith}). + +\section{FP16 vs.\ FP8 vs.\ BF16}\label{sec:compare} + +\paragraph{Why \FP{16} works.} \FP{16} products carry $22$ significant bits against the $24$-bit +accumulator window, so truncation is dense and, crucially, insensitive to the miner's choices: +across all tested strategies $f_{\text{bp}}\in[0.36,0.51]$. The non-contractibility argument then +applies with a wide margin. + +\paragraph{Why \textsf{BF16} does not.} \textsf{BF16} products carry only $16$ bits and fit inside +the $24$-bit window unless more than $8$ binades below $\eta$. Flat rank-one sign-pattern operands +leave $>\!99\%$ of products exact and only $6\text{--}8\%$ of steps as breakpoints; a groupwise +model without per-product truncation already reproduces more than half the outputs, and the +certified-work ratio falls to $\rho\approx 0.30$. These operands pass the liveness and noise-floor +checks. Honest \textsf{BF16} is itself marginal ($\rho\in[0.84,1.10]$ at $k=1024$), so no +threshold separates honest from adversarial \textsf{BF16} with margin. \textsf{BF16} mining, if +desired, requires either \FP{16} storage, $k\ge 4096$, or a larger noise rank; this document does +not specify it. + +\paragraph{Relation to \FP{8}.} The \FP{8} scheme remains the cheapest option and its hardness +margin is ample; it is preferred for workloads tolerant of \FP{8}-residual accuracy. \FP{16} +trades a modest constant factor (denser truncation to reconstruct, a slightly larger proof) for +\FP{16}-level output accuracy and a hardness source independent of the rounding grid. A deployment +may offer both $\Quant$ values and weight their targets so that each is mined at its true device +throughput; the economics mirror the \FP{8} discussion in~\cite{PearlFP8}. + +\appendix + +\section{A100 arithmetic specification}\label{app:arith} +Element-wise \FP{16}/\textsf{BF16}/\FP{32} operations follow IEEE-754-2019 with the roundings +used by the device: casts to \FP{16} round to nearest even and saturate per the format; the +matrix-multiply accumulation is specified in Section~\ref{sec:device}. The verifier rejects NaN +and infinity in operands and in every intermediate, applying the test after rounding. The A100 +accumulator keeps $W=24$ significant bits (no sub-\FP{32} truncation at the accumulator level, +unlike the Hopper/Blackwell \FP{8} paths of~\cite{PearlFP8}); the nonlinearity is entirely in the +per-product, per-group truncation of Section~\ref{sec:device}. The \texttt{m16n8k8} instruction is +identical to \texttt{m16n8k16} with $G=8$; the \FP{16}-accumulate variant (\texttt{HMMA.16816.F16}) +uses the same grouping and truncation followed by round-to-nearest-even to \FP{16} per group and is +not used by this scheme. + +\section{FP16 commit type}\label{app:commit} +An operand with $n$ rows is committed as a single matrix $V\in\FP{16}^{n\times k}$, each row a +Merkle leaf-set under the key and hash identifier of the main protocol, with aggregate root $H_X$. +Unlike the \FP{8} FP10 commit (int8 values plus a block scale), the \FP{16} format stores values +directly, since \FP{16} already carries the target precision; no block scale is required. Row norms +$\ell_2(X_t),\ell_\infty(X_t)$, used by the noisy-quantization scales, are computed from $V$ in +\FP{32} and floored as in~\cite{PearlFP8}. + +\section{Noise and noisy quantization}\label{app:noise} +The noise sampler, seed chain, and rank-$r$ construction $N=EF^\T$ are those of the \FP{8} +specification, with $r=32$ and per-row relative scale $\delta=1/2$. Noisy quantization computes, +per row, $\At_t=\RNE_{\FP{16}}(\alpha_t X_t+\beta_t N_t)$ with the scales $\alpha_t,\beta_t$ chosen +so the noise carries relative Euclidean weight $\delta$; the clamp and norm-floor rules follow +Appendix~C.4 of~\cite{PearlFP8} with target magnitude $Q$ set to the largest finite \FP{16} value +$65504$. Because \FP{16} is the target precision, $\alpha_t$ performs only range normalization and +the recovered product retains \FP{16} accuracy after the low-rank correction. + +\section{Certified-work ratio}\label{app:rho} +The ratio $\rho$ of Section~\ref{sec:policy} is an attacker-favorable lower bound on the cost of +reconstructing a tile under the following generous premises: (i) exact prefix sums over any +$k$-range cost $r$ MAC-equivalents per cell via the low-rank structure; (ii) a run of consecutive +non-breakpoint steps can be merged at cost $r$ plus one per truncated product; (iii) each +breakpoint step costs $\min(G,r)=G$ to resolve its discarded low bits from the previous exact +state; (iv) the breakpoint locations are supplied for free by an oracle. Summing gives the +per-cell cost $G\,N_{\text{bp}}+r\,N_{\text{run}}+N_{\text{pt}}$ used in the definition, normalized +by the honest $k$. Premises (i)--(iv) overstate the attacker's power---in particular, quantization +makes the operands only approximately low rank---so a measured $\rho\ge 1.2$ is a conservative +certificate that no such shortcut beats honest work. + +\section{Empirical validation}\label{app:validation} +All experiments were run on A100-class (GA100, sm\_80) silicon. The accumulation model of +Section~\ref{sec:device} matched the hardware bit-for-bit on $>1.1\times10^6$ random dot products +per device (both devices agreeing), on $69$ directed edge-case scenarios totaling $6.9\times10^6$ +dot products (subnormal inputs and accumulators, exact cancellation, mixed signs, grid-boundary +products, partial and empty groups, $k=2048$ chains, overflow, infinity, NaN, and $0\cdot\infty$), +and on the adversarial and realistic noised operands below. One residual is known: \textsf{BF16} +chains whose partial sums remain entirely in the \FP{32}-subnormal range can be off by one +subnormal ulp in $<\!1\%$ of outputs; this cannot occur for \FP{16} or for $O(1)$-scaled operands +and is excluded by policy. + +Adversarial study (tiles $16\times16$, $k=1024$, $r=32$, $\delta=1/2$, operands row-scaled to unit +max magnitude): sixteen input strategies---realistic Gaussian with outlier channels, heavy-tailed, +$A=B=0$, rank-two, several flat and few-bit constructions designed to minimize truncation, sparse, +spiked, and geometric---all kept \FP{16} at $f_{\text{bp}}\in[0.36,0.51]$ and $\rho\ge 1.38$, with +the cheapest shortcut predictors reproducing $\le 1.6\%$ of cells (one geometric case $13\%$, still +$\rho=1.68$). The same strategies drive \textsf{BF16} to $f_{\text{bp}}$ as low as $0.06$ and +$\rho\approx 0.30$. The truncation-correction attack, costed end-to-end, is $6\text{--}13\times$ +honest (compute-bound-optimistic) and $220\text{--}470\times$ (measured, memory-bound), because the +per-product corrections cannot use tensor cores. + +\paragraph{Reproducible harness.} A self-contained harness is committed alongside this +specification at \texttt{docs/fp16\_scheme/validation/} (it links only the CUDA runtime, so it runs +on an \texttt{sm\_80} box without the miner's Python stack). On \textsf{A100}-class silicon +(validated on a GA100 \texttt{sm\_80} device) it: +(i) captures the output of the real \texttt{mma.sync.m16n8k16.f32.f16} and checks the model of +Section~\ref{sec:device} against the device \emph{bit-for-bit} over $910$ dot products---the $238$ +committed reference vectors plus $272$ generated edge cases ($k$ up to $1024$, subnormal operands, +subnormal accumulators, subnormal outputs, near-total cancellation, grid-boundary, and +max-magnitude)---with zero mismatches, so the model is validated against the device rather than +against another copy of itself; +(ii) resolves the rounding mode on silicon, \emph{confirming round-toward-zero} at both the +per-product alignment and the per-group \FP{32} encode: the device matches the \RZ model on all +$400$ vectors constructed to separate \RZ from round-to-nearest-even, while each RNE variant +disagrees with the device on a large fraction of them; +(iii) recomputes the policy metrics $f_{\text{bp}},\rho$ and the shortcut-predictor rates over the +adversarial strategies, through both an independent noise implementation and the exact consensus +noise pipeline, reproducing the regime above ($f_{\text{bp}}\in[0.45,0.52]$, +$\rho\in[1.67,1.94]$, cheapest shortcut $\le 1.6\%$); and +(iv) micro-benchmarks the truncation-correction attack against the honest tensor-core \FP{16} GEMM +(the miner's own kernel), measuring $\approx 38\text{--}43\times$ honest on this silicon even when +the attacker is granted the exact sums and the breakpoint oracle for free---consistent with the +accounting of Section~\ref{sec:attacks}. The model-vs-silicon corpus is enforced in CI by the Rust +test \texttt{api::fp16::accumulate::matches\_hardware\_capture\_k1024}; the overflow guard was never +triggered, confirming that a single \FP{16} dot product cannot overflow. + +\begin{thebibliography}{9} +\bibitem{KW25} I.~Komargodski and O.~Weinstein. \emph{Proofs of Useful Work from Arbitrary Matrix +Multiplication}. arXiv:2504.09971; IACR ePrint 2025/685, 2025. +\bibitem{PearlFP8} Pearl Research Team. \emph{Pearl Floating Point Scheme Specification} +(FP8 certificate-v4), September 2026. +\bibitem{Hawkeye} E.~Badash, D.~Boneh, I.~Komargodski, and M.~Srivastava. \emph{Hawkeye: +Reproducing GPU-level Non-determinism}. arXiv:2603.20421, 2026. +\bibitem{BLAKE3} J.~O'Connor, J.-P.~Aumasson, S.~Neves, and Z.~Wilcox-O'Hearn. \emph{BLAKE3: +one function, fast everywhere}, 2020. +\end{thebibliography} + +\end{document} diff --git a/docs/fp16_scheme/stark_feasibility.md b/docs/fp16_scheme/stark_feasibility.md new file mode 100644 index 000000000..f25a1aa4a --- /dev/null +++ b/docs/fp16_scheme/stark_feasibility.md @@ -0,0 +1,396 @@ +# FP16 / A100 matmul STARK — feasibility analysis (Stage 3, Task 1) + +Status: **GO-WITH-CHANGES**. A `matmul_a100` STARK that proves the device tile +equals `api::fp16::accumulate::a100_matmul` is provable under the plonky2/starky +batched-FRI framework used by the FP8 schemes, with two required design changes +relative to the B200 fork (below). The Goldilocks field and the degree-≤3 budget +hold with wide margin; the only genuine scaling pressure is **trace height** +(G = 8 ⇒ 4× the B200 row count), which the "groups-per-row" packing in §4 tames. + +The numbers below were derived against the frozen ground truth +`zk-pow/src/api/fp16/{accumulate.rs,dtype.rs,params.rs}` and the 238 +GPU-validated vectors in `testdata/a100_dot_vectors.txt`. + +--- + +## 1. The arithmetic to prove (one G = 8 group step) + +From `a100_dot`, for incoming FP32 accumulator `c` decomposed as +`value = s_c · cm · 2^(el−23)` (`acc_parts`: `el = exp−127` for normal, +`el = −126`, `cm = mantissa` for subnormal, `cm = 0` for zero): + +* each lane `u` decodes its FP16 operands (`decompose_fp16`) to + `(sign, m, eps)`, `value = sign·m·2^(eps−10)`, `m ∈ [0, 2047]` (11-bit), + `eps ∈ [−14, 15]`; the product has significand `P = m_a·m_b` and stored + exponent sum `e_u = ea + eb`; +* `eta = max( e_u over nonzero products, el if c ≠ 0 )`; `unit = eta − 24`; +* every product is truncated toward zero onto the `2^unit` grid: + `term_u = ±⌊P·2^(e_u−20) / 2^unit⌋ = ±⌊P·16 / 2^(eta−e_u)⌋`; +* the accumulator similarly: `term_c = ±⌊2·cm / 2^(eta−el)⌋` + (uniform: value `= cm·2^(el−23)` for both normal **and** subnormal, since + subnormal has `el = −126`, `el−23 = −149`); +* `sum = Σ term_u + term_c` exactly (signed integer); +* `new = rz_to_f32(sum, unit)` — round toward zero to FP32. + +The `PolicyStep` census per group: `nonempty`, `breakpoint` +(accumulator-alignment drop **or** RZ drop), `products_truncated` +(count of lanes whose right-shift discarded a nonzero bit). + +## 2. Field and range budget — PASS, wide margin + +Goldilocks `p = 2^64 − 2^32 + 1 ≈ 2^63.9999`. + +| quantity | bound | note | +|---|---|---| +| product significand `P = m_a·m_b` | `< 2047² < 2^22` | one degree-2 multiply | +| `e_u = ea + eb` | `[−28, 30]` (59 values) | biased to stay ≥ 0 | +| accumulator exponent `el` | `[−126, 127]` | f32, overflow aborts | +| `eta = max(e_u, el)` | `[−126, 127]` | window anchor | +| product left-shift `e_u − eta + 4` | `≤ 4` | `eta ≥ e_u` for nonzero lanes | +| aligned product term `⌊P·16 / 2^rel⌋` | `< 2^26` | `rel = eta − e_u ≥ 0` | +| aligned accumulator term `⌊2·cm / 2^rel_c⌋` | `< 2^25` | `rel_c = eta − el ≥ 0` | +| group sum `Σ` (8 terms + carry) | `< 8·2^26 + 2^25 < 2^30` | **fits i64, fits field** | +| Euclidean check `quotient·2^rel` | `< 2^26 · 2^26 = 2^52 < p` | integer-exact over 𝔽 | + +The aligned group sum is < 2^30, so the entire signed window sum fits a single +field element (B200 needs the same < 2^32 claim). **FP16's larger exponent span +does *not* blow the field**: the span only widens the *relative shift* `rel`, and +because the pre-shift operands are tiny (`P·16 < 2^26`, `2·cm < 2^25`) **any** +`rel ≥ 26` truncates the term to exactly 0. So the alignment power-of-two table +caps at `2^26` (27 keys, `rel ∈ [0, 26]`), identical in spirit to B200's +`CARRY_SHIFT_CAP = 26`. The shift *range checks* are therefore the same size as +B200's; the span costs nothing. + +## 3. Degree budget — PASS + +* **product** `P = m_a·m_b`: degree 2. +* **eta attainment chain** (the "`≤`" side of the max, B200's MB3 technique): + 9 affine factors (8 lanes + carry). Degree-3 links take 3 factors in the + first link then 2 per link ⇒ **`NUM_ATT_LINKS = 4`** (vs B200's 16 for 33 + factors). Chain-closing with the zero-gated carry factor is degree 3. +* **per-lane Euclidean truncation** `P·16 = q·2^rel + r`, `0 ≤ r < 2^rel`: + degree 2 (`q·2^rel`), two-sided by the remainder/bound RC identity — same as + B200 MB5. +* **RZ encode** (width `W`, truncation/lifting powers via a WIDTH LUT, Euclidean + normalize into `[2^23, 2^24)`): degree 2 — same as B200 MB7. + +`constraint_degree() = 3`, exactly B200. + +## 4. Trace height — the one real cost; GO-WITH-CHANGES + +`rows_per_cell = k / G = k / 8`, `live_rows = h·w·k/8`. + +Under the whitepaper bounds (`params.rs::validate`): `h·w ∈ [256, 2048]`, +`k·(h+w) ≤ 2^22`, `k` a multiple of 8. Maximising `h·w·k`: + +* **worst case** `(h, w, k) = (45, 45, 46600)` → `live_rows ≈ 1.18·10^7 = 2^23.49`, + padded to **`2^24 = 16.8 M` rows**. +* B200 analogue (`/32`) peaks at `2^21.49` → `2^22`. So A100 is the expected **4×**. +* typical tile `(4, 64, 256)` → `live_rows = 8192 = 2^13` (tiny; test-friendly). + +A 2^24-row trace at ~300 columns is ~40 GB of LDE at blow-up 2 — provable on a +large prover but memory-heavy. **Recommended change:** pack `G_ROW` consecutive +G = 8 groups per trace row (chaining the carry *within* the row). `G_ROW = 4` +restores B200-class height (`≤ 2^22`) at ~4× columns, keeping the FRI instance in +the ladder the batch driver already uses; the per-row arithmetic is 4 independent +copies of §1 with the row-internal carry wired from copy `i` to copy `i+1`. This +is a mechanical extension of the single-group AIR delivered in Task 2 and is left +as the documented production step. For the deliverable AIR and all test geometries +(`k ≤ 256`), one group per row is used — correct and well within height limits. + +## 5. The two required changes vs. the B200 fork + +1. **No operand-keyed product LUT.** B200's `B200ALIGN` looks the *entire* aligned + lane term up from the packed operand byte-pair (`2^16` keys). FP16 operand pairs + span `2^32` — a lookup keyed on raw codes is impossible. Instead: + * an **`FP16DECODE` LUT** keyed on the 16-bit code (`2^16` rows, same order as + RC16) returns `(sign, m, eps_biased, is_zero)` per *single* operand + (2 lookups/lane); + * the product significand `P = m_a·m_b` is an **in-AIR degree-2 multiply**; + * alignment is an **in-AIR Euclidean floor** against a `POW2` LUT (`rel ↦ + 2^min(rel,26)`), exactly like B200's carry alignment, applied per lane. + + This is strictly more in-AIR arithmetic than B200 but uses only LUTs of + feasible size (`2^16` decode, `27`-key pow2, `2^16` RC16). + +2. **Groups-per-row packing** for large tiles (§4). + +Everything else (attainment max, signed sum recovery, RZ via width LUT, f32 +encode, cell/padding structure, census columns, CTL channel shape) forks B200 +directly. + +## 6. Column layout to build (one group per row) + +Structural (class a, verifier-recomputable): `cell_id`, `is_cell_final`, +`operand_index_base_a/b`, `is_padding`. (5) + +Per lane × 8: `operand_codes_a/b`, decoded `sig_a/b`, `eps_biased_a/b`, +`is_zero`, product `product_sig`, `product_biased_exp`, `sign`, aligned +`aligned_term`, `shift_power`, `rem_lo/hi`, `rem_bound_lo/hi`, +`products_truncated_flag`. (~16/lane) + +Accumulator alignment: `incoming_carry_is_zero`, `carry_shift_power`, +`aligned_carry_lo/hi`, `carry_rem_lo/hi`, `carry_rem_bound_lo/hi`. (~8, reads +previous row's `out_sign/out_sig/out_exp` as carry, no copy columns — B200 +pattern) + +Window max + sum + RZ: `group_max_biased_exponent`, `max_exponent_attainment[4]`, +`group_sum_sign`, `group_sum_abs`, `group_sum_is_zero`, `group_sum_width`, +`truncation_power`, `lifting_power`, `norm_sig_lo/hi`, `trunc_rem`, +`trunc_rem_bound`, `out_sign`, `out_biased_exp`, `out_sig`. (~18) + +Output + census: `cell_result_f32_lo/hi`, `group_nonempty`, `group_breakpoint`, +`cell_products_truncated` (running). (~5) + +≈ **250–300 columns**, comparable to B200's 304. + +## 7. Verdict + +**GO-WITH-CHANGES.** Build the single-group AIR with the FP16DECODE+POW2+WIDTH+RC16 +LUT family and the B200-style attainment/sum/RZ constraints; pack 4 groups/row for +production-size tiles. No field or degree obstruction exists. The dominant risk is +engineering surface area (per-lane in-AIR decode+multiply+align replaces one LUT), +not provability. + +### Scoping notes honoured by the Task 2 implementation + +* The 238 reference outputs are **237 normal + 1 zero, no subnormals, no + overflow** (output exponents `[−21, 31]`). The delivered AIR fully constrains + the **normal and zero** output paths — complete coverage of the validated + corpus. **Subnormal FP32 outputs** (value `< 2^−126`, reachable only by + adversarial near-total cancellation to `2^−126`) use a distinct RZ encode + branch; it is implemented bit-exactly in the trace generator and flagged, but + its *constraints* remain a documented follow-on. + +--- + +## 8. Stage-3 soundness hardening — what is now enforced + +Three soundness gaps flagged above have been closed (commits on `fp16-scheme`): + +### Gap 2 — census tightness (CLOSED) + +`products_truncated_flag`, `carry_dropped`, `rz_dropped` are each pinned to +`[rem != 0]` of their Euclidean remainder (clean `(1-flag)*rem = 0` **and** tight +`flag*(rem*inv - 1) = 0` via per-lane/per-witness inverse columns), with the +inert-branch remainders killed (`incoming_carry_is_zero*carry_rem = 0`, +`z*trunc_rem = 0`). `group_breakpoint` is then pinned bit-exactly to +`group_nonempty * (carry_dropped OR rz_dropped)` (MA11) — the exact `a100_dot` +breakpoint. Because the census only ever *raises* the certified-work ratio, this +is what stops a prover overstating `rho`/`f_bp`. Negative test: +`inflated_census_breaks_constraints`. + +### Gap 1 — LUT/CTL wiring (CLOSED, including limb ranges) + +The matmul AIR's semantic auxiliary columns are now served by committed LUTs via +cross-table lookups, so the STARK's own verification (the CTL multiset balance) +enforces them — no blind trust: + +| table | keys | values | pins | +|---|---|---|---| +| **FP16DECODE** (`2^16`) ×16 | operand code | `(sig, sign, eps_biased, is_zero)` | the per-operand decode MA1 derives each lane's product/sign/exponent from | +| **FP16POW2** (`2^min(d,26)`, `d∈[0,255]`) ×9 | `group_max − product_biased_exp` (8 lanes + carry) | `shift_power` | the alignment divisor; the key domain also proves the eta `≥` side | +| **WIDTH32** (`[1,32]`) ×1 | `group_sum_width` | `(2^max(W−24,0), 2^max(24−W,0))` | the RZ truncate/lift powers + width range | +| **RANGE16** ×60 | `cell_result_f32_lo/hi`; MA12 floor-witness limbs; RZ `trunc_rem`/`trunc_rem_bound` | — | the FP32 result limbs **and** the limb-range splits below | + +`FP16DECODE`/`FP16POW2` are new `LutStark` variants (reusing the FP8 LUT +machinery) that no FP8 device commits, so the FP8 consensus layout is untouched; +`RANGE16`/`WIDTH32` are the FP8 tables reused directly. The FP16 batch and its +`CrossTableLookup` set are in `circuit::fp16::ctl`. Tests: the honest batch +serves every instance (`LutChecker`) and balances every channel (`check_ctls`); +forged decode/shift/width/exponent columns are rejected by the committed tables, +and a tampered matmul value unbalances a channel +(`forged_auxiliary_columns_are_rejected_by_the_luts`). + +**Limb ranges (CLOSED — MA12).** The per-lane and carry Euclidean +remainders/quotients (`aligned_mag`, `lane_rem`, `lane_rem_bound` per lane; +`aligned_carry`, `carry_rem`, `carry_rem_bound`; the RZ `norm_sig`) now carry +`lo`/`hi` limb columns. MA12 pins `value = lo + 2^16·hi` (degree 1), and the +committed-LUT inventory `RANGE16`-checks `lo < 2^16` and `2^6·hi < 2^16` (so +`hi < 2^10`, bounding the magnitude by `~2^26`); the RZ `trunc_rem` / +`trunc_rem_bound` (`< TRUNCATION_POWER ≤ 2^6`) are `RANGE16`-checked directly. +A wrapped quotient/remainder has no valid 16/10-bit limb witness, so no field +element `q ≥ 2^26` can alias an alignment/normalization `floor` — the identities +are integer-exact under a real FRI proof. The matmul RANGE16 inventory grows +`2 → 60` (56 limb checks + 2 result limbs + 2 RZ-remainder checks; 86 matmul LUT +instances total). Negative tests: an out-of-range `hi` limb (a field-fraction +alias) is rejected by `RANGE16` +(`forged_auxiliary_columns_are_rejected_by_the_luts`), and bumping a limb breaks +MA12's reconstruction (`tampered_cells_break_constraints`). + +### Gap 3 — rho / breakpoint-density policy AIR (CLOSED) + +`circuit::fp16::policy_stark` enforces the exact `api::fp16::policy` gate over the +per-group census: a run-start detector for `N_runs`, tile-global inclusive +accumulators for the breakpoint count and the numerator +`sum[ 8·N_bp + 32·N_runs + N_pt ]`, and a division-free last-row gate +`5·numerator ≥ 6·cells·k` (⇔ `rho ≥ 1.2`) and +`10·breakpoints ≥ 3·total_steps` (⇔ `f_bp ≥ 0.30`), each witnessed by a +nonnegative slack whose 16-bit limbs are `RANGE16`-checked (so a sub-threshold +tile has no valid nonnegative witness). The AIR's gate decision and running +totals equal `policy::evaluate` on every reference-vector tile (accept and reject +both covered); flat tiles and tampered gate witnesses fail. Its per-step census +columns are bound to the matmul's tight census by a `matmul → policy` +census-import CTL (CLOSED — see below). + +### Gap 3 linkage + batched-FRI driver (CLOSED) + +The `matmul → policy` **census-import CTL** (`circuit::fp16::ctl::census_import_ctl`) +links the two main tables: the matmul exports, per live group step, the tuple +`(operand_index_base_a, operand_index_base_b, group_breakpoint, +Σ products_truncated_flag)`; the policy imports the same tuple. The +`(base_a, base_b)` pair is unique per live row (`base_a` fixes `(r, j)`, +`base_b` fixes `(c, j)`), so the multiset equality forces the policy's per-step +census to equal the matmul's tightly-pinned one bit-for-bit — the policy can no +longer score a census different from the one the matmul proved. Both sides are +filtered to live rows. (Two `operand_index_base_*` columns were added to the +policy class-(a) layout to carry the key.) Negative test: +`forged_policy_census_breaks_the_import_channel`. + +The **batched-FRI driver** `circuit::fp16::driver::Fp16System` batches the matmul +AIR, the policy AIR, and the four committed LUTs (`FP16DECODE`, `RANGE16`, +`FP16POW2`, `WIDTH32`) under one `batch_prove` / `batch_verify` with the full +`CrossTableLookup` set (four LUT channels + census import). Canonical table order +matmul (0), policy (1), LUTs (2..6); the LUT precommitment is built at a Merkle +cap (`Fp16System::preprocessed_data`); the two main tables' class-(a) columns are +recomputed by the verifier and the trace openings bound to them; the FRI ladder +covers the job's distinct heights. End-to-end test +`batched_fp16_proof_roundtrips_and_rejects_tampering`: an honest 2×2 tile proves +and verifies, and a tampered trace cell, a forged per-step census value, a forged +decode column, and a mismatched statement are all rejected (~2.5 s). The +channel-balance analogue is `one_fp16_job_balances_every_ctl_channel`. + +### Entry-liveness + noise-floor shared gates (CLOSED) + +The whitepaper's §"Shared checks" (the FP8 entry-liveness and noise-floor gates that bound +degenerate operands) are now enforced for the ZK path: + +* **Noise floor (`sigma_i = DELTA*alpha_i*l2_i >= 1`) — implied, no constraint.** The scale + derivation forces `alpha_i = Q/(linf_i + DELTA*sqrt(r)*l2_i)` with `linf_i <= sqrt(k)*l2_i`, so + `sigma_i >= DELTA*Q/(sqrt(k) + DELTA*sqrt(r)) >= ~16` for every `k <= 2^22`. Because + `row_scale_stark` already *constrains* `alpha` to that derived value, a sub-floor `sigma` has no + valid witness. Machine-checked by `api::fp16::policy::tests::shared_gates:: + noise_floor_is_implied_by_honest_derivation`. +* **Entry liveness (`|D_X| <= eps_idle*|I_X|*k`, `eps_idle = 1/64`) — enforced in-circuit + (`row_scale_stark`, group L).** Per element a `dead = [ |x| >= 4*l2 ]` flag is pinned by an exact + integer aligned compare (`|x| = x_sig*2^(x_eps_biased-25)` vs `4*l2 = (128+l2_m)*2^(l2_e-132)`, + shift via FP16POW2 with a sound 2^26 saturation, two-sided RANGE16 slack). Two side-masked + inclusive accumulators (`dead_run_a/b`) and a division-free last-row gate + `64*dead_side <= rows_side*k` (nonnegative RANGE16 slack) make a spike-dominated tile + unsatisfiable. `num_a_rows` (`h`) is an AIR compile-time constant (like `k`), so no known column + / public input / wrapper-PI change — the header-bound consensus verifier is untouched. All AIRs + stay degree <= 3. Tests: `row_scale_stark::stark::tests::{liveness_gate_matches_check_shared_gates, + tampered_liveness_witnesses_break_constraints}` (bit-exact accept/reject vs + `api::fp16::policy::check_shared_gates`, plus fail-closed tampers), and the honest batch still + balances every CTL channel and proves/verifies. + +### Subnormal FP32-output RZ branch (CLOSED — MA13) + +The per-group round-toward-zero to FP32 now constrains the **subnormal-output** +branch (`|x| < 2^-126`): `circuit::fp16::matmul_a100_stark` MA13 writes the +`2^-149`-grid encode — exponent field 0, mantissa `OUT_SIG = NORM_SIG >> k` with +`k = 1 - raw` (`raw = GROUP_MAX_BIASED_EXPONENT + W - 25`) — gated by an +`out_is_subnormal` flag that MA13 pins to `[raw <= 0]` via a nonnegative RANGE16 +`exp_slack` witness (so neither over- nor under-claiming the subnormal regime has +a valid witness). `SUB_SHIFT_POWER = 2^k` is FP16POW2-bound (subnormal-filtered) +and the mantissa is RANGE16 limb-reconstructed, so `OUT_SIG` is a genuine `< 2^23` +integer; MA8/MA9 mux the exponent / significand / encode residue on the flag. The +generator computes the branch bit-exactly (the old `unimplemented!`/panic guard is +gone; the two remaining `debug_assert!`s in this branch are release-stripped +correctness invariants, not the soundness check — that is MA13's constraints). + +The from-zero matmul statement never *reaches* the branch — FP16 products align at +`eta >= 99`, so a group output floors at `~2^-52`, and the carry model forbids a +cell-start carry-in — so MA13 is a **sound guard** there; the branch is the +bit-exact encode for the accumulation datapath (subnormal FP32 carry-in) that the +oracle `a100_dot` already models. Tests: `subnormal_output_is_bit_exact_and_ +satisfies_ma13` (generator == `a100_dot` for a spread of FP32 subnormals, and the +committed columns satisfy the MA13/MA8/MA9 relations) and +`forged_subnormal_claim_is_rejected` (honest traces never set the flag; a forged +flag / subnormal encode is rejected). All AIRs stay degree <= 3, and +`circuit_constraints_match_native` holds. + +### Recursive FRI wrapper (DELIVERED per-shape; universal variant deferred) + +`circuit::fp16::wrapper` compresses the `Fp16System` batch proof to a constant-size +recursive plonky2 proof via a two-stage wrapper mirroring the FP8 structure: stage +1 (`PoseidonGoldilocksConfig`, no ZK) runs starky's in-circuit batch verifier +(`verify_batch_stark_proof_circuit`) over all six tables — every AIR, the four +committed-LUT channels + the census-import CTL, the baked-in LUT cap and the +batched FRI — and exposes the Fiat-Shamir `zeta`, the statement digest and the +class-(a) known-column evaluations as public inputs; stage 2 +(`Blake3GoldilocksConfig`, `zero_knowledge: true`) verifies stage 1 and republishes +them. The native gateway `verify_wrapped_proof` pins every slot — the digest to the +statement, the known-column evals to its own recompute at `zeta` — giving the same +guarantees as `Fp16System::verify`. The driver gained the consensus fold ladder, +the committed-LUT grouping (`FP16_GROUPED_TABLES`), the statement-digest binding and +the universal envelope needed by the wrapper paths. Test +`wrapped_fp16_proof_verifies_and_rejects_tampering`: an honest tile wraps and +verifies; the **wrapped proof length is constant (71 486 bytes) across two tile +sizes** (`2x3` and `3x3`, main tables `2^4` vs `2^5`, both compiling stage-1 to +`2^15`); a wrong statement digest and any tampered public-input slot are rejected. + +* **Universal (one-circuit-for-all-sizes) wrapper — deferred.** FP8 compiles a + single circuit for every envelope-legal job via + `starky::batch_universal::verify_universal_batch_stark_proof_circuit`; the FP16 + driver already ships the consensus ladder, envelope and digest machinery that + path needs (`fp16_universal_envelope`), but the universal verifier + over-determines a witness wire (`set twice`) for FP16's table shape — two + **equal-height** variable main tables (matmul and policy share one row grid) + linked by a direct CTL (census-import), a configuration FP8 never produces (its + variable tables always differ in height) and the universal verifier's own tests + do not cover. The fix is in `plonky2/starky/src/batch_universal.rs`, shared with + FP8's wrapper, so it is left as the residual. The per-shape wrapper above already + delivers a constant-size, verifiable, tamper-rejecting recursive proof; the + universal variant only removes the per-shape circuit compilation. + +--- + +## 9. Soundness fix + consensus-binding status (operand + output + header bindings CLOSED) + +**NORM_SIG normalized-range pin (FIXED).** The matmul AIR originally bounded the +normalized significand `NORM_SIG` only by the MA12 limb split (`< 2^26`), dropping +the FP8/B200 MB7 check that forces it into `[2^23, 2^24)`. Without that range the +MA7 width identity `GROUP_SUM_ABS·L = NORM_SIG·T + TRUNC_REM` admits *any* +`GROUP_SUM_WIDTH` for a given sum magnitude, so a prover could pick a false width, +choose `TRUNC_REM != 0`, and forge `RZ_DROPPED` (MA11) → `GROUP_BREAKPOINT` → the +jackpot census (`f_bp`/`rho`) — defeating the whole "unpredictable accumulation +steps" gate (a flat/cheap tile made to clear `f_bp ≥ 0.30, rho ≥ 1.2`). Now closed +by a committed-RANGE16 check `(NORM_SIG_HI − 128)·2^9 < 2^16` filtered to +nonzero-sum rows (`matmul_a100_stark::ctl`), mirroring B200. This also makes +`NORM_SIG < 2^24`, which closes the latent MA13 subnormal `OUT_SIG < 2^23` claim. +Regression: `circuit::fp16::ctl::forged_norm_sig_width_is_rejected_by_the_normalized_range`. + +**Status update — all three bindings below are now CLOSED, and the header-bound +ZK certificate is the wired consensus path (the plaintext certificate is +retired).** When first written this section listed two open gaps and a header +residual; all are now bound and tested (`zk_binding_design.md §8/§8b`): + +1. **Operand commitment / provenance — CLOSED.** `operand_codes_a/b` are now tied + to the committed operand Merkle roots (`HASH_A`/`HASH_B`) through the + raw→noised→matmul-operand CTL chain, carrying the `w`/`h` reuse multiplicity + that forces cross-cell row/column sharing (`circuit::fp16::blake3_commit`, + `noisy_quant_stark`, `ctl`). +2. **Output / ticket binding — CLOSED.** Matmul results → XorFold → BLAKE3 jackpot + → `HASH_JACKPOT`, with `statement_digest` derived from the proof's *own* + `HASH_JACKPOT` (`driver.rs`), and native `check_jackpot_difficulty`. + +3. **Header binding — CLOSED (at the consensus verifier gateway).** The opening + keys (`KEY_A`/`KEY_B`), the public-parameter encoding `p`, and the jackpot key + enter the STARK from the caller, but the consensus verifier + `verify_wrapped_proof_with_headers` (`circuit::fp16::wrapper`) re-derives them + from the proposed/ancestor headers + committed operand roots, derives the + `statement_digest` from the proof's *own* `HASH_JACKPOT`, and pins the ENTIRE + stage-2 public-input vector by equality before verifying the wrapped proof and + checking native difficulty. A proof whose keys/seeds/jackpot-key do not match + the header is rejected, so the statement is header-bound at consensus. + +**Wired consensus path.** The FP16 (A100) consensus certificate is the +header-bound ZK certificate (`CertificateV5` → `verify_fp16_zk_cert_ffi` → +`verify_wrapped_proof_with_headers`); the earlier plaintext certificate +(`api::fp16::verify`, which bound operands by Merkle opening and recomputed the +tile + census by replay) is **retired** as a consensus path. The one remaining +residual is provisioning, not soundness: the FP16 wrapper is compiled per degree +profile, so the embedded verifier cache (`fp16_cache.bin`) must enumerate every +consensus-legal profile before V5 is activated (the universal FP16 wrapper, §8, +would remove the per-shape cache). The full blueprint is in `zk_binding_design.md`. diff --git a/docs/fp16_scheme/validation/README.md b/docs/fp16_scheme/validation/README.md new file mode 100644 index 000000000..f2523af3c --- /dev/null +++ b/docs/fp16_scheme/validation/README.md @@ -0,0 +1,118 @@ +# FP16 / A100 scheme — reproducible hardware validation + +This directory is the **reproducible hardware oracle and calibration harness** for +the FP16 accumulation-hardness scheme (`docs/fp16_scheme/fp16_scheme.tex`). It +exists to close three gaps a review of the scheme flagged: + +1. the committed reference corpus + (`zk-pow/src/api/fp16/testdata/a100_dot_vectors.txt`) topped out at **k=256** + and carried no explicit subnormal / cancellation / overflow edges; +2. the accumulation model was validated only **circularly** in-tree + (`accumulate.rs`, the Python reference, and the vector file are three + expressions of the *same* model) — nothing checked it against the **device**; +3. the **RZ-vs-RNE** rounding question (does the A100 round toward zero, as the + model assumes, or to nearest-even?) had no in-tree silicon resolution, and the + Appendix "Empirical validation" numbers (f_bp / rho distributions, shortcut + rates) were prose with **no runnable harness**. + +Everything here runs on a real **sm_80** GPU (A100 / GA100 / CMP 170HX) with a +standard CUDA toolkit (tested: nvcc 12.8, CMP 170HX 64 GB, driver 610.43.02). It +deliberately links only the CUDA runtime — **no torch, no pearl-gemm** — so it +builds and runs on an sm_80 box that cannot install the py3.12 miner stack. + +## Contents + +| file | what it does | +|---|---| +| `a100_hmma_capture.cu` | Standalone capture tool. Issues the real `mma.sync.m16n8k16.f32.f16` (asm + fragment layout copied verbatim from the validated production kernel `fp16_gemm/_kernel_sm80.cu`) and dumps device FP32 result bits for each input dot product. | +| `generate_and_capture.py` | Generates an edge-case corpus (k up to 1024; subnormal operands / accumulators / outputs; cancellation; grid-boundary; max-magnitude), captures it on silicon, and **cross-checks the software model against the device** bit-for-bit. Writes `a100_dot_vectors_k1024.txt`. | +| `rounding_mode_probe.py` | Builds four model variants (per-product ∈ {RZ,RNE} × per-group ∈ {RZ,RNE}), finds vectors where they disagree, captures them on silicon, and reports which rounding the device matches. **Resolves RZ-vs-RNE empirically.** | +| `calibration.py` | Reproduces the Appendix policy-metric study: per-strategy `f_bp`, `rho`, and shortcut-predictor reproduction rates, checked against the gate (`f_bp>=0.30`, `rho>=1.2`) and the paper's claimed regime. CPU only. `--rust-noise` drives the **real consensus noise pipeline** (next row) instead of a Python reimplementation. | +| `attack_cost_benchmark.cu` | Times the honest tensor-core GEMM against the per-product truncation-correction kernel (which must run on CUDA cores) on silicon, measuring the attacker's cost multiplier — the paper's "6-13x / memory-bound far more" claim. | +| `../../../zk-pow/examples/fp16_noise_tool.rs` | Rust example that emits seed-exact noised operands through the real `fp16_noised_operands` pipeline (root-derived seeds -> BLAKE3 noise lines -> `noisy_quantize`); `calibration.py --rust-noise` shells out to it. Build: `cd zk-pow && cargo build --release --example fp16_noise_tool`. | + +## How to run + +```sh +cd docs/fp16_scheme/validation +nvcc -arch=sm_80 -O2 -o a100_hmma_capture a100_hmma_capture.cu # build once +python3 generate_and_capture.py # edge corpus + model-vs-silicon cross-check +python3 rounding_mode_probe.py # RZ-vs-RNE resolution on silicon +python3 calibration.py # policy-metric calibration (Python noise; no GPU) + +# seed-exact consensus noise + the attack-cost benchmark: +(cd ../../../zk-pow && cargo build --release --example fp16_noise_tool) +python3 calibration.py --rust-noise # same calibration, real consensus noise bytes +nvcc -arch=sm_80 -O3 -o attack_cost_benchmark attack_cost_benchmark.cu +./attack_cost_benchmark 512 512 1024 50 # honest vs truncation-correction cost +``` + +The regenerated `a100_dot_vectors_k1024.txt` is copied to +`zk-pow/src/api/fp16/testdata/` and consumed by the Rust cross-check test +`api::fp16::accumulate::tests::matches_hardware_capture_k1024`, so CI enforces +"model == captured silicon bits" (including a k=1024 and a subnormal-output +assertion). The capture binary itself is a build artifact (git-ignored). + +## Recorded results (on CMP 170HX, sm_80, nvcc 12.8) + +**Model vs silicon — bit-exact.** The capture tool reproduces all **238** +pre-existing committed vectors bit-for-bit, and the model reproduces all **272** +newly captured edge vectors (k up to 1024; 16 of them subnormal-FP32 outputs; +64 subnormal-FP32 carry-ins). Total: **910** independent silicon dot products +agree with the model, **0 mismatches** (238 committed + 272 edge + 400 +rounding-discriminating). + +**RZ-vs-RNE — RZ confirmed at both stages.** On **400** vectors constructed so the +four rounding variants disagree, the device matched the committed `(RZ, RZ)` +model on **400/400**; the alternatives matched only where they happen to coincide +with RZ and were excluded elsewhere (`RZ/RNE` 113/400, `RNE/RZ` 109/400, +`RNE/RNE` 60/400). **Conclusion: the A100/GA100 `HMMA.16816.F32` rounds toward +zero** both when aligning each product/accumulator onto the `2^(eta-24)` grid and +when encoding the per-group sum to FP32 — exactly what `accumulate.rs` models. + +**Overflow is unreachable from a single FP16 dot product.** Max-magnitude +(|operand| up to 65504) k=1024 tiles with ±max-finite FP32 carry-in all stayed +finite on silicon; no generated vector overflowed. The accumulation guard against +non-finite results is therefore defensive, consistent with the feasibility note +that FP16 products align at `eta >= 99` and the carry model forbids a cell-start +carry-in. + +**Subnormal-FP32 output is reachable only via a surviving subnormal carry-in.** +With FP16 operands the smallest nonzero product is `2^-48`, so any nonzero product +dominates a subnormal (`< 2^-126`) accumulator and pushes the output normal; a +nonzero subnormal output arises only when a subnormal FP32 carry-in survives +products that are zero or exactly cancel. The corpus includes 16 such cases +(captured and model-matched), which exercise the device's subnormal encode — the +`matmul_a100_stark` MA13 branch the ZK audit noted was otherwise silicon-untested. +This confirms MA13 is a sound guard on the reachable sub-case. + +**Policy calibration (`calibration.py`, 16×16 tile, k=1024, rank-32 δ=1/2 noise).** +Across 8 adversarial/realistic strategies, with the **shape-faithful Python** +noise: `f_bp ∈ [0.453, 0.512]`, `rho ∈ [1.67, 1.94]`, shortcut reproduction +≤ 1.56%. With the **seed-exact Rust consensus** noise (`--rust-noise`, via +`fp16_noise_tool`): `f_bp ∈ [0.448, 0.518]`, `rho ∈ [1.674, 1.939]`, shortcut +≤ 2.34%. Both match the paper's claimed regime (`f_bp ∈ [0.36,0.51]`, +`rho ≥ 1.38`, cheapest shortcut ≤ ~1.6%), all well above the `0.30 / 1.2` gate — +and the two noise sources agree closely, so the Python proxy was faithful. + +**Truncation-correction attack cost (`attack_cost_benchmark.cu`, on CMP 170HX).** +Granting the attacker the exact sums and the breakpoint oracle for free, the +unavoidable per-product correction (decode + multiply + per-group truncation on +CUDA cores) measured **37.6×** the honest bit-exact tensor-core GEMM at +`512×512×1024` and **43.0×** at `1024³`. The honest baseline is the miner's own +kernel style (one warp per 16×8 subtile, no shared-memory pipelining — exactly +`fp16_gemm/_kernel_sm80.cu`), so the ratio is representative, not pessimistic. It +sits well above the whitepaper's "6–13× compute-bound-optimistic" floor and below +its "220–470× memory-bound" ceiling, consistent with the hardness claim that the +corrections cannot be batched onto tensor cores. + +## Scope / remaining + +- The accumulation model and both roundings are silicon-validated; the + policy-metric distributions are reproducible with **both** a Python proxy and + the **real consensus noise pipeline** (`--rust-noise`); and the attack-cost + multiplier is measured on silicon. The three gaps the review flagged are closed. +- The attack benchmark measures the *lower-bound* elementwise correction cost; a + production attacker's kernel could be tuned, but so could the honest one (which + benefits from tensor cores — the asymmetry the scheme relies on). The strategy + set in `calibration.py` is extensible for broader adversarial sweeps. diff --git a/docs/fp16_scheme/validation/a100_hmma_capture.cu b/docs/fp16_scheme/validation/a100_hmma_capture.cu new file mode 100644 index 000000000..bdf269e6f --- /dev/null +++ b/docs/fp16_scheme/validation/a100_hmma_capture.cu @@ -0,0 +1,160 @@ +// Hardware capture of the A100/GA100 (sm_80) HMMA.16816.F32 accumulation, for +// the FP16 proof-of-useful-work scheme (docs/fp16_scheme). This is the +// *hardware* oracle: it issues the real tensor-core `mma.sync` on silicon and +// dumps the FP32 result bits, so the software model in +// `zk-pow/src/api/fp16/accumulate.rs` can be checked against the device rather +// than against another copy of itself. +// +// Deliberately standalone: it links only the CUDA runtime (no torch, no +// pearl-gemm), so it builds and runs on an sm_80 box that cannot install the +// py3.12 miner stack. The mma asm and the distributed fragment layout are copied +// verbatim from the validated production kernel +// `miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_kernel_sm80.cu`, so a capture here +// exercises exactly the datapath the miner uses. +// +// Build: nvcc -arch=sm_80 -O2 -o a100_hmma_capture a100_hmma_capture.cu +// +// Input (stdin), one dot product per line: +// k a_bits[0..k) b_bits[0..k) c_bits +// where a_bits/b_bits are FP16 bit patterns (u16) and c_bits is the FP32 +// carry-in bit pattern (u32). `k` must be a positive multiple of 16. +// +// Output (stdout), one line per input: the FP32 result bit pattern (u32), +// captured from the device D[0][0] of a 16x8 tile whose A-row 0 is `a`, B-row 0 +// is `b`, and C[0][0] is the carry-in (all other tile entries zero). +// +// Exit non-zero on any CUDA error or malformed input. + +#include +#include +#include +#include +#include +#include + +#define CUDA_CHECK(expr) \ + do { \ + cudaError_t _e = (expr); \ + if (_e != cudaSuccess) { \ + fprintf(stderr, "CUDA error %s at %s:%d\n", \ + cudaGetErrorString(_e), __FILE__, __LINE__); \ + std::exit(2); \ + } \ + } while (0) + +__device__ __forceinline__ unsigned pack2(const __half* p, int i0, int i1) { + __half2 h = __halves2half2(p[i0], p[i1]); + return *reinterpret_cast(&h); +} + +// One warp computes one 16x8 output subtile D = A(16xK) . B(8xK)^T with FP32 +// accumulation chained in ascending k order (groups of 16 per mma.sync, no +// split-k, no atomics), carrying the accumulator forward across the whole k +// axis -- the pinned reduction order that defines the device result. Identical +// to fp16_gemm_a100_kernel but single-tile (M=16, N=8). +__global__ void capture_kernel(const __half* __restrict__ A, + const __half* __restrict__ B, + const float* __restrict__ C, + float* __restrict__ D, int K) { + int lane = threadIdx.x & 31; + int gid = lane >> 2; // 0..7 + int t4 = lane & 3; // 0..3 + + float c0 = 0.f, c1 = 0.f, c2 = 0.f, c3 = 0.f; + if (C != nullptr) { + c0 = C[(gid) * 8 + t4 * 2]; + c1 = C[(gid) * 8 + t4 * 2 + 1]; + c2 = C[(gid + 8) * 8 + t4 * 2]; + c3 = C[(gid + 8) * 8 + t4 * 2 + 1]; + } + for (int k0 = 0; k0 < K; k0 += 16) { + unsigned a0 = pack2(A, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned a1 = pack2(A, (gid + 8) * K + k0 + t4 * 2, (gid + 8) * K + k0 + t4 * 2 + 1); + unsigned a2 = pack2(A, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + unsigned a3 = pack2(A, (gid + 8) * K + k0 + t4 * 2 + 8, (gid + 8) * K + k0 + t4 * 2 + 9); + unsigned b0 = pack2(B, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned b1 = pack2(B, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + asm volatile( + "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 " + "{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};\n" + : "+f"(c0), "+f"(c1), "+f"(c2), "+f"(c3) + : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(b0), "r"(b1)); + } + D[(gid) * 8 + t4 * 2] = c0; + D[(gid) * 8 + t4 * 2 + 1] = c1; + D[(gid + 8) * 8 + t4 * 2] = c2; + D[(gid + 8) * 8 + t4 * 2 + 1] = c3; +} + +int main() { + // Persistent device buffers sized to the largest tile we expect. + int cap_k = 0; + __half *dA = nullptr, *dB = nullptr; + float *dC = nullptr, *dD = nullptr; + std::vector<__half> hA, hB; + float hC[128], hD[128]; + + // Each record is whitespace-separated: k, then k a-bits, k b-bits, c-bits. + long k; + while (scanf("%ld", &k) == 1) { + if (k <= 0) { + fprintf(stderr, "bad k=%ld (must be positive)\n", k); + return 1; + } + // The mma tile runs in units of 16 along the contraction axis. Any k is + // zero-padded up to the next multiple of 16; within each group of 8 the + // padded entries are zero (skipped by the model), and any whole trailing + // all-zero group is a no-op, so the padded capture equals the model's + // result for the true k -- which also validates those properties on + // silicon (the committed corpus includes k not a multiple of 16). + long kpad = (k + 15) / 16 * 16; + std::vector a(k), b(k); + uint32_t cbits; + for (long i = 0; i < k; i++) { + unsigned v; + if (scanf("%u", &v) != 1) { fprintf(stderr, "truncated a\n"); return 1; } + a[i] = (uint16_t)v; + } + for (long i = 0; i < k; i++) { + unsigned v; + if (scanf("%u", &v) != 1) { fprintf(stderr, "truncated b\n"); return 1; } + b[i] = (uint16_t)v; + } + if (scanf("%u", &cbits) != 1) { fprintf(stderr, "truncated c\n"); return 1; } + + if (kpad > cap_k) { + if (dA) { cudaFree(dA); cudaFree(dB); } + CUDA_CHECK(cudaMalloc(&dA, sizeof(__half) * 16 * kpad)); + CUDA_CHECK(cudaMalloc(&dB, sizeof(__half) * 8 * kpad)); + if (!dC) { + CUDA_CHECK(cudaMalloc(&dC, sizeof(float) * 128)); + CUDA_CHECK(cudaMalloc(&dD, sizeof(float) * 128)); + } + hA.resize(16 * kpad); + hB.resize(8 * kpad); + cap_k = kpad; + } + // Zero the tile, place the vectors in row 0 of A and B, carry-in at [0][0]. + for (auto& h : hA) h = __ushort_as_half((unsigned short)0); + for (auto& h : hB) h = __ushort_as_half((unsigned short)0); + for (long i = 0; i < k; i++) hA[i] = __ushort_as_half((unsigned short)a[i]); + for (long i = 0; i < k; i++) hB[i] = __ushort_as_half((unsigned short)b[i]); + for (int i = 0; i < 128; i++) hC[i] = 0.f; + float cf; + memcpy(&cf, &cbits, 4); + hC[0] = cf; + + CUDA_CHECK(cudaMemcpy(dA, hA.data(), sizeof(__half) * 16 * kpad, cudaMemcpyHostToDevice)); + CUDA_CHECK(cudaMemcpy(dB, hB.data(), sizeof(__half) * 8 * kpad, cudaMemcpyHostToDevice)); + CUDA_CHECK(cudaMemcpy(dC, hC, sizeof(float) * 128, cudaMemcpyHostToDevice)); + capture_kernel<<<1, 32>>>(dA, dB, dC, dD, (int)kpad); + CUDA_CHECK(cudaGetLastError()); + CUDA_CHECK(cudaDeviceSynchronize()); + CUDA_CHECK(cudaMemcpy(hD, dD, sizeof(float) * 128, cudaMemcpyDeviceToHost)); + + uint32_t dbits; + memcpy(&dbits, &hD[0], 4); + printf("%u\n", dbits); + } + return 0; +} diff --git a/docs/fp16_scheme/validation/attack_cost_benchmark.cu b/docs/fp16_scheme/validation/attack_cost_benchmark.cu new file mode 100644 index 000000000..e79963513 --- /dev/null +++ b/docs/fp16_scheme/validation/attack_cost_benchmark.cu @@ -0,0 +1,161 @@ +// Truncation-correction attack-cost micro-benchmark (FP16 scheme, A100/sm_80). +// +// The hardness argument (whitepaper Section "Hardness"/"Attack vectors") is: the +// device output D_ij = RZ( S_ij - sum_u rho_u - sum_g gamma_g ), where S_ij is +// the exact dot product (an attacker can get it, and every eta, cheaply from the +// low-rank structure), but the per-product truncation corrections rho_u are a +// *per-product nonlinearity applied before the reduction* -- not a contraction, +// so no tensor-core matmul evaluates them. The attacker must compute them +// elementwise on CUDA cores. This benchmark measures that cost against the +// honest tensor-core GEMM, reproducing the paper's "6-13x honest +// (compute-bound-optimistic)" and "memory-bound, far more" figures on silicon. +// +// We grant the attacker EVERYTHING the paper grants and more: the exact sums and +// the breakpoint oracle are free; the attack kernel only does the unavoidable +// work of touching each of the M*N*K products and computing its truncation +// remainder on CUDA cores (decompose both FP16 operands, multiply significands, +// per-group eta, extract the discarded low bits). The honest kernel is the real +// `mma.sync.m16n8k16.f32.f16` tensor-core GEMM (same datapath as the miner). +// +// Build: nvcc -arch=sm_80 -O3 -o attack_cost_benchmark attack_cost_benchmark.cu +// Run: ./attack_cost_benchmark [M N K iters] (defaults 512 512 1024 50) + +#include +#include +#include +#include +#include + +#define CK(e) do{cudaError_t _e=(e); if(_e!=cudaSuccess){fprintf(stderr,"CUDA %s @%d\n",cudaGetErrorString(_e),__LINE__);std::exit(2);} }while(0) + +#define W 24 +#define GROUP 8 + +// ---------- honest: tensor-core GEMM (one warp per 16x8 subtile) ---------- +__device__ __forceinline__ unsigned pack2(const __half* p, long i0, long i1) { + __half2 h = __halves2half2(p[i0], p[i1]); + return *reinterpret_cast(&h); +} +__global__ void honest_gemm(const __half* __restrict__ A, const __half* __restrict__ B, + float* __restrict__ D, int M, int N, int K) { + int m0 = blockIdx.y * 16, n0 = blockIdx.x * 8; + if (m0 >= M || n0 >= N) return; + int lane = threadIdx.x & 31, gid = lane >> 2, t4 = lane & 3; + const __half* Am = A + (long)m0 * K; + const __half* Bn = B + (long)n0 * K; + float c0 = 0, c1 = 0, c2 = 0, c3 = 0; + for (int k0 = 0; k0 < K; k0 += 16) { + unsigned a0 = pack2(Am, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned a1 = pack2(Am, (gid + 8) * K + k0 + t4 * 2, (gid + 8) * K + k0 + t4 * 2 + 1); + unsigned a2 = pack2(Am, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + unsigned a3 = pack2(Am, (gid + 8) * K + k0 + t4 * 2 + 8, (gid + 8) * K + k0 + t4 * 2 + 9); + unsigned b0 = pack2(Bn, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned b1 = pack2(Bn, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + asm volatile("mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 " + "{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};\n" + : "+f"(c0), "+f"(c1), "+f"(c2), "+f"(c3) + : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(b0), "r"(b1)); + } + float* Dt = D + (long)m0 * N + n0; + Dt[(gid) * N + t4 * 2] = c0; Dt[(gid) * N + t4 * 2 + 1] = c1; + Dt[(gid + 8) * N + t4 * 2] = c2; Dt[(gid + 8) * N + t4 * 2 + 1] = c3; +} + +// ---------- attack: per-product truncation correction on CUDA cores ---------- +// (sign, significand, stored_exp) of an FP16 code, matching dtype::decompose_fp16. +__device__ __forceinline__ void decompose(unsigned short bits, int& sign, int& m, int& eps) { + int exp = (bits >> 10) & 0x1F, man = bits & 0x3FF; + sign = (bits & 0x8000) ? -1 : 1; + if (exp == 0) { m = man; eps = -14; } // subnormal/zero + else { m = 0x400 | man; eps = exp - 15; } // normal +} +// One thread per output cell; compute sum_u rho_u (the correction) for its row/col. +__global__ void attack_corrections(const __half* __restrict__ A, const __half* __restrict__ B, + float* __restrict__ OUT, int M, int N, int K) { + long idx = (long)blockIdx.x * blockDim.x + threadIdx.x; + if (idx >= (long)M * N) return; + int i = idx / N, j = idx % N; + const unsigned short* a = reinterpret_cast(A) + (long)i * K; + const unsigned short* b = reinterpret_cast(B) + (long)j * K; + long correction = 0; // sum of discarded low bits (the attacker's unavoidable work) + for (int g0 = 0; g0 < K; g0 += GROUP) { + int g1 = g0 + GROUP < K ? g0 + GROUP : K; + // eta = max over nonzero products of (ea+eb) (accumulator granted free) + int eta = -1000000; + for (int u = g0; u < g1; u++) { + int sa, ma, ea, sb, mb, eb; decompose(a[u], sa, ma, ea); decompose(b[u], sb, mb, eb); + if (ma && mb) { int e = ea + eb; if (e > eta) eta = e; } + } + if (eta == -1000000) continue; + int unit = eta - W; + for (int u = g0; u < g1; u++) { + int sa, ma, ea, sb, mb, eb; decompose(a[u], sa, ma, ea); decompose(b[u], sb, mb, eb); + if (!ma || !mb) continue; + long P = (long)ma * mb; // product significand (exact, < 2^22) + int sh = (ea + eb) - 20 - unit; // product LSB is 2^(ea+eb-20) + if (sh < 0) { + int s = -sh; if (s > 62) s = 62; + long discarded = P & ((1L << s) - 1); // the bits the device truncates + correction += (sa * sb) * discarded; // rho_u contribution + } + } + } + OUT[idx] = (float)correction; // prevents dead-code elimination +} + +static double time_ms(cudaEvent_t s, cudaEvent_t e) { float ms = 0; cudaEventElapsedTime(&ms, s, e); return ms; } + +int main(int argc, char** argv) { + int M = argc > 1 ? atoi(argv[1]) : 512; + int N = argc > 2 ? atoi(argv[2]) : 512; + int K = argc > 3 ? atoi(argv[3]) : 1024; + int iters = argc > 4 ? atoi(argv[4]) : 50; + if (M % 16 || N % 8 || K % 16) { fprintf(stderr, "need M%%16==0, N%%8==0, K%%16==0\n"); return 1; } + + cudaDeviceProp prop; CK(cudaGetDeviceProperties(&prop, 0)); + printf("device: %s (sm_%d%d), %d SMs\n", prop.name, prop.major, prop.minor, prop.multiProcessorCount); + printf("tile M=%d N=%d K=%d, %d timed iters; products = M*N*K = %.3g\n\n", M, N, K, iters, (double)M * N * K); + + // Random finite FP16 operands. + std::vector hA((long)M * K), hB((long)N * K); + srand(1); + auto rnd_fp16 = []() { int e = 1 + rand() % 29, m = rand() % 1024, s = (rand() & 1) << 15; return (unsigned short)(s | (e << 10) | m); }; + for (auto& x : hA) x = rnd_fp16(); + for (auto& x : hB) x = rnd_fp16(); + + __half *dA, *dB; float *dD, *dOUT; + CK(cudaMalloc(&dA, sizeof(__half) * hA.size())); + CK(cudaMalloc(&dB, sizeof(__half) * hB.size())); + CK(cudaMalloc(&dD, sizeof(float) * (long)M * N)); + CK(cudaMalloc(&dOUT, sizeof(float) * (long)M * N)); + CK(cudaMemcpy(dA, hA.data(), sizeof(__half) * hA.size(), cudaMemcpyHostToDevice)); + CK(cudaMemcpy(dB, hB.data(), sizeof(__half) * hB.size(), cudaMemcpyHostToDevice)); + + dim3 gg(N / 8, M / 16), gb(32, 1); + int tpb = 256; long cells = (long)M * N; int ab = (int)((cells + tpb - 1) / tpb); + + cudaEvent_t s, e; CK(cudaEventCreate(&s)); CK(cudaEventCreate(&e)); + // warmup + honest_gemm<<>>(dA, dB, dD, M, N, K); + attack_corrections<<>>(dA, dB, dOUT, M, N, K); + CK(cudaDeviceSynchronize()); + + CK(cudaEventRecord(s)); + for (int t = 0; t < iters; t++) honest_gemm<<>>(dA, dB, dD, M, N, K); + CK(cudaEventRecord(e)); CK(cudaEventSynchronize(e)); + double honest = time_ms(s, e) / iters; + + CK(cudaEventRecord(s)); + for (int t = 0; t < iters; t++) attack_corrections<<>>(dA, dB, dOUT, M, N, K); + CK(cudaEventRecord(e)); CK(cudaEventSynchronize(e)); + double attack = time_ms(s, e) / iters; + CK(cudaGetLastError()); + + double macs = 2.0 * (double)M * N * K; + printf("honest tensor-core GEMM : %8.3f ms/iter (%.1f GFLOP/s effective)\n", honest, macs / (honest * 1e6)); + printf("attack per-product corr : %8.3f ms/iter (CUDA cores, elementwise)\n", attack); + printf("\nMEASURED attack / honest wall-time ratio : %.1fx\n", attack / honest); + printf(" (the attacker pays this to reconstruct one tile's corrections even\n"); + printf(" with the exact sums and breakpoint oracle granted for free)\n"); + return 0; +} diff --git a/docs/fp16_scheme/validation/calibration.py b/docs/fp16_scheme/validation/calibration.py new file mode 100644 index 000000000..0c0c0ede1 --- /dev/null +++ b/docs/fp16_scheme/validation/calibration.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +"""Reproducible calibration / adversarial harness for the FP16 jackpot policy. + +Backs the whitepaper's Appendix "Empirical validation": for a battery of input +strategies (realistic and adversarial), it computes the per-tile breakpoint +density `f_bp` and certified-work ratio `rho` (bit-matched to +`zk-pow/src/api/fp16/policy.rs`), and the reproduction rate of the two cheap +"shortcut" predictors (exact-sum-rounded-to-FP32; group-sums-without-per-product +truncation). It then checks them against the policy gate (`f_bp >= 0.30`, +`rho >= 1.2`) and prints the min `rho` / `f_bp` observed per strategy. + +What this harness IS: a reproducible reimplementation of the policy-metric +distribution study, so a reviewer can re-run the calibration and see where +honest and adversarial tiles land relative to the gate. The accumulation model +is now silicon-validated (see `generate_and_capture.py` / `rounding_mode_probe.py` +and the README), so computing the census from the model is sound. + +What this harness is NOT: the concrete truncation-correction *attack cost* +(the "6-13x honest" figure). That is a separate hardware micro-benchmark, not a +policy-metric computation, and is left as the documented remaining piece. + +Noise: an independent, faithful reimplementation of the mandated rank-32, +delta=1/2 low-rank noise added before FP16 quantization (mirrors the SHAPE of +`api/fp16/noise.rs` + `quantization.rs`, not its seed-exact bytes). Final +consensus numbers should be reproduced through the Rust path; this is for the +statistical distribution. + +Usage: python3 calibration.py (CPU only; no GPU needed) +""" +from __future__ import annotations + +import argparse +import os +import subprocess +import sys +import numpy as np + +sys.path.insert( + 0, + os.path.join(os.path.dirname(__file__), "..", "..", "..", "miner", "pearl-gemm", "tests", "helpers"), +) +import a100_fp16_reference as ref # noqa: E402 + +HERE = os.path.dirname(os.path.abspath(__file__)) +GROUP = ref.GROUP +NOISE_RANK = 32 +DELTA = 0.5 +MIN_FBP = 0.30 +MIN_RHO = 1.2 + + +# ---- FP16 <-> f32 (round-to-nearest-even cast, saturating, matches dtype.rs) ---- +def f32_to_fp16_bits(x: np.ndarray) -> np.ndarray: + return x.astype(np.float16).view(np.uint16) + + +def fp16_bits_to_f32(u: np.ndarray) -> np.ndarray: + return u.astype(np.uint16).view(np.float16).astype(np.float32) + + +# ---- census (mirrors accumulate.rs PolicyStep + a100_dot breakpoint logic) ---- +def dot_with_census(a, b, c_bits): + """Returns (d_bits, list_of_steps) where each step is (nonempty, breakpoint, + products_truncated). Bit-identical census to accumulate.rs::a100_dot.""" + a = [int(x) for x in a] + b = [int(x) for x in b] + cur = int(c_bits) & 0xFFFFFFFF + k = len(a) + steps = [] + g0 = 0 + while g0 < k: + g1 = min(g0 + GROUP, k) + cs, cm, cel, culp = ref._acc_parts(cur) + eta = cel + for u in range(g0, g1): + _, ma, ea = ref.decompose_fp16(a[u]) + _, mb, eb = ref.decompose_fp16(b[u]) + if ma and mb: + eta = max(eta, ea + eb) + if eta == ref._NEG: + steps.append((False, False, 0)) + g0 = g1 + continue + unit = eta - ref.W + total = 0 + ptc = 0 + for u in range(g0, g1): + sa, ma, ea = ref.decompose_fp16(a[u]) + sb, mb, eb = ref.decompose_fp16(b[u]) + if not ma or not mb: + continue + prod = ma * mb + sh = (ea + eb) - 20 - unit + if sh < 0 and (prod & ((1 << min(-sh, 126)) - 1)) != 0: + ptc += 1 + total += (sa * sb) * ref._shift(prod, sh) + csh = culp - unit + acc_trunc = csh < 0 and cm != 0 and (cm & ((1 << min(-csh, 63)) - 1)) != 0 + total += cs * ref._shift(cm, csh) + nb = ref._rz_to_f32_bits(total, unit) + # rz dropped a nonzero bit iff the encoded value != exact sum*2^unit + enc = np.float64(np.float32(np.uint32(nb).view(np.float32))) + exact = np.float64(total) * np.float64(2.0) ** np.float64(unit) + rz_dropped = enc != exact + steps.append((True, bool(acc_trunc or rz_dropped), ptc)) + cur = nb + g0 = g1 + return cur & 0xFFFFFFFF, steps + + +def tile_metrics(A_bits, B_bits, h, w, k): + """f_bp and rho over an h x w tile (bit patterns, row-major, B transposed).""" + breakpoints = 0 + total_steps = 0 + numerator = 0 + for i in range(h): + ai = A_bits[i * k:(i + 1) * k] + for j in range(w): + bj = B_bits[j * k:(j + 1) * k] + _, steps = dot_with_census(list(ai), list(bj), 0) + n_bp = sum(1 for s in steps if s[1]) + n_pt = sum(s[2] for s in steps if not s[1]) # truncated products outside breakpoints + # maximal runs of non-breakpoint *nonempty* steps + n_runs = 0 + in_run = False + for s in steps: + if s[0] and not s[1]: + if not in_run: + n_runs += 1 + in_run = True + else: + in_run = False + numerator += GROUP * n_bp + NOISE_RANK * n_runs + n_pt + breakpoints += n_bp + total_steps += len(steps) + f_bp = breakpoints / total_steps + rho = numerator / (h * w * k) + return f_bp, rho + + +def shortcut_rates(A_bits, B_bits, h, w, k): + """Fraction of cells reproduced by the two cheap predictors.""" + A = fp16_bits_to_f32(np.asarray(A_bits, np.uint16)).reshape(h, k) + B = fp16_bits_to_f32(np.asarray(B_bits, np.uint16)).reshape(w, k) + exact_hit = group_hit = 0 + for i in range(h): + for j in range(w): + d_bits, _ = dot_with_census(list(A_bits[i * k:(i + 1) * k]), list(B_bits[j * k:(j + 1) * k]), 0) + # predictor 1: exact FP32 dot product (no per-group grid), then it IS the rz-to-f32 of exact sum + exact = np.float32(np.dot(A[i].astype(np.float64), B[j].astype(np.float64))) + if exact.view(np.uint32) == d_bits: + exact_hit += 1 + # predictor 2: group sums without per-product truncation (sum each group exactly, rz per group) + cur = np.float32(0.0) + for g0 in range(0, k, GROUP): + s = np.float64(cur) + np.dot(A[i, g0:g0 + GROUP].astype(np.float64), B[j, g0:g0 + GROUP].astype(np.float64)) + cur = np.float32(s) # RNE cast; approximates "no per-product trunc" + if cur.view(np.uint32) == d_bits: + group_hit += 1 + cells = h * w + return exact_hit / cells, group_hit / cells + + +# ---- seed-exact noise via the real Rust consensus pipeline ---- +RUST_NOISE_TOOL = os.path.join( + HERE, "..", "..", "..", "zk-pow", "target", "release", "examples", "fp16_noise_tool" +) + + +def rust_noise(A_bits, B_bits, h, w, k): + """Noise A/B raw FP16 codes through the real `fp16_noised_operands` pipeline + (root-derived seeds -> BLAKE3 noise lines -> noisy_quantize). Returns the + seed-exact noised A, B code arrays.""" + if not os.path.exists(RUST_NOISE_TOOL): + sys.exit( + f"rust noise tool not built: {RUST_NOISE_TOOL}\n" + " (cd zk-pow && cargo build --release --example fp16_noise_tool)" + ) + payload = ( + f"{h} {w} {k}\n" + + " ".join(str(int(x)) for x in A_bits) + "\n" + + " ".join(str(int(x)) for x in B_bits) + "\n" + ) + proc = subprocess.run([RUST_NOISE_TOOL], input=payload, capture_output=True, text=True) + if proc.returncode != 0: + sys.exit(f"rust noise tool failed: {proc.stderr}") + out = [int(x) for x in proc.stdout.split()] + if len(out) != h * k + w * k: + sys.exit(f"rust noise tool returned {len(out)} codes, expected {h*k + w*k}") + return np.array(out[: h * k], np.uint16), np.array(out[h * k:], np.uint16) + + +# ---- mandated low-rank noise + FP16 quantization (shape-faithful fallback) ---- +def noisy_quantize(X: np.ndarray, rng, k): + """X: (rows, k) f32. Add rank-32 delta=1/2 noise, then FP16-cast. Returns bits.""" + rows = X.shape[0] + E = rng.standard_normal((rows, NOISE_RANK)).astype(np.float32) + F = rng.standard_normal((k, NOISE_RANK)).astype(np.float32) + N = (E @ F.T).astype(np.float32) + # per-row scales: noise carries relative Euclidean weight delta + xn = np.linalg.norm(X, axis=1, keepdims=True) + 1e-30 + nn = np.linalg.norm(N, axis=1, keepdims=True) + 1e-30 + beta = DELTA * xn / nn + # alpha range-normalizes to the FP16 finite range (target magnitude ~ 65504) + noised = X + beta * N + mx = np.max(np.abs(noised), axis=1, keepdims=True) + 1e-30 + alpha = 60000.0 / mx + noised = (alpha * noised).astype(np.float32) + return f32_to_fp16_bits(noised).reshape(-1) + + +# ---- adversarial / realistic input strategies ---- +def make_operand(strategy, rows, k, rng): + if strategy == "gaussian_outlier": + X = rng.standard_normal((rows, k)).astype(np.float32) + X[:, rng.integers(0, k, size=max(1, k // 64))] *= 30.0 + elif strategy == "heavy_tailed": + X = (rng.standard_t(2.0, size=(rows, k))).astype(np.float32) + elif strategy == "zeros": + X = np.zeros((rows, k), np.float32) + elif strategy == "rank_two": + U = rng.standard_normal((rows, 2)).astype(np.float32) + V = rng.standard_normal((2, k)).astype(np.float32) + X = (U @ V).astype(np.float32) + elif strategy == "flat": + X = np.ones((rows, k), np.float32) * rng.standard_normal((rows, 1)).astype(np.float32) + elif strategy == "few_bits": + X = rng.integers(-4, 5, size=(rows, k)).astype(np.float32) + elif strategy == "sparse": + X = rng.standard_normal((rows, k)).astype(np.float32) + X *= (rng.random((rows, k)) < 0.05) + elif strategy == "spiked": + X = (rng.random((rows, k)) < 0.02).astype(np.float32) * 1000.0 + elif strategy == "geometric": + X = (2.0 ** rng.integers(-8, 8, size=(rows, k))).astype(np.float32) * rng.choice([-1, 1], (rows, k)) + else: + raise ValueError(strategy) + return X + + +STRATEGIES = [ + "gaussian_outlier", "heavy_tailed", "rank_two", "flat", + "few_bits", "sparse", "spiked", "geometric", +] + + +def self_test(): + """The accumulate.rs breakpoint example: 2^24 + 1 drops a bit -> breakpoint.""" + a = [f32_to_fp16_bits(np.array([1.0], np.float32))[0]] + b = [f32_to_fp16_bits(np.array([1.0], np.float32))[0]] + c_bits = np.float32(16_777_216.0).view(np.uint32) + d, steps = dot_with_census(a, b, int(c_bits)) + assert steps[0][1], "census must flag the RZ-drop breakpoint" + assert d == int(np.float32(16_777_216.0).view(np.uint32)) + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument( + "--rust-noise", action="store_true", + help="derive noise through the real Rust fp16_noised_operands pipeline " + "(seed-exact consensus bytes) instead of the shape-faithful Python noise", + ) + ap.add_argument("--h", type=int, default=16) + ap.add_argument("--w", type=int, default=16) + ap.add_argument("--k", type=int, default=1024) + args = ap.parse_args() + + self_test() + rng = np.random.default_rng(0xBEEF) + h, w, k = args.h, args.w, args.k # the study's tile + noise_src = "rust (seed-exact consensus pipeline)" if args.rust_noise else "python (shape-faithful)" + print(f"tile h={h} w={w} k={k}, rank={NOISE_RANK}, delta={DELTA}; gate f_bp>={MIN_FBP}, rho>={MIN_RHO}") + print(f"noise source: {noise_src}\n") + print(f"{'strategy':20} {'f_bp':>8} {'rho':>8} {'exact%':>8} {'group%':>8} {'gate':>6}") + worst_fbp, worst_rho = 1e9, 1e9 + all_pass = True + for strat in STRATEGIES: + A = make_operand(strat, h, k, rng) + B = make_operand(strat, w, k, rng) + if args.rust_noise: + # Commit raw FP16 codes, then noise through the real pipeline. + A_raw = f32_to_fp16_bits(np.clip(A, -65504, 65504).astype(np.float32)).reshape(-1) + B_raw = f32_to_fp16_bits(np.clip(B, -65504, 65504).astype(np.float32)).reshape(-1) + A_bits, B_bits = rust_noise(A_raw, B_raw, h, w, k) + else: + A_bits = noisy_quantize(A, rng, k) + B_bits = noisy_quantize(B, rng, k) + f_bp, rho = tile_metrics(A_bits, B_bits, h, w, k) + ex, gr = shortcut_rates(A_bits, B_bits, h, w, k) + gate = f_bp >= MIN_FBP and rho >= MIN_RHO + all_pass &= gate + worst_fbp = min(worst_fbp, f_bp) + worst_rho = min(worst_rho, rho) + print(f"{strat:20} {f_bp:8.3f} {rho:8.3f} {ex*100:7.2f}% {gr*100:7.2f}% {'PASS' if gate else 'FAIL':>6}") + print(f"\nworst observed: f_bp={worst_fbp:.3f} (gate {MIN_FBP}), rho={worst_rho:.3f} (gate {MIN_RHO})") + print("whitepaper claims (noised adversarial): f_bp in [0.36,0.51], rho>=1.38, shortcut<=~1.6%") + print(f"all strategies pass the gate: {all_pass}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/fp16_scheme/validation/generate_and_capture.py b/docs/fp16_scheme/validation/generate_and_capture.py new file mode 100644 index 000000000..9051c7400 --- /dev/null +++ b/docs/fp16_scheme/validation/generate_and_capture.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +"""Generate an edge-case FP16/A100 dot-product corpus, capture it on real sm_80 +silicon, and cross-check the software model against the device. + +This is the reproducible hardware oracle for the FP16 scheme +(docs/fp16_scheme). It closes the gap that the committed +`zk-pow/src/api/fp16/testdata/a100_dot_vectors.txt` corpus tops out at k=256 and +carries no explicitly-constructed subnormal / cancellation / overflow edges, and +that nothing in-tree checked the model against the device rather than against +another copy of itself. + +Pipeline, per generated vector `(k, a[k], b[k], c_bits)`: + 1. the software model (`a100_fp16_reference.a100_dot_bits`, the authoritative + RZ port of `zk-pow/src/api/fp16/accumulate.rs`) computes the expected d_bits + (or flags overflow); + 2. the standalone capture tool runs the REAL `mma.sync.m16n8k16.f32.f16` on the + GPU and reports the device d_bits; + 3. the two are compared bit-for-bit. Any disagreement is a model/silicon + divergence and is reported (and fails the run). + +Finite, agreeing vectors are written to `a100_dot_vectors_k1024.txt` in the same +format as the committed corpus, so they can be added to it and consumed by the +Rust cross-check test (`accumulate.rs`). + +Usage: + # build the capture tool once: + nvcc -arch=sm_80 -O2 -o a100_hmma_capture a100_hmma_capture.cu + # then: + python3 generate_and_capture.py --out a100_dot_vectors_k1024.txt + +Requires: an sm_80 GPU (A100 / GA100 / CMP 170HX), numpy. Deterministic (seeded). +""" +from __future__ import annotations + +import argparse +import os +import struct +import subprocess +import sys +import numpy as np + +# The authoritative RZ software model (bit-exact port of accumulate.rs). +sys.path.insert( + 0, + os.path.join( + os.path.dirname(__file__), "..", "..", "..", "miner", "pearl-gemm", "tests", "helpers" + ), +) +import a100_fp16_reference as ref # noqa: E402 + +HERE = os.path.dirname(os.path.abspath(__file__)) +CAPTURE_BIN = os.path.join(HERE, "a100_hmma_capture") + + +def fp16_normal(rng: np.random.Generator) -> int: + """A finite normal/zero FP16 bit pattern (exp field in [0, 30]; never inf/NaN).""" + exp = int(rng.integers(0, 31)) # 0 = subnormal/zero, 1..30 = normal + man = int(rng.integers(0, 1024)) + sign = int(rng.integers(0, 2)) << 15 + return sign | (exp << 10) | man + + +def fp16_subnormal(rng: np.random.Generator) -> int: + man = int(rng.integers(1, 1024)) + sign = int(rng.integers(0, 2)) << 15 + return sign | man # exp field 0 + + +def fp16_large(rng: np.random.Generator) -> int: + """Near-max-magnitude FP16 (exp 29..30), for the overflow-edge probe.""" + exp = int(rng.integers(29, 31)) + man = int(rng.integers(0, 1024)) + sign = int(rng.integers(0, 2)) << 15 + return sign | (exp << 10) | man + + +def f32_bits(x: float) -> int: + return struct.unpack("1024 gap). + for k in (16, 32, 64, 128, 256, 512, 768, 1024): + for _ in range(8): + a = [fp16_normal(rng) for _ in range(k)] + b = [fp16_normal(rng) for _ in range(k)] + yield ("sweep_k", k, a, b, 0) + + # 3. Subnormal FP16 operands (exp field 0) -- the per-product decode's + # subnormal branch, dense. + for _ in range(32): + k = int(rng.choice([64, 256, 1024])) + a = [fp16_subnormal(rng) for _ in range(k)] + b = [fp16_subnormal(rng) if rng.integers(0, 2) else fp16_normal(rng) for _ in range(k)] + yield ("subnormal_operands", k, a, b, 0) + + # 4. Subnormal FP32 accumulator carry-in (exp field 0, nonzero mantissa). + for _ in range(32): + k = int(rng.choice([16, 64, 256])) + a = [fp16_subnormal(rng) for _ in range(k)] + b = [fp16_subnormal(rng) for _ in range(k)] + c = int(rng.integers(1, 1 << 23)) | (int(rng.integers(0, 2)) << 31) # subnormal f32 + yield ("subnormal_acc", k, a, b, c) + + # 5. Subnormal FP32 OUTPUT (the MA13 subnormal-encode branch the ZK circuit + # audit flagged as silicon-untested). With FP16 operands (min |product| + # = 2^-48) a nonzero sub-2^-126 result is only reachable when a subnormal + # FP32 carry-in survives products that are zero or exactly cancel -- so we + # construct exactly that: a subnormal carry-in with (a) all-zero operands + # (pure subnormal passthrough) or (b) exactly-cancelling +x/-x product + # pairs. These keep the output in the subnormal grid, exercising the + # device's subnormal FP32 encode. (That nonzero subnormal outputs are + # otherwise unreachable is itself a reportable property -- see README.) + for i in range(32): + k = int(rng.choice([16, 64, 256])) + sub_c = int(rng.integers(1, 1 << 23)) # subnormal f32 bits (exp field 0) + if i % 2 == 0: + a = [0] * k # all-zero operands: output == carry-in (subnormal) + b = [fp16_subnormal(rng) for _ in range(k)] + else: + # +x / -x pairs that cancel exactly inside each group of 8. + a, b = [], [] + for u in range(k): + x = fp16_subnormal(rng) + a.append(x if u % 2 == 0 else (x ^ 0x8000)) # flip sign every other + b.append(1 << 10) # 2^-14 (smallest normal) so product = +/- x * 2^-14 + yield ("subnormal_output", k, a, b, sub_c) + + # 6. Grid-boundary products: operands whose product lands exactly on / just + # off the 2^(eta-24) alignment grid. + for _ in range(32): + k = int(rng.choice([8, 16, 64])) + a, b = [], [] + for _u in range(k): + # one big, rest small -> wide exponent spread within a group => dense truncation + if rng.integers(0, 4) == 0: + a.append(fp16_large(rng)); b.append(fp16_large(rng)) + else: + a.append(fp16_subnormal(rng)); b.append(fp16_normal(rng)) + yield ("grid_boundary", k, a, b, 0) + + # 7. Overflow edge: max-magnitude operands + a near-max-finite carry-in. + for _ in range(16): + k = 1024 + a = [fp16_large(rng) for _ in range(k)] + b = [fp16_large(rng) for _ in range(k)] + c = int(rng.choice([0, 0x7F7FFFFF, 0xFF7FFFFF])) # 0, +max, -max finite f32 + yield ("overflow_edge", k, a, b, c) + + +def run_capture(records: list[tuple[int, list[int], list[int], int]]) -> list[int]: + """Feed (k,a,b,c_bits) records to the silicon capture tool; return d_bits.""" + if not os.path.exists(CAPTURE_BIN): + sys.exit(f"capture tool not built: {CAPTURE_BIN}\n nvcc -arch=sm_80 -O2 -o a100_hmma_capture a100_hmma_capture.cu") + lines = [] + for k, a, b, c in records: + toks = [str(k)] + [str(x) for x in a] + [str(x) for x in b] + [str(c & 0xFFFFFFFF)] + lines.append(" ".join(toks)) + proc = subprocess.run( + [CAPTURE_BIN], input="\n".join(lines) + "\n", capture_output=True, text=True + ) + if proc.returncode != 0: + sys.exit(f"capture tool failed (rc={proc.returncode}):\n{proc.stderr}") + out = [int(x) for x in proc.stdout.split()] + if len(out) != len(records): + sys.exit(f"capture returned {len(out)} results for {len(records)} records") + return out + + +def main() -> int: + ap = argparse.ArgumentParser() + # Canonical location: the Rust cross-check test include_str!'s it from testdata. + default_out = os.path.join( + HERE, "..", "..", "..", "zk-pow", "src", "api", "fp16", "testdata", "a100_dot_vectors_k1024.txt" + ) + ap.add_argument("--out", default=default_out) + ap.add_argument("--seed", type=lambda s: int(s, 0), default=0xA100) + args = ap.parse_args() + + cats = {} + records = [] + meta = [] # (category, model_dbits_or_None_if_overflow) + for cat, k, a, b, c in gen_vectors(args.seed): + try: + model = ref.a100_dot_bits(a, b, c) + overflow = False + except OverflowError: + model, overflow = None, True + records.append((k, a, b, c)) + meta.append((cat, model, overflow)) + cats[cat] = cats.get(cat, 0) + 1 + + print(f"generated {len(records)} vectors: " + ", ".join(f"{k}={v}" for k, v in sorted(cats.items()))) + device = run_capture(records) + + agree = mism = overflow_finite = overflow_both = 0 + mismatches = [] + corpus = [] + for (k, a, b, c), (cat, model, overflow), dev in zip(records, meta, device): + dev_nonfinite = ((dev >> 23) & 0xFF) == 0xFF + if overflow: + # model aborts; silicon should be non-finite (inf) too. + if dev_nonfinite: + overflow_both += 1 + else: + overflow_finite += 1 + mismatches.append((cat, k, "model-overflow but device finite", hex(dev))) + continue + if dev == model: + agree += 1 + if not dev_nonfinite: + corpus.append((k, a, b, c, dev)) + else: + mism += 1 + mismatches.append((cat, k, f"model={hex(model)}", f"device={hex(dev)}")) + + print(f"\nfinite vectors: {agree} agree, {mism} MISMATCH") + print(f"overflow-flagged: {overflow_both} device-also-nonfinite, {overflow_finite} device-finite(!)") + if mismatches: + print("\n=== DIVERGENCES (model vs silicon) ===") + for m in mismatches[:50]: + print(" ", m) + + # Write the agreeing finite vectors as a committed corpus extension. + with open(args.out, "w") as f: + f.write("# A100 FP16 dot-product reference vectors (hardware-captured on sm_80).\n") + f.write(f"# Generated by docs/fp16_scheme/validation/generate_and_capture.py --seed {hex(args.seed)}\n") + f.write("# Device: run on NVIDIA sm_80 (A100/GA100/CMP 170HX) via real mma.sync.m16n8k16.f32.f16.\n") + f.write("# Covers k up to 1024 plus subnormal-operand/subnormal-acc/cancellation/grid-boundary edges.\n") + f.write("# format: k a_bits[k] b_bits[k] c_bits(u32 f32) d_bits(u32 f32)\n") + for k, a, b, c, d in corpus: + toks = [str(k)] + [str(x) for x in a] + [str(x) for x in b] + [str(c & 0xFFFFFFFF), str(d & 0xFFFFFFFF)] + f.write(" ".join(toks) + "\n") + print(f"\nwrote {len(corpus)} finite silicon-verified vectors to {args.out}") + return 1 if (mism or overflow_finite) else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/fp16_scheme/validation/rounding_mode_probe.py b/docs/fp16_scheme/validation/rounding_mode_probe.py new file mode 100644 index 000000000..537546d0d --- /dev/null +++ b/docs/fp16_scheme/validation/rounding_mode_probe.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +"""Empirically resolve the A100/sm_80 HMMA.16816.F32 rounding mode on silicon. + +The FP16 scheme's model (`zk-pow/src/api/fp16/accumulate.rs`) asserts the device +rounds **toward zero** (RZ), at two places: (1) each product/accumulator is +truncated toward zero onto the per-group `2^(eta-24)` alignment grid, and (2) the +per-group integer sum is rounded toward zero to FP32. The natural alternative is +round-to-nearest-even (RNE) at either place. If the real device used RNE where +the model uses RZ, miner and verifier would still agree with each other (both run +the model) and no in-tree check would catch it -- so this must be settled against +the hardware. + +Method: build four model variants (prod ∈ {rz,rne} × group ∈ {rz,rne}), search +random vectors for ones where the variants disagree, capture those on the real +tensor core, and report which variant the device matches. A clean result is: the +device matches (rz,rz) on every discriminating vector and none of the others. + +Usage: python3 rounding_mode_probe.py (needs the built capture tool + sm_80 GPU) +""" +from __future__ import annotations + +import os +import subprocess +import sys +import numpy as np + +sys.path.insert( + 0, + os.path.join(os.path.dirname(__file__), "..", "..", "..", "miner", "pearl-gemm", "tests", "helpers"), +) +import a100_fp16_reference as ref # noqa: E402 + +HERE = os.path.dirname(os.path.abspath(__file__)) +CAPTURE_BIN = os.path.join(HERE, "a100_hmma_capture") + + +def shift_round(x: int, s: int, mode: str) -> int: + """`x * 2^s` as an integer. Left shift if s>=0. Right shift (s<0) either + truncates toward zero ('rz') or rounds half-to-even ('rne').""" + if s >= 0: + return x << s + r = -s + if r >= 200: + return 0 + neg = x < 0 + a = -x if neg else x + if mode == "rz": + q = a >> r + else: # rne, half-to-even + q = a >> r + rem = a - (q << r) + half = 1 << (r - 1) + if rem > half or (rem == half and (q & 1)): + q += 1 + return -q if neg else q + + +def to_f32_bits(s: int, unit: int, mode: str) -> int: + """Round integer `s * 2^unit` to FP32 (24 sig bits; subnormal 2^-149 grid), + toward zero ('rz') or half-to-even ('rne'); return u32 bits.""" + if s == 0: + return 0 + neg = s < 0 + a = -s if neg else s + nb = a.bit_length() - 1 + keep = max(nb + unit - 23, ref._FP32_MIN_EXP) + drop = min(max(keep - unit, 0), 200) + if mode == "rz": + m = a >> drop + else: + m = a >> drop + if drop > 0: + rem = a - (m << drop) + half = 1 << (drop - 1) + if rem > half or (rem == half and (m & 1)): + m += 1 + truncated = m << drop + val = np.float64(-1.0 if neg else 1.0) * np.float64(truncated) * np.float64(2.0) ** np.float64(unit) + return int(np.float32(val).view(np.uint32)) + + +def dot_mode(a, b, c_bits, prod_mode, group_mode) -> int: + """a100_dot with selectable product-alignment and group-final rounding.""" + cur = c_bits & 0xFFFFFFFF + k = len(a) + g0 = 0 + while g0 < k: + g1 = min(g0 + ref.GROUP, k) + cs, cm, cel, culp = ref._acc_parts(cur) + eta = cel + for u in range(g0, g1): + _, ma, ea = ref.decompose_fp16(a[u]) + _, mb, eb = ref.decompose_fp16(b[u]) + if ma and mb: + eta = max(eta, ea + eb) + if eta == ref._NEG: + g0 = g1 + continue + unit = eta - ref.W + total = 0 + for u in range(g0, g1): + sa, ma, ea = ref.decompose_fp16(a[u]) + sb, mb, eb = ref.decompose_fp16(b[u]) + if not ma or not mb: + continue + prod = ma * mb + total += (sa * sb) * shift_round(prod, (ea + eb) - 20 - unit, prod_mode) + total += cs * shift_round(cm, culp - unit, prod_mode) + nb = to_f32_bits(total, unit, group_mode) + if (nb >> 23) & 0xFF == 0xFF: + return -1 # overflow + cur = nb + g0 = g1 + return cur & 0xFFFFFFFF + + +def run_capture(records): + lines = [] + for k, a, b, c in records: + lines.append(" ".join([str(k)] + [str(x) for x in a] + [str(x) for x in b] + [str(c & 0xFFFFFFFF)])) + proc = subprocess.run([CAPTURE_BIN], input="\n".join(lines) + "\n", capture_output=True, text=True) + if proc.returncode != 0: + sys.exit(f"capture failed: {proc.stderr}") + return [int(x) for x in proc.stdout.split()] + + +MODES = [("rz", "rz"), ("rz", "rne"), ("rne", "rz"), ("rne", "rne")] + + +def main() -> int: + rng = np.random.default_rng(0x2026) + # Find vectors that discriminate the rounding modes. Wide exponent spread + # within groups maximizes truncated low bits, so modes diverge often. + disc = [] + tries = 0 + while len(disc) < 400 and tries < 200000: + tries += 1 + k = int(rng.choice([8, 16, 64, 256])) + a, b = [], [] + for _ in range(k): + ea = int(rng.integers(1, 31)); ma = int(rng.integers(0, 1024)) + eb = int(rng.integers(1, 31)); mb = int(rng.integers(0, 1024)) + a.append((int(rng.integers(0, 2)) << 15) | (ea << 10) | ma) + b.append((int(rng.integers(0, 2)) << 15) | (eb << 10) | mb) + c = int(rng.integers(0, 1 << 32)) if rng.integers(0, 2) else 0 + if (c >> 23) & 0xFF == 0xFF: + continue + vals = [dot_mode(a, b, c, pm, gm) for pm, gm in MODES] + if -1 in vals: + continue + if len(set(vals)) > 1: # the modes disagree -> discriminating + disc.append((k, a, b, c, vals)) + + if not disc: + sys.exit("found no discriminating vectors (unexpected)") + records = [(k, a, b, c) for k, a, b, c, _ in disc] + device = run_capture(records) + + # Tally which mode the device matches. + match = {m: 0 for m in MODES} + device_matches_committed = 0 + device_matches_other = 0 + examples = [] + for (k, a, b, c, vals), dev in zip(disc, device): + matched_here = [] + for m, v in zip(MODES, vals): + if v == dev: + match[m] += 1 + matched_here.append(m) + if ("rz", "rz") in matched_here: + device_matches_committed += 1 + # does any NON-(rz,rz) mode give a DIFFERENT value than the device? (yes by construction on some) + if ("rz", "rz") not in matched_here: + device_matches_other += 1 + if len(examples) < 10: + examples.append((k, hex(c), {f"{pm},{gm}": hex(v) for (pm, gm), v in zip(MODES, vals)}, hex(dev))) + + n = len(disc) + print(f"discriminating vectors captured on silicon: {n} (from {tries} tries)") + print("device-matches-mode tally (a vector can match several modes when they happen to agree):") + for m in MODES: + tag = " <-- committed model" if m == ("rz", "rz") else "" + print(f" prod={m[0]:3} group={m[1]:3}: {match[m]:4}/{n}{tag}") + print(f"\ndevice matched committed (rz,rz) on {device_matches_committed}/{n} discriminating vectors") + print(f"device matched (rz,rz) on NONE: {device_matches_other}/{n}") + if examples: + print("\n=== vectors where the device did NOT match (rz,rz) -- would indicate the model is wrong ===") + for e in examples: + print(" ", e) + # A clean RZ result: every discriminating vector matches (rz,rz), and at least + # one other mode is excluded (i.e., (rz,rz) is not vacuously always-matching). + rz_rz = match[("rz", "rz")] + strictly_excluded = any(match[m] < n for m in MODES if m != ("rz", "rz")) + ok = (rz_rz == n) and strictly_excluded + print(f"\nVERDICT: device is round-toward-zero (RZ) at both stages: {'CONFIRMED' if ok else 'NOT CONFIRMED'}") + if ok: + other = [f"{pm}/{gm}={match[(pm,gm)]}/{n}" for pm, gm in MODES if (pm, gm) != ("rz", "rz")] + print(f" (committed (rz,rz) matched all {n}; alternatives excluded on some vectors: {', '.join(other)})") + return 0 if ok else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/fp16_scheme/zk_binding_design.md b/docs/fp16_scheme/zk_binding_design.md new file mode 100644 index 000000000..ecf31ca1c --- /dev/null +++ b/docs/fp16_scheme/zk_binding_design.md @@ -0,0 +1,325 @@ +# FP16 ZK proof — consensus-binding design (closing the two unbound gaps) + +Status: **IMPLEMENTED (operand + output + noise binding in-circuit; header +binding at the consensus verifier gateway); the header-bound ZK certificate is +the wired consensus path.** This records how the FP16 batched ZK proof +(`zk-pow/src/circuit/fp16/`) is bound to the consensus statement. The two +originally-open gaps below — operand provenance / cross-cell sharing and +output/ticket binding — are now closed and tested in-circuit (§8/§8b). Header +binding is enforced at the consensus verifier: the opening keys (`KEY_A`/`KEY_B`), +the public-parameter encoding `p`, and the jackpot key enter the STARK from the +caller, but `verify_wrapped_proof_with_headers` (`circuit::fp16::wrapper`) +re-derives them from the proposed/ancestor headers + committed operand roots, +derives the `statement_digest` from the proof's own `HASH_JACKPOT`, and pins the +whole public-input vector by equality before verifying — so the statement is +header-bound at consensus. **The wired consensus path is the header-bound ZK +certificate** (`CertificateV5` → `verify_fp16_zk_cert_ffi`); the earlier plaintext +certificate (`api::fp16::verify`) is retired. The remaining residual is +provisioning, not soundness: the per-shape wrapper needs an embedded verifier +cache covering every consensus-legal degree profile (or the universal wrapper, +§8) before V5 is activated. + +## 1. What the circuit proves today, and the gap + +The batch proves the *arithmetic*: the matmul AIR (`matmul_a100_stark`) proves +each output cell is the A100 `a100_dot` of its row's `operand_codes`, and the +policy AIR proves the jackpot gate over the matmul's tightly-pinned census. It +does **not** bind that computation to the consensus statement: + +1. **Operand provenance / cross-cell sharing (Finding 3).** `operand_codes_a/b` + are free witness. `FP16DECODE` only checks each code *decodes*; nothing ties a + code to the committed operand Merkle root, and nothing forces cells `(r,c1)`, + `(r,c2)` of one output row to reuse the same `A[r,:]` (or a column to reuse + `B[:,c]`). The AIR proves per-cell dot products over *arbitrary* operands. +2. **Output / ticket binding (Finding 4).** The output tile (`cell_result_f32_*`) + and census totals are not public inputs. `Fp16System::bind_statement_digest` + stores a **caller-supplied opaque** digest; the two main AIRs have **zero** + public inputs. The circuit never constrains the digest to commit the operands + or the tile, so a verified proof attests "some policy-passing tile of this + geometry exists," not "this block's committed matmul." + +### 1a. The noise subtlety the FP8 mechanism does not cover + +In the real scheme the matmul is **not** over the committed rows. The plaintext +verifier (`api::fp16::verify::verify_tile`) does: + +``` +raw committed rows --(noise derived from the committed root)--> N = E @ F^T +noised = Q(alpha*raw + beta*N) (per-row scales; f32 FMA; FP16 cast) +tile = a100_matmul(noised_A, noised_B) +``` + +So `operand_codes` fed to the matmul must equal the **noised** operands, which are +a deterministic function of (committed raw codes, seed-derived noise). A correct +binding therefore cannot connect the matmul operands directly to the commitment +(as the FP8 single-hop analogy suggests). It must prove the whole chain +`committed raw -> noise -> noisy_quantize -> noised`, and the noise must itself be +bound to the committed root — otherwise a prover grinds the noise draw. FP8 hides +its noise inside `input_quant_stark`'s FMA; FP16 dropped that table and has **no** +noise stage in-circuit yet. These are exactly the `FP16 noisy-quant / noise-line / +tensor-hash` pieces the PR lists as deferred follow-ons. + +## 2. FP8 reference architecture (what to mirror) + +FP8 batch = 5 main AIRs + 15 LUTs (`circuit/fp8/ctl.rs:58-67,95`). Binding-relevant: + +| FP8 table | role | FP16 relevance | +|---|---|---| +| **Blake3** (`blake3_stark`) | keyed-BLAKE3 Merkle roots over committed bytes → `HASH_A/HASH_B` PIs; folds XorFold's 16 lottery words → `HASH_JACKPOT` PI | **reuse (simplified)** | +| **InputQuant** (`input_quant_stark`) | int8+bf16-scale decode, QCAST, **noise FMA** | **replace** with an FP16 noisy-quant table (different math; no int8/scale) | +| **Scale** (`scale_stark`) | prequant L2 norm / σ chain | **drop** (FP16 commits raw u16, no prequant) — but the FP16 noisy-quant needs its own `row_norms`/`derive_row_scales` sub-logic | +| **Matmul** (`matmul_h100`/`matmul_b200_stark`) | the dot products | **have it** (`matmul_a100_stark`) | +| **XorFold** (`xor_fold_stark`) | f32 cell results → 16 lottery lane words | **reuse (~verbatim)** | + +Binding CTL channels (`circuit/fp8/ctl.rs:160-170`): +- **operand codes**: `InputQuant (looked) <-> Matmul (looking)`, keyed by element + index; **cross-cell sharing is enforced by a multiplicity on the looked side** — + A elements carry multiplicity `w`, B elements `h` (`input_quant_stark/ctl.rs: + 121-157`). Cells in a row emit the same `operand_index_base` key, so differing + per-cell operands cannot balance the single multiplicity-`w` looked tuple. +- **results**: `Matmul (looked) <-> XorFold (looking)`, tuple `(cell_id, + result_lo, result_hi, skips)`, filter `is_cell_final*(1-is_padding)`. +- **lottery words**: `XorFold (looked) <-> Blake3 (looking)`, 16 `(lane_id, + fold_out)` tuples → the jackpot block Blake3 hashes to `HASH_JACKPOT`. + +Statement binding (`fp8/driver.rs:805,852,873`): `HASH_A/HASH_B/HASH_JACKPOT` are +Blake3 public inputs; `verify` forces `proof.public_inputs == +batch_public_inputs(expected)` where the caller supplies the header-derived roots +and jackpot hash; difficulty is a **native** epilogue `check_jackpot_difficulty( +HASH_JACKPOT, nbits, h, w, k)` (`api/proof_utils.rs:123`). `statement_digest` is a +separate FS salt derived from the proven jackpot hash. + +## 3. The full FP16 binding chain to build + +``` + keyA = H(proposed_header) keyB = H(ancestor_header) + | | + committed raw A rows (u16) --Blake3 Merkle--> HASH_A HASH_B <-- raw B rows + | (root -> seed chain, B then A) | + +------------- seed_A, seed_B ---------+ + | + noise-line (BLAKE3 XOF -> normalize: isqrt + bf16 div) -> E_A,F_A,E_B,F_B + | + noise matmul N = E @ F^T (an a100_matmul instance) + | + noisy-quant: noised = Q(alpha*raw + beta*N) (row_norms, derive_row_scales + | in bf16; f32 FMA; FP16 cast) + main matmul tile = a100_matmul(noised_A, noised_B) + | | + policy gate (census) XorFold -> 16 lane words + | + Blake3 jackpot hash -> HASH_JACKPOT + | + native: check_jackpot_difficulty(HASH_JACKPOT, nbits, h,w,k) +``` + +Every arrow is a CTL (or a committed-root/public-input equality). The security +load-bearing links: raw↔root (provenance), seed↔root (anti-grind noise), +noise↔noised↔matmul-operands (the noised codes are what gets multiplied), tile↔ +ticket↔difficulty (work actually counts), and root/jackpot↔header PIs. + +## 4. New components + +**New STARKs (FP16 batch grows 6 → ~5 main + LUTs; update `NUM_FP16_MAIN_TABLES`, +batch order, `batch_public_inputs`):** + +1. `fp16/blake3_stark` — mirror `fp8/blake3_stark`, **simplified**: one keyed + Merkle root per operand over u16 LE rows (no second scales tree, no two-plane + `operand_digest_fp10` fold, drop routing/offsets PIs unless MoE is in scope); + plus the lottery-words → `HASH_JACKPOT` compression. PIs: `KEY_A`, `KEY_B`, + `POW_KEY`, `HASH_A`, `HASH_B`, `HASH_JACKPOT`. Must also expose the seed-chain + outputs (or a dedicated small AIR) so the noise stage keys off the proven root. +2. `fp16/noise_stark` (**net-new, no FP8 analogue**) — proves the noise-line draw: + per factor, keyed-BLAKE3 XOF of the `side|factor|line` address under the seed, + then `normalize_line` (signed magnitudes → integer `isqrt` → one bf16 division → + FP16 cast). Mirrors `api/fp16/noise.rs` bit-for-bit. +3. `fp16/noisy_quant_stark` (**net-new**, replaces FP8 `input_quant_stark`) — + proves `noised = Q(alpha*raw + beta*(E@F^T))`: `row_norms` (L2/Linf in bf16, + grid-rounded), `derive_row_scales` (`alpha,beta` in bf16), the f32 FMA, the FP16 + round, and the `[-MAX_FP16, MAX_FP16]` clamp. Mirrors `api/fp16/quantization.rs`. + The `N = E@F^T` can be a second instance of `matmul_a100_stark` (it is literally + `a100_matmul(E, F)`), avoiding a bespoke AIR. +4. `fp16/xor_fold_stark` — mirror `fp8/xor_fold_stark` ~verbatim (f32 cell results + → 16 lottery words; RC16 limbs already shared). + +**New CTL channels** (add to `fp16/ctl.rs::all_cross_table_lookups`, currently 5): +- `Blake3 (looked, raw bytes) <-> NoisyQuant (looking)` — binds raw committed u16 + to the noisy-quant input (value = `byte_lo + 2^8*byte_hi`; stride 1, no pairing). +- `NoiseStark (looked E/F) <-> {noise-matmul, NoisyQuant} (looking)` — binds the + noise factors into N and into the `beta*N` term. +- `NoisyQuant (looked noised codes) <-> Matmul (looking)` — the **operand** channel; + carries the **multiplicity `w`/`h`** (A reused in `w` cells, B in `h`) exactly as + `input_quant_stark/ctl.rs:121-157`, closing provenance **and** cross-cell sharing. +- `Matmul (looked results) <-> XorFold (looking)` — the results channel. +- `XorFold (looked lane words) <-> Blake3 (looking)` — the lottery-words channel. +- seed-chain binding: root PIs → noise seeds (CTL or in-Blake3 constraint). + +**Driver/verify wiring:** publish `HASH_A/HASH_B/HASH_JACKPOT` (+ keys) as batch +PIs (`fp16/driver.rs` `batch_public_inputs`), force them equal to header-derived +expected PIs in `verify` (mirror `fp8/driver.rs:852`), derive the FS salt from the +proven jackpot hash (mirror `fp8/driver.rs:805`), and keep difficulty native via +`check_jackpot_difficulty`. This is what upgrades `statement_digest` from opaque to +statement-committing. + +## 5. Reuse vs net-new + +- **Reuse ~verbatim:** `xor_fold_stark`; the Blake3 hashing engine, byte-pair + message channel, and commit-fold wrapper; the LUT oracle machinery (already + shared); the `statement_digest`/known-column/wrapper plumbing (already present in + `fp16/driver.rs`); `check_jackpot_difficulty`, `xor_fold_extract`, + `compute_jackpot_ticket` (native, scheme-neutral). +- **Net-new (no FP8 analogue):** `noise_stark` (BLAKE3-XOF + normalize) and + `noisy_quant_stark` (bf16 scale derivation + f32 FMA + FP16 cast). These are the + deferred `noise-line` / `noisy-quant` pieces and carry the most new constraint + surface (bf16 arithmetic, `isqrt`). +- **Drop:** `scale_stark`, the int8 path of `input_quant_stark`, QCAST/Div448 and + the two-plane commitment fold. + +## 5a. Blake3 reuse — UNBLOCKED and delivered (investigated, then built) + +The FP8 `Blake3Stark` AIR is a general, program-driven BLAKE3 engine. The initial worry was +that `Blake3Program::from_blake_program` (`circuit/fp8/blake3_stark/stark.rs:435`) hard-asserts +the FP8 prequant four-plane shape (`A values / A scales / B values / B scales`) and panics on +anything else, and that there is no FP16 commitment→program compiler. **That turned out to be +only a limitation of the `from_blake_program` bridge, not of the engine.** The engine is +genuinely scheme-neutral at the `Blake3Instruction` / `generate_trace` level: + +* `Blake3Instruction::lottery()` already exists (the jackpot compression); +* `generate_trace` already supports per-plane `HashId` leaf padding; +* a single keyed Merkle-tree root can bind **directly** to `HASH_A`/`HASH_B` (no FP8 commit-fold + wrapper needed), keyed by `KEY_A`/`KEY_B`. + +So the remediation was just §5a-item-2: a **new FP16-specific `Blake3Program` constructor** that +assembles the `Blake3Instruction` list directly, bypassing `from_blake_program`. **No shared +code was changed, and no separate commitment-program compiler was needed.** This is delivered in +`circuit/fp16/blake3_commit.rs`: + +* `jackpot_program()` / `operand_tree_program()` / `fp16_blake3_program()` build the programs; +* `append_operand_tree()` compiles one operand's keyed tree (BLAKE3 chunk per leaf, keyed parent + merges with odd-tail promotion, root on the top merge) **bit-exact with + `pearl_blake3::MerkleTree::with_chunk_len`** for every allowed leaf size (128/256/512/1024); +* `HASH_A`/`HASH_B` match `api::fp16::commitment::commit_operand(...).root()` and `HASH_JACKPOT` + matches `api::fp8::transcript::compute_jackpot_ticket`, both verified across shapes/sizes; +* parameterized CTL hooks (`ctl_lottery_words_looking_blake3`, `ctl_operand_bytes_looking_blake3`) + are exposed for the batch-wiring step (counterparties: `xor_fold` and `noisy_quant`). + +What remains is **only** the batch wiring (§6 step-by-step): register the table in +`circuit::fp16::ctl`, publish `HASH_A/HASH_B/HASH_JACKPOT` as driver public inputs forced equal +to header-derived values in `verify`, and wire the operand-bytes / lottery-words CTLs. Until +that, the program proves "there exist operands/lottery words whose keyed-BLAKE3 roots are these +PIs," not yet that they are *the committed* operands. + +## 6. Incremental, reviewable build order + +Each step is independently testable (honest-serves + tamper-rejects, like the +existing `consistency.rs` / `ctl.rs` tests) and should NOT be merged as a partial +"binding" — a half-bound proof looks bound but is not, so the chain lands behind a +single activation only once complete. + +1. `xor_fold_stark` + results channel + lottery-words channel + `blake3_stark` + jackpot-hash + `HASH_JACKPOT` PI + native difficulty. (Output/ticket binding — + Finding 4, for the *current* raw-operand matmul.) +2. `blake3_stark` Merkle roots + `HASH_A/HASH_B` PIs + header-equality in verify. +3. `noise_stark` + `noisy_quant_stark` + noise-matmul instance + the raw↔noised↔ + matmul-operand channels with `w`/`h` multiplicity. (Operand provenance + the + noise pipeline — Finding 3 + §1a.) +4. Seed-chain binding (root → seeds) so noise is anti-grind. +5. Wrapper: carry the new PIs; re-run the constant-size + tamper tests. + +## 7. Risks / open questions + +- **bf16 / isqrt in-AIR.** `normalize_line` and `derive_row_scales` use bf16 + mul/div/fma and an integer `isqrt`; these need degree-≤3 constraint designs + (FP8's bf16 LUTs — `Div448`, etc. — are a starting point but FP16 uses different + constants). Highest new-constraint risk. +- **Trace height.** The noise matmul `E@F^T` is `num_rows x k` by `k x r` — another + large table; folds into the existing height budget (`stark_feasibility.md §4`). +- **MoE / routing.** Out of scope; FP16 is dense (`CertificateV5::IsMoE()==false`), + so the routing/offsets Blake3 PIs are dropped. +- Until §6 steps 1–4 all land and the wrapper carries the PIs, the ZK proof must + remain flagged as not-a-consensus-path (see `circuit::fp16` module docs). + +## 8. Build status (implemented, by increment) + +All of the FP16 ZK binding below is implemented, batched, and tested +(`cargo test --lib circuit::fp16`, 152 green, 0 ignored at the final increment §8b, incl. the recursive wrapper): + +- **XorFold AIR** + **noise-line normalization AIR** + **noisy-quant AIR** (G1 mul, + G2 single-rounding f32 FMA, G3 cast incl. subnormal/zero) + **per-row scale AIR** + (row_norms + derive_row_scales) — all bit-exact vs their `api::fp16` ground truth, + all ties-to-even uniquely pinned (IS_BOTTOM, no quarter-ulp grinding slack). +- **Blake3 commitment program** (operand trees → `HASH_A/HASH_B` bit-exact vs + `commit_operand`; jackpot hash → `HASH_JACKPOT`) reusing the shared engine unchanged. +- **Output chain wired**: matmul results → XorFold → Blake3 jackpot → `HASH_JACKPOT`, + statement digest derived from the proven jackpot, native `check_jackpot_difficulty` + matching the plaintext decision. +- **Operand chain wired (Finding 3 CLOSED)**: committed bytes (`HASH_A/HASH_B`) → `raw` + → quant `Q(·)` → noised → matmul operand codes, with the `w`/`h` reuse multiplicity + that also forces cross-cell row/column sharing. Fail-closed tamper tests on every link. +- **Noise chain**: `N = E@F^T` proven (two per-side noise matmuls, distinct `F_A/F_B` + matching the plaintext); `E/F` bound to the normalized noise lines proven by the + noise AIR. +- A **latent G2 FMA rounding bug** (opposite-sign cancellation ties) was found and + fixed (sign-aware sticky) when real noise first exercised it. + +### 8a. The one remaining gap: seed→XOF binding (6e-3) — blocked on shared-AIR egress + +The raw keyed-BLAKE3-XOF bytes that the noise AIR normalizes are still **free witness**, +and the noise seeds are fixed constants rather than derived from the committed roots. So +a prover can still **grind the noise** by choosing those bytes. Closing this requires +proving, in-circuit, `seedB=H(root_B‖keyB‖pB)`, `seedA=H(root_A‖seedB‖keyA‖pA)` and each +line's keyed XOF, then binding the XOF **output** bytes to the noise AIR's input. + +This is **blocked under "reuse the shared Blake3 AIR unchanged"**: the shared +`circuit/fp8/blake3_stark` exposes a compression's **output** `cv_out` only internally +(CV-routing, keyed by row index) and to fixed public-input hash slots — there is **no +byte-decomposed, program-keyed, cross-table egress of `cv_out`**, which is exactly what +binding the per-line XOF output needs. A "seed-chain only" subset is not useful: the +seeds are a pure function of public values, but the prover grinds the XOF *bytes* +directly and never needs the seed, so only the output→noise-AIR byte binding reduces the +grindable surface. + +The sound closures both have cost: +- **(A) Extend the shared Blake3 AIR** with an additive output-egress CTL channel (a new + finalization-row readout of `cv_out`, keyed by a program base) + recompute seeds + natively as public inputs. Smallest closure, but it changes the Blake3 **column + layout** that FP8's *active* V4 consensus ZK path commits to — a consensus-compatibility + change (circuit digest / trusted-setup / existing proofs) that needs explicit sign-off. +- **(B) Fork a FP16-specific Blake3 AIR** with the egress feature, leaving the FP8 engine + byte-for-byte untouched. Consensus-safe for FP8, but ~3.6k lines duplicated. +- **(C) Leave as the documented final gap.** Everything else is bound; noise remains + grindable (weakens anti-precompute, does not forge the matmul/output). + +(Decision: option (B), the Blake3 fork — see §8b; 6e-3 is now CLOSED.) + +Until (A) or (B) lands, the FP16 ZK proof binds the committed operands and the +output/ticket but not the noise derivation; it is a succinct proof of "the committed +operands, noised by *some* low-rank E@F, yield this policy-passing tile and jackpot." + +### 8b. Update — 6e-3 CLOSED via the Blake3 fork (anti-grind achieved) + +The §8a gap is now closed (decision: fork, not modify the shared engine): +- **6e-3a** forked the BLAKE3 AIR into `circuit/fp16/blake3_fp16_stark` with an additive + output-egress CTL channel (cv_out → 16-bit limbs, flag-gated). FP8's engine is untouched + (changes under `circuit/fp8` are additive-only — two new `LutTable` variants + `Fp16Decode`/`Fp16Pow2` in `circuit/fp8/luts/`, consumed solely by the FP16 + batch; no existing FP8 table's layout/`slot_height` changes and the shared + BLAKE3 engine is byte-for-byte untouched), fp8 tests green. +- **6e-3c** built `circuit/fp16/noise_blake3.rs` on the fork: 2 subkey compressions + the + `h+w+2k` per-line keyed-XOF compressions (public material pinned), egressing each line's + bytes and binding them to NoiseStark via the egress CTL — closing the free-witness-bytes grind. +- **6e-3d** derives the seeds natively from the committed roots + (`noise_seeds(HASH_A/HASH_B, keys, p)`) and pins the noise-BLAKE3 `KEY_A/KEY_B` to them in + `verify`, so the noise is operand-dependent and matches the plaintext — anti-grind achieved. + +**The in-circuit FP16 ZK binding is now in place and tested** (`cargo test --lib circuit::fp16`: +152 green, 0 ignored, incl. the recursive wrapper): committed operand roots → seed-derived noise → +noised operands → matmul (cross-cell sharing) → policy → lottery tile → `HASH_JACKPOT` → statement +digest → native difficulty, every link fail-closed. **Header binding is enforced at the consensus +verifier gateway** (`verify_wrapped_proof_with_headers`): the opening keys and `p` are supplied to +the STARK by the caller, but the verifier re-derives KEY_A/KEY_B/jackpot-key + noise seeds from the +proposed/ancestor headers and committed roots and pins the whole public-input vector by equality, +so the statement digest is header-bound at consensus. The header-bound ZK certificate (`CertificateV5`) +is the wired consensus path; the plaintext certificate is retired. **One residual remains, and it is +provisioning not soundness:** the per-shape wrapper needs an embedded verifier cache covering every +consensus-legal degree profile (or the universal wrapper, §8) before V5 is activated on a network. diff --git a/miner/miner-base/src/miner_base/async_loop_manager.py b/miner/miner-base/src/miner_base/async_loop_manager.py index 1e0adb065..c33c29b3a 100644 --- a/miner/miner-base/src/miner_base/async_loop_manager.py +++ b/miner/miner-base/src/miner_base/async_loop_manager.py @@ -20,9 +20,12 @@ from .block_submission import ( OpenedBlockInfo, - is_plain_fp8_job, + Scheme, + is_submittable_plain_job, + scheme_of, submit_opened_block, ) +from .fp16_block_submission import Fp16OpenedBlock, submit_fp16_block from .gateway_client import DummyMiningClient, MinerRpcConfig, MiningClient from .settings import MinerSettings @@ -30,6 +33,11 @@ _DRAIN_PROGRESS_LOG_INTERVAL_SECONDS = 5.0 _MAX_STALE_JOB_POLLS = 3 +# The opening payload a submission carries: the FP8 (v4) planes+indices opening +# or the FP16 (v5) full-operand tile opening. Both expose ``owned_copy()`` for +# the asynchronous handoff; ``_submit_block`` dispatches construction by scheme. +SubmittableBlock = OpenedBlockInfo | Fp16OpenedBlock + @dataclass(frozen=True) class MiningLaunchDecision: @@ -478,7 +486,7 @@ def _release_pending_submission_ownership(self) -> None: def _enqueue_submission( self, - opened_block_info: OpenedBlockInfo, + opened_block_info: SubmittableBlock, mining_job: MiningJob, *, timeout: float | None, @@ -489,7 +497,7 @@ def _enqueue_submission( if ( self._conf.no_gateway or self._conf.skip_block_submission - or not is_plain_fp8_job(mining_job) + or not is_submittable_plain_job(mining_job) ): return False @@ -524,12 +532,16 @@ def _enqueue_submission( def handle_submit_block( self, - opened_block_info: OpenedBlockInfo, + opened_block_info: SubmittableBlock, mining_job: MiningJob, *, timeout: float | None = None, ) -> bool: - """Reserve bounded capacity, applying backpressure before ownership transfer.""" + """Reserve bounded capacity, applying backpressure before ownership transfer. + + Accepts either scheme's opening (FP8 ``OpenedBlockInfo`` or FP16 + ``Fp16OpenedBlock``); the executor builds and submits the matching proof. + """ return self._enqueue_submission( opened_block_info, mining_job, @@ -566,7 +578,7 @@ def _submission_finished( def _submit_block( self, - opened_block_info: OpenedBlockInfo, + opened_block_info: SubmittableBlock, mining_job: MiningJob, ) -> bool: if self._conf.no_gateway or self._conf.skip_block_submission: @@ -580,20 +592,52 @@ def _submit_block( self._inflight_clients.add(client) try: with client: - proof = submit_opened_block(opened_block_info, mining_job, client) + proof = self._build_and_submit_proof(opened_block_info, mining_job, client) finally: with self._inflight_lock: self._inflight_clients.discard(client) if proof is None: _LOGGER.info("Lottery winner was not jackpot-admissible; filtered before RPC.") return False - _LOGGER.info("FP8 proof handed to the gateway submission queue.") + _LOGGER.info( + f"{scheme_of(mining_job).value} proof handed to the gateway submission queue." + ) return True + def _build_and_submit_proof( + self, + opened_block_info: SubmittableBlock, + mining_job: MiningJob, + client: MiningClient, + ): + """Dispatch proof construction/verification/submission by scheme. + + The submission plumbing (capacity, backpressure, one-shot clients) is + scheme-agnostic; only this dispatch knows FP8 vs. FP16. Keeping the FP8 + branch calling ``submit_opened_block`` verbatim leaves the v4 datapath + byte-identical. + """ + scheme = scheme_of(mining_job) + if scheme is Scheme.FP8: + if not isinstance(opened_block_info, OpenedBlockInfo): + raise TypeError("an FP8 (v4) job requires an OpenedBlockInfo opening") + return submit_opened_block(opened_block_info, mining_job, client) + if scheme is Scheme.FP16: + if not isinstance(opened_block_info, Fp16OpenedBlock): + raise TypeError("an FP16 (v5) job requires an Fp16OpenedBlock opening") + return submit_fp16_block(opened_block_info, mining_job, client) + raise ValueError( + f"cert version {int(mining_job.cert_version)} is not a submittable plain scheme" + ) + def _classify_mining_launch_locked(self, job: MiningJob) -> MiningLaunchDecision: if job != self._mining_job: return MiningLaunchDecision(False, False) - if self._conf.no_gateway or self._conf.skip_block_submission or not is_plain_fp8_job(job): + if ( + self._conf.no_gateway + or self._conf.skip_block_submission + or not is_submittable_plain_job(job) + ): # The useful runtime may still execute and credit work, but it must # not inspect, construct, verify, or submit a winner. return MiningLaunchDecision(True, False) diff --git a/miner/miner-base/src/miner_base/block_submission.py b/miner/miner-base/src/miner_base/block_submission.py index cbd914dbf..205c4acb7 100644 --- a/miner/miner-base/src/miner_base/block_submission.py +++ b/miner/miner-base/src/miner_base/block_submission.py @@ -17,6 +17,7 @@ from pearl_gateway.comm.dataclasses import MiningJob from pearl_mining import ( CERT_VERSION_PLAIN_FP8, + Fp16PlainProof, IncompleteBlockHeader, PlainProofV4, verify_plain_proof_for_cert_version, @@ -40,6 +41,13 @@ from .layout import AxisPattern from .mining_config import COMMITMENT_CHUNK_SIZE from .prequant import DEFAULT_BLOCK_SIZE +from .schemes import ( + Scheme, + is_plain_fp8_job, + is_plain_fp16_job, + is_submittable_plain_job, + scheme_of, +) # The pearl_mining binding currently exposes only ``(bool, str)``. Keep this # exact consensus-policy message narrow until the binding exposes an error code. @@ -59,7 +67,9 @@ def commit_planes_for_leaf( class PlainProofClient(Protocol): - def submit_plain_proof(self, plain_proof: PlainProofV4, mining_job: MiningJob) -> None: ... + def submit_plain_proof( + self, plain_proof: PlainProofV4 | Fp16PlainProof, mining_job: MiningJob + ) -> None: ... @dataclass(frozen=True) @@ -146,11 +156,6 @@ def owned_copy(self) -> "OpenedBlockInfo": ) -def is_plain_fp8_job(job: MiningJob) -> bool: - """Whether the issuing endpoint advertised certificate-v4 FP8 through ``job``.""" - return int(job.cert_version) == CERT_VERSION_PLAIN_FP8 - - def _validate_plane(plane: torch.Tensor, name: str, dtype: torch.dtype) -> None: if not isinstance(plane, torch.Tensor): raise ValueError(f"{name} must be a torch.Tensor, got {type(plane).__name__}") @@ -480,7 +485,11 @@ def submit_opened_block( "OpenedBlockInfo", "PrebuiltCommitment", "PlainProofClient", + "Scheme", "create_proof", "is_plain_fp8_job", + "is_plain_fp16_job", + "is_submittable_plain_job", + "scheme_of", "submit_opened_block", ] diff --git a/miner/miner-base/src/miner_base/devices.py b/miner/miner-base/src/miner_base/devices.py index 348dc8d1e..477b9fbaa 100644 --- a/miner/miner-base/src/miner_base/devices.py +++ b/miner/miner-base/src/miner_base/devices.py @@ -11,33 +11,47 @@ from .params import Device # Compute-capability majors with a committed mining Device. +_AMPERE_CC_MAJOR = 8 _HOPPER_CC_MAJOR = 9 _BLACKWELL_CC_MAJOR = 10 # SM120's warp-level FP8 MMA reproduces the Blackwell atom arithmetic bit for bit. _SM120_CC_MAJOR = 12 -def device_for_capability(major: int, minor: int = 0) -> Device: +def device_for_capability(major: int, minor: int = 0, *, allow_fp16: bool = False) -> Device: """Map a CUDA compute capability to the committed mining ``Device``. - SM90 (Hopper: H100/H200) -> ``Device.HOPPER`` - SM100 (Blackwell: B200/B300) -> ``Device.BLACKWELL`` - SM120 (RTX PRO 6000, RTX 50) -> ``Device.BLACKWELL`` (same atom arithmetic) + - SM80 (Ampere: A100/GA100) -> ``Device.A100`` **only** when ``allow_fp16``. - Every other capability raises ``ValueError`` (``minor`` only names the - capability in that error). + ``allow_fp16`` is the FP16/v5 opt-in: the FP8 (v4) datapath never passes it, + so sm_80 stays rejected for FP8 exactly as before. Every other capability + raises ``ValueError`` (``minor`` only names the capability in that error). """ if major == _HOPPER_CC_MAJOR: return Device.HOPPER if major in (_BLACKWELL_CC_MAJOR, _SM120_CC_MAJOR): return Device.BLACKWELL + if allow_fp16 and major == _AMPERE_CC_MAJOR: + return Device.A100 raise ValueError(f"no committed mining Device for sm{major}{minor}") -def local_device(device: torch.device | int | None = None) -> Device: - """The committed ``Device`` matching ``device``'s FP8 MMA (the current CUDA - device when omitted). Fails closed on anything without a committed device.""" - return device_for_capability(*torch.cuda.get_device_capability(device)) +def local_device(device: torch.device | int | None = None, *, allow_fp16: bool = False) -> Device: + """The committed ``Device`` matching ``device``'s MMA (the current CUDA + device when omitted). Fails closed on anything without a committed device; + ``allow_fp16`` additionally admits sm_80 as ``Device.A100`` for the FP16 + scheme.""" + return device_for_capability( + *torch.cuda.get_device_capability(device), allow_fp16=allow_fp16 + ) -__all__ = ["device_for_capability", "local_device"] +def is_fp16_capable(device: torch.device | int | None = None) -> bool: + """Whether ``device`` is an sm_80 (A100/GA100) that runs the FP16 scheme.""" + return torch.cuda.get_device_capability(device)[0] == _AMPERE_CC_MAJOR + + +__all__ = ["device_for_capability", "is_fp16_capable", "local_device"] diff --git a/miner/miner-base/src/miner_base/fp16_block_submission.py b/miner/miner-base/src/miner_base/fp16_block_submission.py new file mode 100644 index 000000000..e429f7404 --- /dev/null +++ b/miner/miner-base/src/miner_base/fp16_block_submission.py @@ -0,0 +1,313 @@ +"""FP16 (A100) plaintext certificate assembly: winner -> ``Fp16PlainProof``. + +The FP16 analogue of :func:`miner_base.block_submission.create_proof`. Given the +FULL committed FP16 operands, the public job parameters, and which lottery tile +won (``tile_row`` / ``tile_col``, or an explicit tile base), it commits both +operand trees (bit-exact to the miner's GPU ``fp16_commit`` so the roots -- and +therefore the whole seed chain and the jackpot ticket -- match the search), +opens each at the winning tile's GLOBAL rows, and assembles the wire +``pearl_mining.Fp16PlainProof``. + +Why the FULL operands (not just the opened strip): the noise-seed chain binds the +full ``m x k`` / ``n x k`` Merkle roots, so the certificate tree must be the same +one the search committed. The verifier re-derives ``seedA`` from those roots and +replays the opened tile; a per-tile re-commitment would change the root -> the +seed -> the noise -> the tile, and the winning ticket would not reproduce. + +Tiling (the #7 reconciliation): the committed A100 patterns are *contiguous* +(``P.tile_offsets() == range(P.tile_size())`` with ``P.total() == P.tile_size()``), +so tile ``(tr, tc)`` opens the contiguous global rows ``range(tr*h, tr*h+h)`` / +``range(tc*w, tc*w+w)`` -- exactly how ``pearl_gemm.fp16_miner.search_block`` / +``fp16_search`` slice a hit. Those global indices are passed straight through as +the opening's ``row_indices``; the Rust ``parse_proof`` accepts them as +``base + tile_offsets()`` (``base = tr*h``; ``base == 0`` is the origin tile) and +keys the ``E`` noise lines on them, matching the full-matrix search. + +Needs the ``pearl_mining`` extension (py3.13 here); the opener in +:mod:`miner_base.fp16_commitment` is torch-free and interpreter-agnostic. +""" + +from __future__ import annotations + +from dataclasses import dataclass, replace +from typing import TYPE_CHECKING, Sequence + +import pearl_mining + +from .fp16_commitment import ( + DEFAULT_HASH_ID, + Fp16MatrixMerkleProof, + commit_fp16_operand, + key_a as fp16_key_a, + key_b as fp16_key_b, + rows_to_bytes, +) +from .layout import AxisPattern +from .params import HashId + +if TYPE_CHECKING: + from pearl_gateway.comm.dataclasses import MiningJob + + from .block_submission import PlainProofClient + +__all__ = [ + "NOISE_RANK", + "Fp16OpenedBlock", + "create_fp16_proof", + "submit_fp16_block", +] + +# The FP16 scheme's fixed noise rank (``zk-pow/src/api/fp16/params.rs``). +NOISE_RANK = 32 + +_NATIVE_HASH_ID = { + HashId.BLAKE3_CHUNK_128: pearl_mining.HashId.Blake3Chunk128, + HashId.BLAKE3_CHUNK_256: pearl_mining.HashId.Blake3Chunk256, + HashId.BLAKE3_CHUNK_512: pearl_mining.HashId.Blake3Chunk512, + HashId.BLAKE3_CHUNK_1024: pearl_mining.HashId.Blake3Chunk1024, +} + + +def _header_bytes(header: object) -> bytes: + """The 76-byte serialized header from raw bytes or any ``.to_bytes()`` form.""" + if isinstance(header, (bytes, bytearray, memoryview)): + raw = bytes(header) + else: + raw = bytes(header.to_bytes()) + if len(raw) != 76: + raise ValueError(f"block header must be exactly 76 bytes, got {len(raw)}") + return raw + + +def _native_merkle_proof(opening: Fp16MatrixMerkleProof) -> pearl_mining.MerkleProof: + """Rebuild the opener's (``pearl_blake3``) multi-leaf proof as the verifier's + own ``pearl_mining.MerkleProof`` type (the two extensions are distinct shared + objects, so the Rust type cannot be shared across them -- mirrors the FP8 + ``_native_merkle_proof``).""" + p = opening.proof + return pearl_mining.MerkleProof( + [bytes(leaf) for leaf in p.leaf_data], + list(p.leaf_indices), + bytes(p.root), + [bytes(sibling) for sibling in p.siblings], + p.total_leaves, + ) + + +def _native_matrix_proof(opening: Fp16MatrixMerkleProof) -> pearl_mining.Fp16MatrixProof: + return pearl_mining.Fp16MatrixProof(_native_merkle_proof(opening), list(opening.row_indices)) + + +def _native_pattern(pattern: AxisPattern) -> pearl_mining.AxisPattern: + """A :class:`miner_base.layout.AxisPattern` as the verifier's own type, via + its canonical committed wire form (mirrors the FP8 ``_native_operand``).""" + return pearl_mining.AxisPattern.from_bytes(bytes(pattern.to_bytes())) + + +def _tile_indices(pattern: AxisPattern, tile_index: int, num_rows: int, name: str) -> list[int]: + """The GLOBAL opened rows for tile number ``tile_index`` along this axis: + ``base + P.tile_offsets()`` with ``base = tile_index * P.tile_size()`` (the + contiguous-layout tile base). Validates the base is a legal periodic offset + and the whole tile fits in ``num_rows``.""" + offsets = pattern.tile_offsets + base = int(tile_index) * pattern.tile_size + if base < 0 or not pattern.offset_is_valid(base): + raise ValueError(f"{name}: tile {tile_index} base {base} is not a valid periodic tile offset") + indices = [base + off for off in offsets] + if indices[-1] >= num_rows: + raise ValueError( + f"{name}: tile {tile_index} selects row {indices[-1]} outside [0, {num_rows})" + ) + return indices + + +def create_fp16_proof( + proposed_header: object, + a_full: object, + b_full: object, + *, + k: int, + m: int, + n: int, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + tile_row: int = 0, + tile_col: int = 0, + ancestor_header: object | None = None, + hash_id: HashId = DEFAULT_HASH_ID, + r: int = NOISE_RANK, + device: object | None = None, + a_row_indices: Sequence[int] | None = None, + b_column_indices: Sequence[int] | None = None, +) -> pearl_mining.Fp16PlainProof: + """Assemble the FP16 plaintext certificate for one winning tile. + + ``proposed_header`` (sigma-hat) keys the A tree and the A branch of the seed + chain; ``ancestor_header`` (sigma-Delta, defaulting to the proposed header for + the depth-0 miner) keys the B tree and the B branch. ``a_full`` / ``b_full`` + are the FULL ``m x k`` / ``n x k`` committed FP16 operands (any form + :func:`miner_base.fp16_commitment.rows_to_bytes` accepts). + + ``tile_row`` / ``tile_col`` select the winning tile (``WinningTile.tile_row`` + / ``tile_col`` from ``pearl_gemm.fp16_miner.search_block``); the opened rows + are ``tile_row*h + P_A.tile_offsets()`` / ``tile_col*w + P_B.tile_offsets()``. + Pass ``a_row_indices`` / ``b_column_indices`` instead to open an explicit + GLOBAL row set (they must still be a legal ``base + tile_offsets()`` tile). + + Returns a ``pearl_mining.Fp16PlainProof`` ready for + ``pearl_mining.verify_fp16_plain_proof`` / submission. + """ + proposed = _header_bytes(proposed_header) + ancestor = proposed if ancestor_header is None else _header_bytes(ancestor_header) + + a_idx = ( + [int(i) for i in a_row_indices] + if a_row_indices is not None + else _tile_indices(rows_pattern, tile_row, m, "P_A") + ) + b_idx = ( + [int(i) for i in b_column_indices] + if b_column_indices is not None + else _tile_indices(cols_pattern, tile_col, n, "P_B") + ) + + comm_a = commit_fp16_operand(a_full, m, k, fp16_key_a(proposed), hash_id) + comm_b = commit_fp16_operand(b_full, n, k, fp16_key_b(ancestor), hash_id) + open_a = comm_a.open(a_idx) + open_b = comm_b.open(b_idx) + + return pearl_mining.Fp16PlainProof( + pearl_mining.IncompleteBlockHeader.from_bytes(ancestor), + device if device is not None else pearl_mining.Fp16Device.A100, + int(k), + int(r), + pearl_mining.Fp16OperandParams(int(m), _NATIVE_HASH_ID[hash_id], _native_pattern(rows_pattern)), + pearl_mining.Fp16OperandParams(int(n), _NATIVE_HASH_ID[hash_id], _native_pattern(cols_pattern)), + _native_matrix_proof(open_a), + _native_matrix_proof(open_b), + ) + + +@dataclass(frozen=True) +class Fp16OpenedBlock: + """One winning FP16 tile's full committed operands + opening parameters. + + The FP16 analogue of :class:`miner_base.block_submission.OpenedBlockInfo`: + the self-contained witness the async submission path hands to a worker + thread. Unlike FP8 -- which carries int8 code/scale planes and lazy per-side + commitments -- FP16 carries the FULL ``m x k`` / ``n x k`` raw FP16 operands + (the noise-seed chain binds their complete Merkle roots, so the certificate + tree must be the same one the search committed) and the winning tile's grid + coordinates. :func:`create_fp16_proof` re-commits and opens from these. + + ``a`` / ``b`` are any form :func:`miner_base.fp16_commitment.rows_to_bytes` + accepts; :meth:`owned_copy` snapshots them to the immutable ``u16`` byte + image so a queued submission cannot observe the operand changing underneath + it (the serving thread may reuse the activation buffer on its next forward). + """ + + a: object + b: object + k: int + m: int + n: int + rows_pattern: AxisPattern + cols_pattern: AxisPattern + tile_row: int = 0 + tile_col: int = 0 + hash_id: HashId = DEFAULT_HASH_ID + r: int = NOISE_RANK + ancestor_header: bytes | None = None + # Explicit GLOBAL row/col overrides; default to the contiguous tile the + # grid coordinates name. Mirrors create_fp16_proof's two addressing modes. + a_row_indices: tuple[int, ...] | None = None + b_column_indices: tuple[int, ...] | None = None + + def owned_copy(self) -> "Fp16OpenedBlock": + """Validate and snapshot the operands for an asynchronous handoff. + + Normalizes both operands to their committed ``u16`` LE byte image (bytes + are immutable and torch/numpy-free), so the queued proof builds from a + stable copy no later forward can mutate.""" + a_bytes = rows_to_bytes(self.a, self.m, self.k) + b_bytes = rows_to_bytes(self.b, self.n, self.k) + return replace( + self, + a=a_bytes, + b=b_bytes, + ancestor_header=None if self.ancestor_header is None else bytes(self.ancestor_header), + a_row_indices=None if self.a_row_indices is None else tuple(self.a_row_indices), + b_column_indices=( + None if self.b_column_indices is None else tuple(self.b_column_indices) + ), + ) + + def build_proof(self, proposed_header: bytes) -> pearl_mining.Fp16PlainProof: + """Assemble the ``Fp16PlainProof`` for this opening under ``proposed_header``.""" + return create_fp16_proof( + proposed_header, + self.a, + self.b, + k=self.k, + m=self.m, + n=self.n, + rows_pattern=self.rows_pattern, + cols_pattern=self.cols_pattern, + tile_row=self.tile_row, + tile_col=self.tile_col, + ancestor_header=self.ancestor_header, + hash_id=self.hash_id, + r=self.r, + a_row_indices=self.a_row_indices, + b_column_indices=self.b_column_indices, + ) + + +def submit_fp16_block( + opened_block: Fp16OpenedBlock, + mining_job: "MiningJob", + client: "PlainProofClient", +) -> pearl_mining.Fp16PlainProof | None: + """Verify and hand one certificate-v5 FP16 proof to the gateway. + + The FP16 analogue of :func:`miner_base.block_submission.submit_opened_block`: + assembles the ``Fp16PlainProof`` from the winning tile's full operands, runs + the standalone FP16 verifier against the proposed header, and submits the + admissible proof. ``None`` means the proof did not verify against the job's + difficulty and was filtered (the search latches on difficulty only; host + policy and the verifier are the independent admissibility checks) -- the + same filtered-winner contract the FP8 path returns ``None`` for. + """ + # Checked directly against the pearl_mining constant (not via + # block_submission.is_plain_fp16_job) so this whole FP16 submission module + # stays torch-free and importable under the proof interpreter alone. + if int(mining_job.cert_version) != pearl_mining.CERT_VERSION_PLAIN_FP16: + raise ValueError( + "FP16 proof submission requires certificate version " + f"{pearl_mining.CERT_VERSION_PLAIN_FP16}, got {int(mining_job.cert_version)}" + ) + + proposed = bytes(mining_job.incomplete_header_bytes) + header = pearl_mining.IncompleteBlockHeader.from_bytes(proposed) + plain_proof = opened_block.build_proof(proposed) + is_valid, message = pearl_mining.verify_fp16_plain_proof(header, plain_proof, None) + if not is_valid: + return None if _is_fp16_filtered(message) else _raise_fp16_verify_failure(message) + + client.submit_plain_proof(plain_proof, mining_job) + return plain_proof + + +# The verifier currently reports only ``(bool, str)``. A difficulty miss (the +# tile's ticket did not clear the job target) is a normally-filtered winner, not +# a protocol error; anything else is a genuine construction/commitment bug. Keep +# this match narrow until the binding exposes an error code. +_FP16_DIFFICULTY_MISS = "jackpot" + + +def _is_fp16_filtered(message: str) -> bool: + return _FP16_DIFFICULTY_MISS in message.lower() + + +def _raise_fp16_verify_failure(message: str): + raise RuntimeError(f"FP16 plain proof verification failed: {message}") diff --git a/miner/miner-base/src/miner_base/fp16_commitment.py b/miner/miner-base/src/miner_base/fp16_commitment.py new file mode 100644 index 000000000..95bffd959 --- /dev/null +++ b/miner/miner-base/src/miner_base/fp16_commitment.py @@ -0,0 +1,203 @@ +"""Keyed Merkle commitments and openings for the FP16 (A100) scheme. + +The FP16 analogue of :mod:`miner_base.commitment`, bit-exact to the Rust +``zk-pow/src/api/fp16/commitment.rs``. Unlike FP8 -- which commits a separate +int8-values tree and a BF16-scales tree per operand -- FP16 is strictly simpler: +**one keyed-BLAKE3 Merkle tree per operand, directly over the raw FP16 rows** +(``u16`` bit patterns, little-endian, row-major). The committed leaves ARE the +FP16 values; there is no prequant layer. + +The tree/key/hash-id discipline matches FP8 exactly (and the GPU +``pearl_gemm.fp16_commit`` kernel): leaves are fixed-size ``hash_id.chunk_len`` +chunks of the zero-padded row bytes, built under a per-side opening key + + keyA = H_"key-A"(proposed_header) (A-side tree, keys on sigma-hat) + keyB = H_"key-B"(ancestor_header) (B-side tree, keys on sigma-Delta) + +(``zk-pow/src/api/fp16/noise.rs::commitment_keys``). An opening discloses exactly +the selected tile rows as the unique-minimal leaf/sibling set -- the same +``MerkleTree.compute_leaf_indices_from_rows`` + ``get_multileaf_proof`` the FP8 +opener uses, so the Rust ``verify_and_open_rows`` rebuilds and accepts it. + +Torch-free and importable under any interpreter: the Merkle primitives come from +``pearl_blake3`` (the standalone extension) or, when only the unified extension is +installed, from ``pearl_mining`` (which re-exports the identical types). +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Sequence + +import blake3 + +try: # the standalone blake3 extension (preferred; importable under py3.10/3.13) + from pearl_blake3 import MerkleProof, MerkleTree +except ImportError: # the unified pearl_mining extension re-exports the same types + from pearl_mining import MerkleProof, MerkleTree + +from .params import HashId + +__all__ = [ + "LABEL_KEY_A", + "LABEL_KEY_B", + "DEFAULT_HASH_ID", + "Fp16MatrixCommitment", + "Fp16MatrixMerkleProof", + "commit_fp16_operand", + "key_a", + "key_b", + "commitment_keys", + "rows_to_bytes", +] + +# The protocol default Merkle leaf (the GPU ``fp16_commit`` kernel and the Rust +# both default to ``HashId::Blake3Chunk1024``). +DEFAULT_HASH_ID = HashId.BLAKE3_CHUNK_1024 + +# FP16 transcript labels (``zk-pow/src/api/fp16/noise.rs``): a distinct domain +# from the FP8 labels, so the two schemes never derive the same key from the same +# header. +LABEL_KEY_A = b"pearl/v4/FP16/key-A" +LABEL_KEY_B = b"pearl/v4/FP16/key-B" + + +def _subkey(label: bytes) -> bytes: + """``subkey(label) = BLAKE3(label)`` -- the 32-byte role key (unkeyed).""" + return blake3.blake3(label).digest(length=32) + + +def _hash_labelled(message: bytes, label: bytes) -> bytes: + """``H_label(message) = keyed_hash(key=subkey(label), message)`` + (``noise.rs::hash_labelled``).""" + return blake3.blake3(message, key=_subkey(label)).digest(length=32) + + +def key_a(proposed_header: bytes) -> bytes: + """``keyA = H_"key-A"(proposed_header)`` -- the A-side tree/opening key.""" + return _hash_labelled(bytes(proposed_header), LABEL_KEY_A) + + +def key_b(ancestor_header: bytes) -> bytes: + """``keyB = H_"key-B"(ancestor_header)`` -- the B-side tree/opening key.""" + return _hash_labelled(bytes(ancestor_header), LABEL_KEY_B) + + +def commitment_keys(proposed_header: bytes, ancestor_header: bytes) -> tuple[bytes, bytes]: + """``(keyA, keyB)`` -- the per-side opening keys + (``noise.rs::commitment_keys``). The miner proposes at depth 0, so a caller + with ``ancestor_header == proposed_header`` keys both trees off one header.""" + return key_a(proposed_header), key_b(ancestor_header) + + +def rows_to_bytes(rows: object, num_rows: int, k: int) -> bytes: + """The committed little-endian ``u16`` row-major byte image of an + ``num_rows x k`` FP16 operand (``commitment.rs::rows_to_bytes``), before + hash-id padding. + + ``rows`` may be raw ``bytes`` (already the ``u16`` LE image), a NumPy array + of ``uint16`` / ``int16`` / ``float16`` bit patterns, a torch ``float16`` / + ``int16`` tensor, or a flat sequence of ``u16`` integers. All are read as the + operand's FP16 *bit patterns* -- never re-encoded. + """ + want = num_rows * k * 2 + + if isinstance(rows, (bytes, bytearray, memoryview)): + raw = bytes(rows) + if len(raw) != want: + raise ValueError(f"operand is {len(raw)} bytes, expected {num_rows}*{k}*2 = {want}") + return raw + + # torch tensor -> contiguous CPU, viewed as the underlying u16 bytes. + if type(rows).__module__.split(".", 1)[0] == "torch": + import torch # local import: the opener stays torch-free when unused + + t = rows.detach().to("cpu").contiguous().reshape(num_rows, k) + if t.dtype == torch.float16: + t = t.view(torch.int16) + elif t.dtype not in (torch.int16, torch.uint16): + raise ValueError(f"expected float16 / int16 FP16 bit patterns, got {t.dtype}") + raw = t.view(torch.uint8).numpy().tobytes() + if len(raw) != want: + raise ValueError(f"operand tensor is {len(raw)} bytes, expected {want}") + return raw + + import numpy as np + + arr = np.ascontiguousarray(rows) + if arr.dtype == np.float16: + arr = arr.view(np.uint16) + elif arr.dtype == np.int16: + arr = arr.view(np.uint16) + elif arr.dtype != np.uint16: + # A flat int sequence (or a wider int array): take the low 16 bits. + arr = (arr.astype(np.int64) & 0xFFFF).astype(np.uint16) + raw = arr.astype(" bytes: + return bytes(self.proof.root) + + +@dataclass +class Fp16MatrixCommitment: + """A committed FP16 operand: its keyed Merkle tree (root = digest) plus the + shape/leaf metadata needed to open the unique-minimal row set.""" + + tree: "MerkleTree" + root: bytes + num_rows: int + k: int + hash_id: HashId + + @property + def row_nbytes(self) -> int: + """Committed bytes per row: ``k`` values, 2 bytes each.""" + return self.k * 2 + + def open(self, row_indices: Sequence[int]) -> Fp16MatrixMerkleProof: + """Open exactly ``row_indices`` as the unique-minimal leaf/sibling set, + bit-exact to ``commitment.rs::open_rows``.""" + indices = [int(i) for i in row_indices] + if not indices: + raise ValueError("must open at least one row") + if any(i < 0 or i >= self.num_rows for i in indices): + raise ValueError(f"opened row index out of range for {self.num_rows} rows") + leaf_idx = MerkleTree.compute_leaf_indices_from_rows( + indices, (self.num_rows, self.row_nbytes), self.hash_id.chunk_len + ) + proof = self.tree.get_multileaf_proof(leaf_idx) + return Fp16MatrixMerkleProof(proof, indices) + + +def commit_fp16_operand( + rows: object, + num_rows: int, + k: int, + key: bytes, + hash_id: HashId = DEFAULT_HASH_ID, +) -> Fp16MatrixCommitment: + """Build the keyed Merkle tree committing an ``num_rows x k`` FP16 operand + (row-major ``u16`` bit patterns) under ``key``, bit-exact to + ``commitment.rs::commit_operand`` and the GPU ``fp16_commit`` kernel: + ``MerkleTree(hash_id.pad(rows_to_bytes(rows)), key, hash_id.chunk_len)``. + """ + raw = rows_to_bytes(rows, num_rows, k) + tree = MerkleTree(data=hash_id.pad(raw), key=bytes(key), chunk_len=hash_id.chunk_len) + return Fp16MatrixCommitment(tree, bytes(tree.root), num_rows, k, hash_id) diff --git a/miner/miner-base/src/miner_base/gateway_client.py b/miner/miner-base/src/miner_base/gateway_client.py index 50b4e1ce5..e505aba83 100644 --- a/miner/miner-base/src/miner_base/gateway_client.py +++ b/miner/miner-base/src/miner_base/gateway_client.py @@ -7,7 +7,7 @@ from pearl_gateway.comm.dataclasses import MiningJob from pearl_gateway.comm.json_rpc_client import JSONRPCClient from pearl_gateway.config import MinerRpcConfig -from pearl_mining import IncompleteBlockHeader, PlainProof, PlainProofV4 +from pearl_mining import Fp16PlainProof, IncompleteBlockHeader, PlainProof, PlainProofV4 _LOGGER = get_logger(__name__) @@ -45,12 +45,15 @@ def get_mining_info(self) -> MiningJob: return MiningJob.from_dict(result) def submit_plain_proof( - self, plain_proof: PlainProof | PlainProofV4, mining_job: MiningJob + self, plain_proof: PlainProof | PlainProofV4 | Fp16PlainProof, mining_job: MiningJob ) -> None: """Submit a plain proof to the gateway. Args: - plain_proof: PlainProof (int7 certs) or PlainProofV4 (cert v4) with the proof data + plain_proof: PlainProof (int7 certs), PlainProofV4 (cert v4 FP8), or + Fp16PlainProof (cert v5 FP16/A100) with the proof data. Transport + is base64 and version-agnostic (the gateway dispatches on the + job's cert_version), so the same RPC carries every scheme. mining_job: MiningJob associated with this proof """ self.client.call( diff --git a/miner/miner-base/src/miner_base/params.py b/miner/miner-base/src/miner_base/params.py index fe3bbc1ab..f79da9efb 100644 --- a/miner/miner-base/src/miner_base/params.py +++ b/miner/miner-base/src/miner_base/params.py @@ -51,10 +51,16 @@ class Quant(enum.IntEnum): class Device(enum.IntEnum): - """Committed mining device and concrete arithmetic implementation.""" + """Committed mining device and concrete arithmetic implementation. + + ``HOPPER``/``BLACKWELL`` are the FP8/v4 FP8-MMA devices. ``A100`` (sm_80) is + the FP16/v5 scheme's device: its FP32-accumulated FP16 tensor core is a + distinct committed arithmetic, never mixed into an FP8 (v4) transcript. + """ HOPPER = 0 BLACKWELL = 1 + A100 = 2 @dataclass(frozen=True) diff --git a/miner/miner-base/src/miner_base/schemes.py b/miner/miner-base/src/miner_base/schemes.py new file mode 100644 index 000000000..1fb672b9d --- /dev/null +++ b/miner/miner-base/src/miner_base/schemes.py @@ -0,0 +1,74 @@ +"""Plaintext-PoUW scheme classification from a job's certificate version. + +The single, torch-free classifier shared by every dispatch point: arch/layer +admission, the per-forward launch branch (fused FP8 ``_launch_stages`` vs. the +standalone FP16 ``search_block``), and submission (``PlainProofV4`` vs. +``Fp16PlainProof``). Kept out of :mod:`miner_base.block_submission` (which pulls +in torch) so the classifier -- and the FP16 submission path that reuses it -- +imports under the proof interpreter alone. + +Only ``pearl_mining`` (the cert-version constants) is required; the ``job`` is +duck-typed on its ``cert_version`` attribute, so no gateway/torch import is +needed here. +""" + +from __future__ import annotations + +import enum +from typing import TYPE_CHECKING + +from pearl_mining import CERT_VERSION_PLAIN_FP8, CERT_VERSION_PLAIN_FP16 + +if TYPE_CHECKING: + from pearl_gateway.comm.dataclasses import MiningJob + +__all__ = [ + "Scheme", + "is_plain_fp8_job", + "is_plain_fp16_job", + "is_submittable_plain_job", + "scheme_of", +] + + +class Scheme(enum.Enum): + """The plaintext-PoUW scheme a job's certificate version selects. + + ``FP8`` is cert-v4 (Hopper/Blackwell FP8-MMA, the fused mixed-GEMM lottery); + ``FP16`` is cert-v5 (A100/sm_80, the standalone full-matrix FP16 search). + ``OTHER`` is any version this miner does not plaintext-mine (ZK v1/v2/v3), + which the runtime may execute and credit but never inspects, builds, or + submits a proof for. + """ + + FP8 = "fp8" + FP16 = "fp16" + OTHER = "other" + + +def scheme_of(job: "MiningJob") -> Scheme: + """The :class:`Scheme` a job advertises through its certificate version.""" + version = int(job.cert_version) + if version == CERT_VERSION_PLAIN_FP8: + return Scheme.FP8 + if version == CERT_VERSION_PLAIN_FP16: + return Scheme.FP16 + return Scheme.OTHER + + +def is_plain_fp8_job(job: "MiningJob") -> bool: + """Whether the issuing endpoint advertised certificate-v4 FP8 through ``job``.""" + return int(job.cert_version) == CERT_VERSION_PLAIN_FP8 + + +def is_plain_fp16_job(job: "MiningJob") -> bool: + """Whether the issuing endpoint advertised certificate-v5 FP16 (A100).""" + return int(job.cert_version) == CERT_VERSION_PLAIN_FP16 + + +def is_submittable_plain_job(job: "MiningJob") -> bool: + """Whether this job runs a plaintext scheme this miner can submit a proof for + (FP8/v4 or FP16/v5). The shared submission-admission gate keys on this so the + AsyncLoopManager plumbing is scheme-agnostic while proof construction branches + per scheme.""" + return scheme_of(job) in (Scheme.FP8, Scheme.FP16) diff --git a/miner/miner-base/tests/test_fp16_admission.py b/miner/miner-base/tests/test_fp16_admission.py new file mode 100644 index 000000000..bf772bfe6 --- /dev/null +++ b/miner/miner-base/tests/test_fp16_admission.py @@ -0,0 +1,81 @@ +"""FP16 (A100 / sm_80) committed-device admission. + +``miner_base.devices`` resolves a CUDA compute capability to the committed +mining ``Device``. The FP16 scheme admits sm_80 as ``Device.A100`` -- but only +behind the explicit ``allow_fp16`` opt-in, so the FP8 (v4) datapath (which never +passes it) still rejects sm_80 exactly as before. + +``devices`` imports ``torch`` at module top for ``local_device`` / +``is_fp16_capable``; only a minimal stub is needed to exercise the pure +capability->Device mapping, so a fake ``torch`` is injected for this module. +""" + +from __future__ import annotations + +import sys +import types + +import pytest + + +@pytest.fixture() +def devices_module(monkeypatch): + """Import ``miner_base.devices`` against a stub ``torch`` (capability only).""" + fake_torch = types.ModuleType("torch") + fake_torch.device = object # only used in type hints + fake_cuda = types.ModuleType("torch.cuda") + fake_cuda._cap = (8, 0) + + def get_device_capability(device=None): + return fake_cuda._cap + + fake_cuda.get_device_capability = get_device_capability + fake_torch.cuda = fake_cuda + monkeypatch.setitem(sys.modules, "torch", fake_torch) + monkeypatch.setitem(sys.modules, "torch.cuda", fake_cuda) + monkeypatch.delitem(sys.modules, "miner_base.devices", raising=False) + import miner_base.devices as devices + + yield devices + sys.modules.pop("miner_base.devices", None) + + +def test_sm80_admitted_as_a100_only_for_fp16(devices_module): + from miner_base.params import Device + + # FP8 datapath (no opt-in): sm_80 has no committed device -> rejected. + with pytest.raises(ValueError): + devices_module.device_for_capability(8, 0) + # FP16 opt-in: sm_80 -> A100. + assert devices_module.device_for_capability(8, 0, allow_fp16=True) is Device.A100 + + +def test_fp8_families_unchanged_under_fp16_opt_in(devices_module): + from miner_base.params import Device + + for major, expected in ((9, Device.HOPPER), (10, Device.BLACKWELL), (12, Device.BLACKWELL)): + # The FP16 opt-in must not alter the FP8 families' mapping. + assert devices_module.device_for_capability(major, 0) is expected + assert devices_module.device_for_capability(major, 0, allow_fp16=True) is expected + + +def test_unknown_capability_rejected_both_ways(devices_module): + for allow in (False, True): + with pytest.raises(ValueError): + devices_module.device_for_capability(7, 5, allow_fp16=allow) + + +def test_is_fp16_capable_detects_sm80(devices_module): + import torch # the stub + + torch.cuda._cap = (8, 0) + assert devices_module.is_fp16_capable() is True + torch.cuda._cap = (9, 0) + assert devices_module.is_fp16_capable() is False + + +def test_device_enum_has_a100(): + from miner_base.params import Device + + assert int(Device.A100) == 2 + assert Device.HOPPER != Device.A100 and Device.BLACKWELL != Device.A100 diff --git a/miner/miner-base/tests/test_fp16_block_submission.py b/miner/miner-base/tests/test_fp16_block_submission.py new file mode 100644 index 000000000..562496f8a --- /dev/null +++ b/miner/miner-base/tests/test_fp16_block_submission.py @@ -0,0 +1,183 @@ +"""FP16 (A100) plaintext-certificate opener + assembler tests. + +Mirrors the Rust oracle ``zk-pow/src/api/fp16/{commitment,verify}.rs``: + +* the opener (:mod:`miner_base.fp16_commitment`) builds the per-operand keyed + Merkle tree over raw FP16 ``u16`` rows and opens the tile's global rows; +* the assembler (:func:`miner_base.fp16_block_submission.create_fp16_proof`) + wraps a winning tile into a ``pearl_mining.Fp16PlainProof``. + +The honest operands are reproduced bit-for-bit from the Rust ``cert`` fixture's +``Gen`` xorshift (``honest_fixture`` in ``verify.rs``), so the assembled proof is +byte-identical to the committed ``node/zkpow/testdata/fp16_plain_proof_a100.bin`` +and verifies. + +Skipped unless the ``pearl_mining`` extension is importable (needs py3.12/3.13 +here; the default miner interpreter cannot both run GPU kernels and import it). +""" + +from __future__ import annotations + +import struct +from pathlib import Path + +import numpy as np +import pytest + +pearl_mining = pytest.importorskip("pearl_mining") + +from miner_base.fp16_commitment import ( # noqa: E402 + DEFAULT_HASH_ID, + commit_fp16_operand, + commitment_keys, + key_a, + key_b, +) +from miner_base.fp16_block_submission import create_fp16_proof # noqa: E402 +from miner_base.layout import AxisPattern, DimType # noqa: E402 + +# Honest-fixture shape (verify.rs::cert): m=8 > h=4 and n=128 > w=64, so unopened +# rows carry real siblings. k=256, rank 32. +_M, _N, _K, _R = 8, 128, 256, 32 +_NBITS = 0x207FFFFF # EASY_NBITS +_GEN_SEED = 0xDEADBEEF0BADF00D + +# P_A = [(4, Blake)] -> h=4 ; P_B = [(4, Blake), (16, Fold)] -> w=64. +_P_A = AxisPattern(((4, DimType.BLAKE),)) +_P_B = AxisPattern(((4, DimType.BLAKE), (16, DimType.FOLD))) + +_FIXTURE = Path(__file__).resolve().parents[3] / "node" / "zkpow" / "testdata" / "fp16_plain_proof_a100.bin" +_U64 = (1 << 64) - 1 + + +class _Gen: + """Byte-identical to the Rust ``Gen`` xorshift64 operand generator.""" + + def __init__(self, seed: int) -> None: + self.s = seed & _U64 + + def _next(self) -> int: + self.s ^= (self.s << 13) & _U64 + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & _U64 + return self.s + + def operand(self, n: int) -> np.ndarray: + out = np.empty(n, dtype=np.float16) + for i in range(n): + r = self._next() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = ((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(np.float32(sign * mant * (2.0 ** exp))) + return out.view(np.uint16) + + +def _test_header() -> bytes: + """The ``honest_fixture`` wire bytes: version 0, timestamp 0x66666666, nbits, + with ASYMMETRIC prev_block/merkle_root (not palindromic under byte reversal, so + the fixture exercises header byte-orientation across the FFI seam). The Rust + generator sets the hash arrays to [0..31] / [0x40..0x5f]; IncompleteBlockHeader + serializes them in reversed (wire) byte order, so the on-disk bytes are + prev_block = [0x1f..0x00], merkle_root = [0x5f..0x40].""" + return ( + struct.pack(" tuple[np.ndarray, np.ndarray]: + g = _Gen(_GEN_SEED) + a = g.operand(_M * _K) + b = g.operand(_N * _K) + return a, b + + +def test_patterns_are_contiguous() -> None: + # The #7 resolution: the committed A100 patterns have contiguous tile + # offsets, so a tile opens a dense contiguous run of global rows. + assert _P_A.tile_offsets == list(range(4)) + assert _P_A.total == _P_A.tile_size == 4 + assert _P_B.tile_offsets == list(range(64)) + assert _P_B.total == _P_B.tile_size == 64 + + +def test_opener_root_is_deterministic_and_opening_authenticates() -> None: + a, _b = _honest_operands() + header = _test_header() + comm = commit_fp16_operand(a, _M, _K, key_a(header), DEFAULT_HASH_ID) + # Re-committing identical rows reproduces the root (keyed, deterministic). + comm2 = commit_fp16_operand(a, _M, _K, key_a(header), DEFAULT_HASH_ID) + assert comm.root == comm2.root + # Open the origin tile and check the native Merkle proof authenticates. + opening = comm.open(_P_A.tile_offsets) + assert opening.row_indices == [0, 1, 2, 3] + native = pearl_mining.MerkleProof( + [bytes(x) for x in opening.proof.leaf_data], + list(opening.proof.leaf_indices), + bytes(opening.proof.root), + [bytes(s) for s in opening.proof.siblings], + opening.proof.total_leaves, + ) + assert native.verify(bytes(key_a(header))) + + +def test_keys_match_commitment_keys_helper() -> None: + header = _test_header() + ka, kb = commitment_keys(header, header) + assert ka == key_a(header) + assert kb == key_b(header) + + +def test_create_fp16_proof_origin_verifies() -> None: + a, b = _honest_operands() + header = _test_header() + proof = create_fp16_proof( + header, a, b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + tile_row=0, tile_col=0, + ) + assert list(proof.values_a.row_indices) == [0, 1, 2, 3] + assert list(proof.values_b.row_indices) == list(range(64)) + assert proof.a.num_rows == _M and proof.b.num_rows == _N + assert proof.k == _K and proof.r == _R + # Wire round-trip. + assert pearl_mining.Fp16PlainProof.from_bytes(proof.to_bytes()).to_bytes() == proof.to_bytes() + # Full plaintext verification accepts. + ok, msg = pearl_mining.verify_fp16_plain_proof( + pearl_mining.IncompleteBlockHeader.from_bytes(header), proof, None + ) + assert ok, msg + + +@pytest.mark.skipif(not _FIXTURE.exists(), reason="committed FP16 Go fixture not present") +def test_create_fp16_proof_byte_matches_committed_fixture() -> None: + a, b = _honest_operands() + header = _test_header() + blob = _FIXTURE.read_bytes() + assert blob[:76] == header + plen = struct.unpack_from(" None: + # A winner off the origin opens the contiguous global rows base+tile_offsets + # (tr*h / tc*w). Requires the base-aware parse_proof (current zk-pow). + a, b = _honest_operands() + header = _test_header() + proof = create_fp16_proof( + header, a, b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + tile_row=1, tile_col=1, + ) + assert list(proof.values_a.row_indices) == [4, 5, 6, 7] + assert list(proof.values_b.row_indices) == list(range(64, 128)) + ok, msg = pearl_mining.verify_fp16_plain_proof( + pearl_mining.IncompleteBlockHeader.from_bytes(header), proof, None + ) + assert ok, msg diff --git a/miner/miner-base/tests/test_fp16_manager_dispatch.py b/miner/miner-base/tests/test_fp16_manager_dispatch.py new file mode 100644 index 000000000..7da786829 --- /dev/null +++ b/miner/miner-base/tests/test_fp16_manager_dispatch.py @@ -0,0 +1,91 @@ +"""AsyncLoopManager submission dispatch across the FP8 (v4) and FP16 (v5) schemes. + +The shared submission plumbing (capacity, backpressure, one-shot clients) is +scheme-agnostic; ``_build_and_submit_proof`` is the one point that knows FP8 vs. +FP16, routing an ``OpenedBlockInfo`` to ``submit_opened_block`` and an +``Fp16OpenedBlock`` to ``submit_fp16_block`` by the job's cert version, and +refusing a mismatched opening/scheme. + +Needs ``torch`` (``async_loop_manager`` -> ``block_submission`` import it), so it +is skipped in the proof-only interpreter and runs in the unified production env. +""" + +from __future__ import annotations + +import pytest + +pytest.importorskip("torch") +pytest.importorskip("pearl_mining") + +from miner_base import async_loop_manager as alm # noqa: E402 +from miner_base.block_submission import Scheme # noqa: E402 + + +class _Job: + def __init__(self, cert_version: int) -> None: + self.cert_version = cert_version + self.incomplete_header_bytes = b"\x00" * 76 + + +class _FakeFp8Opening: + """Stand-in whose only requirement is being an ``OpenedBlockInfo`` instance; + we monkeypatch the actual submit function, so no real planes are needed.""" + + +class _FakeFp16Opening: + pass + + +@pytest.fixture() +def manager(): + from miner_base.gateway_client import MinerRpcConfig + from miner_base.settings import MinerSettings + + # Construct only (no start()): _build_and_submit_proof is a pure dispatch. + conf = MinerSettings(no_gateway=True) + return alm.AsyncLoopManager(MinerRpcConfig(), conf) + + +def test_v4_routes_to_fp8_submit(manager, monkeypatch): + calls = {} + monkeypatch.setattr(alm, "OpenedBlockInfo", _FakeFp8Opening) + monkeypatch.setattr(alm, "submit_opened_block", lambda o, j, c: calls.setdefault("fp8", (o, j))) + monkeypatch.setattr( + alm, "submit_fp16_block", lambda o, j, c: calls.setdefault("fp16", (o, j)) + ) + opening = _FakeFp8Opening() + manager._build_and_submit_proof(opening, _Job(4), client=object()) + assert "fp8" in calls and "fp16" not in calls + + +def test_v5_routes_to_fp16_submit(manager, monkeypatch): + calls = {} + monkeypatch.setattr(alm, "Fp16OpenedBlock", _FakeFp16Opening) + monkeypatch.setattr(alm, "submit_opened_block", lambda o, j, c: calls.setdefault("fp8", (o, j))) + monkeypatch.setattr( + alm, "submit_fp16_block", lambda o, j, c: calls.setdefault("fp16", (o, j)) + ) + opening = _FakeFp16Opening() + manager._build_and_submit_proof(opening, _Job(5), client=object()) + assert "fp16" in calls and "fp8" not in calls + + +def test_mismatched_opening_for_scheme_raises(manager, monkeypatch): + monkeypatch.setattr(alm, "Fp16OpenedBlock", _FakeFp16Opening) + # A V5 job with a non-Fp16 opening is a programming error, not a silent drop. + with pytest.raises(TypeError): + manager._build_and_submit_proof(object(), _Job(5), client=object()) + + +def test_non_submittable_scheme_raises(manager): + with pytest.raises(ValueError): + manager._build_and_submit_proof(object(), _Job(3), client=object()) + + +def test_submittable_gate_accepts_both_schemes(): + from miner_base.block_submission import is_submittable_plain_job + + assert is_submittable_plain_job(_Job(4)) + assert is_submittable_plain_job(_Job(5)) + assert not is_submittable_plain_job(_Job(2)) + assert Scheme.FP16.value == "fp16" diff --git a/miner/miner-base/tests/test_fp16_submission_glue.py b/miner/miner-base/tests/test_fp16_submission_glue.py new file mode 100644 index 000000000..e99b26c02 --- /dev/null +++ b/miner/miner-base/tests/test_fp16_submission_glue.py @@ -0,0 +1,201 @@ +"""Winner -> ``Fp16PlainProof`` -> gateway submission glue for the FP16 (v5) scheme. + +The non-GPU half of the A100 runtime integration: given a winning tile's full +committed operands (as :class:`miner_base.fp16_block_submission.Fp16OpenedBlock`), +:func:`~miner_base.fp16_block_submission.submit_fp16_block` must assemble the +cert, verify it against the proposed header, and hand it to the client. The GPU +search (``pearl_gemm.fp16_miner.search_block``) that *produces* the tile cannot +run here (no A100 / torch+pearl_mining together), so the winning operands are the +Rust ``cert`` honest fixture -- the same bit-exact source the opener/assembler +test uses -- and the client is a recorder. + +Also covers the torch-free scheme classifier (:mod:`miner_base.schemes`), which +drives arch/layer admission, the per-forward launch branch, and this submission +dispatch alike. Skipped unless ``pearl_mining`` is importable (py3.12/3.13 here). +""" + +from __future__ import annotations + +import struct + +import numpy as np +import pytest + +pearl_mining = pytest.importorskip("pearl_mining") + +from miner_base.fp16_block_submission import ( # noqa: E402 + Fp16OpenedBlock, + submit_fp16_block, +) +from miner_base.layout import AxisPattern, DimType # noqa: E402 +from miner_base.schemes import ( # noqa: E402 + Scheme, + is_plain_fp16_job, + is_plain_fp8_job, + is_submittable_plain_job, + scheme_of, +) + +_M, _N, _K, _R = 8, 128, 256, 32 +_NBITS = 0x207FFFFF # EASY_NBITS +_GEN_SEED = 0xDEADBEEF0BADF00D +_U64 = (1 << 64) - 1 + +# P_A = [(4, Blake)] -> h=4 ; P_B = [(4, Blake), (16, Fold)] -> w=64 (the +# committed A100 patterns; contiguous tile offsets). +_P_A = AxisPattern(((4, DimType.BLAKE),)) +_P_B = AxisPattern(((4, DimType.BLAKE), (16, DimType.FOLD))) + + +class _Gen: + """Byte-identical to the Rust ``Gen`` xorshift64 operand generator.""" + + def __init__(self, seed: int) -> None: + self.s = seed & _U64 + + def _next(self) -> int: + self.s ^= (self.s << 13) & _U64 + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & _U64 + return self.s + + def operand(self, n: int) -> np.ndarray: + out = np.empty(n, dtype=np.float16) + for i in range(n): + r = self._next() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = ((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(np.float32(sign * mant * (2.0**exp))) + return out.view(np.uint16) + + +def _honest_operands() -> tuple[np.ndarray, np.ndarray]: + g = _Gen(_GEN_SEED) + return g.operand(_M * _K), g.operand(_N * _K) + + +def _test_header() -> bytes: + return ( + struct.pack(" None: + self.cert_version = cert_version + self.incomplete_header_bytes = header + + +class _RecordingClient: + def __init__(self) -> None: + self.calls: list[tuple[object, object]] = [] + + def submit_plain_proof(self, plain_proof, mining_job) -> None: + self.calls.append((plain_proof, mining_job)) + + +# ---- scheme classifier ----------------------------------------------------- + + +def test_scheme_classifier_maps_cert_versions() -> None: + hdr = _test_header() + assert scheme_of(_Job(4, hdr)) is Scheme.FP8 + assert scheme_of(_Job(5, hdr)) is Scheme.FP16 + assert scheme_of(_Job(3, hdr)) is Scheme.OTHER + assert is_plain_fp8_job(_Job(4, hdr)) and not is_plain_fp8_job(_Job(5, hdr)) + assert is_plain_fp16_job(_Job(5, hdr)) and not is_plain_fp16_job(_Job(4, hdr)) + # Both plaintext schemes are submittable; a ZK version is not. + assert is_submittable_plain_job(_Job(4, hdr)) + assert is_submittable_plain_job(_Job(5, hdr)) + assert not is_submittable_plain_job(_Job(3, hdr)) + + +def test_classifier_matches_binding_constant() -> None: + assert scheme_of(_Job(pearl_mining.CERT_VERSION_PLAIN_FP16, _test_header())) is Scheme.FP16 + assert scheme_of(_Job(pearl_mining.CERT_VERSION_PLAIN_FP8, _test_header())) is Scheme.FP8 + + +# ---- winner -> submit glue -------------------------------------------------- + + +def test_submit_fp16_block_builds_verifies_and_submits() -> None: + a, b = _honest_operands() + header = _test_header() + opened = Fp16OpenedBlock( + a=a, b=b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + tile_row=0, tile_col=0, + ) + client = _RecordingClient() + proof = submit_fp16_block(opened, _Job(5, header), client) + + assert proof is not None + assert isinstance(proof, pearl_mining.Fp16PlainProof) + # The winner was handed to the client exactly once, with the same proof/job. + assert len(client.calls) == 1 + submitted_proof, submitted_job = client.calls[0] + assert submitted_proof is proof + assert submitted_job.cert_version == 5 + # The submitted proof opens the origin tile and verifies against the header. + assert list(proof.values_a.row_indices) == [0, 1, 2, 3] + assert list(proof.values_b.row_indices) == list(range(64)) + ok, msg = pearl_mining.verify_fp16_plain_proof( + pearl_mining.IncompleteBlockHeader.from_bytes(header), proof, None + ) + assert ok, msg + + +def test_submit_fp16_block_non_origin_tile() -> None: + a, b = _honest_operands() + header = _test_header() + opened = Fp16OpenedBlock( + a=a, b=b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + tile_row=1, tile_col=1, + ) + client = _RecordingClient() + proof = submit_fp16_block(opened, _Job(5, header), client) + assert proof is not None + assert list(proof.values_a.row_indices) == [4, 5, 6, 7] + assert list(proof.values_b.row_indices) == list(range(64, 128)) + assert len(client.calls) == 1 + + +def test_submit_fp16_block_rejects_non_v5_job() -> None: + a, b = _honest_operands() + opened = Fp16OpenedBlock( + a=a, b=b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + ) + client = _RecordingClient() + with pytest.raises(ValueError, match="certificate version"): + submit_fp16_block(opened, _Job(4, _test_header()), client) + assert client.calls == [] + + +def test_owned_copy_snapshots_operands_against_buffer_reuse() -> None: + # The serving thread may overwrite the activation buffer on its next + # forward; owned_copy must snapshot the committed bytes before handoff. + a, b = _honest_operands() + a = a.copy() + opened = Fp16OpenedBlock( + a=a, b=b, k=_K, m=_M, n=_N, rows_pattern=_P_A, cols_pattern=_P_B, + ) + owned = opened.owned_copy() + frozen = bytes(owned.a) + a[:] = 0 # simulate in-place buffer reuse after the handoff + assert bytes(owned.a) == frozen # unchanged + # And the snapshot still builds a verifying proof. + header = _test_header() + client = _RecordingClient() + proof = submit_fp16_block(owned, _Job(5, header), client) + ok, _ = pearl_mining.verify_fp16_plain_proof( + pearl_mining.IncompleteBlockHeader.from_bytes(header), proof, None + ) + assert ok diff --git a/miner/pearl-gateway/src/pearl_gateway/blockchain_utils/zk_certificate.py b/miner/pearl-gateway/src/pearl_gateway/blockchain_utils/zk_certificate.py index 54ff7f337..70053efc0 100644 --- a/miner/pearl-gateway/src/pearl_gateway/blockchain_utils/zk_certificate.py +++ b/miner/pearl-gateway/src/pearl_gateway/blockchain_utils/zk_certificate.py @@ -31,6 +31,7 @@ class CertificateVersion(IntEnum): ZK_MOE = 2 # V2: MoE and dense proofs. ZK_V3 = 3 # V3: V2 layout with the salted noise-seed derivation. PLAIN_FP8 = 4 # V4: FP8 proofs (``pearl_mining.PlainProofV4``). + PLAIN_FP16 = 5 # V5: FP16 (A100) proofs (``pearl_mining.Fp16PlainProof``). @property def uses_salted_seeds(self) -> bool: @@ -55,18 +56,46 @@ def uses_salted_seeds(self) -> bool: ] ) +# V5 (FP16): no public-data blob at all. Preamble is version + header hash, then +# the length-prefixed proof and the ancestor count/headers follow. +_V5_PREAMBLE_DTYPE = np.dtype( + [ + ("version", " int: + """The proof-data byte cap for ``cert_version`` (version-aware; V5 is larger).""" + if cert_version == CertificateVersion.PLAIN_FP16: + return _FP16_ZK_MAX_PROOF_DATA_SIZE + return _ZK_MAX_PROOF_DATA_SIZE + _VARIABLE_LENGTH_VERSIONS = { CertificateVersion.ZK_MOE, CertificateVersion.ZK_V3, CertificateVersion.PLAIN_FP8, } +# Versions that carry ancestor headers (parent, then grandparent) after the proof. +_ANCESTOR_VERSIONS = { + CertificateVersion.PLAIN_FP8, + CertificateVersion.PLAIN_FP16, +} + @dataclass(frozen=True) class CertificateProof: @@ -100,24 +129,30 @@ def __post_init__(self) -> None: self._validate() def _validate(self) -> None: - if len(self.proof.proof_data) > _ZK_MAX_PROOF_DATA_SIZE: + max_proof_data = _max_proof_data_size(self.cert_version) + if len(self.proof.proof_data) > max_proof_data: raise ValueError( f"Proof data is too large: {len(self.proof.proof_data)} bytes " - f"(max {_ZK_MAX_PROOF_DATA_SIZE} bytes)" + f"(max {max_proof_data} bytes)" ) - if self.cert_version != CertificateVersion.PLAIN_FP8: + if self.cert_version not in _ANCESTOR_VERSIONS: if self.ancestor_headers: - raise ValueError("Ancestor headers require a V4 certificate") + raise ValueError("Ancestor headers require a V4/V5 certificate") return if len(self.header_hash) != 32: - raise ValueError("V4 header hash must be 32 bytes") - if len(self.proof.public_data) > _ZK_MAX_PROOF_DATA_SIZE: - raise ValueError("V4 public data exceeds max size") + raise ValueError("header hash must be 32 bytes") + if self.cert_version == CertificateVersion.PLAIN_FP8: + if len(self.proof.public_data) > _ZK_MAX_PROOF_DATA_SIZE: + raise ValueError("V4 public data exceeds max size") + elif self.cert_version == CertificateVersion.PLAIN_FP16: + # V5 carries no public-data blob: the whole statement rides in proof_data. + if self.proof.public_data: + raise ValueError("V5 (FP16) certificate carries no public data") if len(self.ancestor_headers) > self.MAX_ANCESTOR_HEADERS: - raise ValueError("V4 certificate permits at most two ancestor headers") + raise ValueError("certificate permits at most two ancestor headers") for header in self.ancestor_headers: if len(header.serialize()) != PearlHeader.get_serialized_header_size(): - raise ValueError("V4 ancestor header must include a full proof commitment") + raise ValueError("ancestor header must include a full proof commitment") def serialize(self) -> bytes: """Serialize to the wire format expected by the Go node. @@ -127,11 +162,23 @@ def serialize(self) -> bytes: PublicData(N) | ProofDataLen(4) | ProofData PLAIN_FP8 (v4): the same prefix, then AncestorCount(1) | AncestorHeaders(108 each). The count is mandatory, including zero; parent precedes grandparent. + PLAIN_FP16 (v5): Version(4) | HeaderHash(32) | ProofDataLen(4) | ProofData | + AncestorCount(1) | AncestorHeaders(108 each). No public-data blob. """ self._validate() public_data = bytes(self.proof.public_data) proof = bytes(self.proof.proof_data) + if self.cert_version == CertificateVersion.PLAIN_FP16: + preamble = np.array( + [(int(self.cert_version), self.header_hash)], + dtype=_V5_PREAMBLE_DTYPE, + ) + encoded = preamble.tobytes() + struct.pack(" int: self._validate() pd_len = len(self.proof.public_data) proof_len = len(self.proof.proof_data) + if self.cert_version == CertificateVersion.PLAIN_FP16: + return ( + _V5_PREAMBLE_DTYPE.itemsize + + _PROOF_DATA_LEN_SIZE + + proof_len + + 1 + + len(self.ancestor_headers) * PearlHeader.get_serialized_header_size() + ) if self.cert_version == CertificateVersion.ZK_DENSE: return _DENSE_DTYPE.itemsize + proof_len if self.cert_version in _VARIABLE_LENGTH_VERSIONS: @@ -174,6 +229,40 @@ def deserialize(cls, data: bytes) -> "ZKCertificate": cert_version = CertificateVersion(raw_version) ancestor_headers = [] + if cert_version == CertificateVersion.PLAIN_FP16: + arr = np.frombuffer(data, dtype=_V5_PREAMBLE_DTYPE, count=1)[0] + header_hash = bytes(arr["header_hash"]) + public_data = b"" + proof_start = _V5_PREAMBLE_DTYPE.itemsize + (proof_data_len,) = struct.unpack_from(" _max_proof_data_size(cert_version): + raise ValueError("V5 proof data exceeds max size") + proof_body_start = proof_start + _PROOF_DATA_LEN_SIZE + proof_end = proof_body_start + proof_data_len + if len(data) <= proof_end: + raise ValueError("Truncated V5 proof data or missing ancestor count") + count = data[proof_end] + if count > cls.MAX_ANCESTOR_HEADERS: + raise ValueError("V5 ancestor count must be between zero and two") + header_size = PearlHeader.get_serialized_header_size() + ancestors_start = proof_end + 1 + if len(data) != ancestors_start + count * header_size: + raise ValueError("Truncated V5 ancestor headers or trailing data") + ancestor_headers = [ + PearlHeader.deserialize(data[offset : offset + header_size]) + for offset in range(ancestors_start, len(data), header_size) + ] + proof_data = data[proof_body_start:proof_end] + return cls( + header_hash=header_hash, + proof=CertificateProof(public_data, proof_data), + cert_version=cert_version, + ancestor_headers=ancestor_headers, + ) + if cert_version == CertificateVersion.ZK_DENSE: arr = np.frombuffer(data, dtype=_DENSE_DTYPE, count=1)[0] header_hash = bytes(arr["header_hash"]) @@ -228,7 +317,9 @@ def from_pearl_header( *, ancestor_headers: list[PearlHeader] | None = None, ) -> "ZKCertificate": - commitment = cls._get_proof_commitment(proof.public_data, cert_version=cert_version) + commitment = cls._get_proof_commitment( + cls._committed_blob(proof, cert_version), cert_version=cert_version + ) if header.proof_commitment is None: header.proof_commitment = commitment elif header.proof_commitment != commitment: @@ -240,14 +331,31 @@ def from_pearl_header( ancestor_headers=[] if ancestor_headers is None else ancestor_headers, ) + @staticmethod + def _committed_blob( + proof: CertificateProof, cert_version: CertificateVersion + ) -> bytes: + """The blob the proof commitment binds over. + + V5 (FP16) has no public-data blob, so it commits over ``proof_data`` + (matching Go ``CertificateV5.ProofCommitment``); every other version + commits over ``public_data`` (``CertificateV*.ProofCommitment``). + """ + if cert_version == CertificateVersion.PLAIN_FP16: + return bytes(proof.proof_data) + return bytes(proof.public_data) + @staticmethod def _get_proof_commitment( - public_data: bytes | bytearray, + committed_blob: bytes | bytearray, cert_version: CertificateVersion = CertificateVersion.ZK_DENSE, ) -> bytes: return double_sha256( - int(cert_version).to_bytes(_CERT_VERSION_SIZE, "little") + bytes(public_data) + int(cert_version).to_bytes(_CERT_VERSION_SIZE, "little") + bytes(committed_blob) ) def get_proof_commitment(self) -> bytes: - return self._get_proof_commitment(self.proof.public_data, cert_version=self.cert_version) + return self._get_proof_commitment( + self._committed_blob(self.proof, self.cert_version), + cert_version=self.cert_version, + ) diff --git a/miner/pearl-gateway/src/pearl_gateway/miner_rpc/server.py b/miner/pearl-gateway/src/pearl_gateway/miner_rpc/server.py index c769b64b2..d6b884cf8 100644 --- a/miner/pearl-gateway/src/pearl_gateway/miner_rpc/server.py +++ b/miner/pearl-gateway/src/pearl_gateway/miner_rpc/server.py @@ -7,7 +7,13 @@ import fastjsonschema from miner_utils import get_logger -from pearl_mining import CERT_VERSION_PLAIN_FP8, PlainProof, PlainProofV4 +from pearl_mining import ( + CERT_VERSION_PLAIN_FP8, + CERT_VERSION_PLAIN_FP16, + Fp16PlainProof, + PlainProof, + PlainProofV4, +) from pearl_gateway.comm.dataclasses import MiningJob, MiningPausedError from pearl_gateway.config import MinerRpcConfig @@ -215,13 +221,16 @@ async def _process_request(self, request_line: str, client: ClientInfo) -> dict[ if error := self._validate_params(validate_submit_plain_proof, params, request_id): return error mining_job = MiningJob.from_dict(params["mining_job"]) - # Certificate v4 (plain FP8) proofs ride their own wire type; the - # Int7 ZK certificate versions keep the legacy ``PlainProof``. - proof_type = ( - PlainProofV4 - if int(mining_job.cert_version) == CERT_VERSION_PLAIN_FP8 - else PlainProof - ) + # Certificate v5 (plain FP16/A100) and v4 (plain FP8) proofs each + # ride their own wire type; the Int7 ZK certificate versions keep + # the legacy ``PlainProof``. + cert_version = int(mining_job.cert_version) + if cert_version == CERT_VERSION_PLAIN_FP16: + proof_type: type = Fp16PlainProof + elif cert_version == CERT_VERSION_PLAIN_FP8: + proof_type = PlainProofV4 + else: + proof_type = PlainProof plain_proof = proof_type.from_base64(params["plain_proof"]) asyncio.create_task(self.handle_submit_plain_proof(plain_proof, mining_job)) return self._jsonrpc_success("submitted", request_id) @@ -242,7 +251,7 @@ async def _process_request(self, request_line: str, client: ClientInfo) -> dict[ return self._jsonrpc_error(-32000, str(e), request_id) async def handle_submit_plain_proof( - self, plain_proof: PlainProof | PlainProofV4, mining_job: MiningJob + self, plain_proof: PlainProof | PlainProofV4 | Fp16PlainProof, mining_job: MiningJob ) -> None: """Handle submitPlainProof requests.""" # Get the current template (needed to build the full block) diff --git a/miner/pearl-gateway/src/pearl_gateway/proof_worker.py b/miner/pearl-gateway/src/pearl_gateway/proof_worker.py index 28916d3b3..7f724da5e 100644 --- a/miner/pearl-gateway/src/pearl_gateway/proof_worker.py +++ b/miner/pearl-gateway/src/pearl_gateway/proof_worker.py @@ -10,8 +10,11 @@ from miner_utils import get_logger from pearl_mining import ( CERT_VERSION_PLAIN_FP8, + CERT_VERSION_PLAIN_FP16, Fp8Prover, Fp8Verifier, + Fp16PlainProof, + Fp16Prover, IncompleteBlockHeader, PlainProof, PlainProofV4, @@ -25,6 +28,7 @@ _MMA_BF16_TO_FP8_FP32 = 1 _fp8_prover: Fp8Prover | None = None +_fp16_prover: Fp16Prover | None = None def worker_init() -> None: @@ -83,6 +87,32 @@ def _prove_fp8( return public_bytes, proof_bytes +def _prove_fp16( + header: IncompleteBlockHeader, + plain_proof: Fp16PlainProof, + debug: bool, +) -> tuple[bytes, bytes]: + """Prove a winning FP16 (A100) tile into the header-bound ``Fp16ZkCertificate``. + + ``plain_proof`` is the opener bundle the miner assembles (job + the committed + Merkle openings at the winning tile); the prover re-opens + authenticates the + tile codes under ``header`` and produces the constant-size wrapped proof. The + V5 certificate carries no public-data blob, so public_data is empty and the + cert bytes ride entirely in proof_data (``CertificateV5.ProofData``). + """ + global _fp16_prover + if _fp16_prover is None: + _LOGGER.info("Building Fp16Prover (per-geometry wrapper compiles on first proof)") + _fp16_prover = Fp16Prover() + cert_bytes = bytes(_fp16_prover.prove_from_plain_proof(header, plain_proof)) + if debug: + # FP16 consensus verification is the node's job (verify_fp16_zk_cert_ffi); + # there is no in-process Python verifier, so there is nothing to self-check + # here without recompiling the (minutes-long) wrapper verifier. + _LOGGER.info("FP16 debug self-verify is node-side only; skipping in-worker check") + return b"", cert_bytes + + def prove( cert_version: int, incomplete_header_bytes: bytes, @@ -93,6 +123,8 @@ def prove( header = IncompleteBlockHeader.from_bytes(incomplete_header_bytes) if cert_version == CERT_VERSION_PLAIN_FP8: return _prove_fp8(header, PlainProofV4.from_base64(plain_proof_b64), debug) + if cert_version == CERT_VERSION_PLAIN_FP16: + return _prove_fp16(header, Fp16PlainProof.from_base64(plain_proof_b64), debug) plain_proof = PlainProof.from_base64(plain_proof_b64) zk_proof = generate_proof_for_cert_version(cert_version, header, plain_proof) diff --git a/miner/pearl-gateway/src/pearl_gateway/submission_service.py b/miner/pearl-gateway/src/pearl_gateway/submission_service.py index b2604f244..db66fb7d5 100644 --- a/miner/pearl-gateway/src/pearl_gateway/submission_service.py +++ b/miner/pearl-gateway/src/pearl_gateway/submission_service.py @@ -2,7 +2,12 @@ from typing import TYPE_CHECKING, Any from miner_utils import get_logger -from pearl_mining import PlainProof, PlainProofV4, check_cert_version_eligible +from pearl_mining import ( + Fp16PlainProof, + PlainProof, + PlainProofV4, + check_cert_version_eligible, +) from pearl_gateway.comm.dataclasses import BlockTemplate from pearl_gateway.pearl_client import PearlNodeClient @@ -35,7 +40,16 @@ def __init__( self.accepted_blocks = 0 self.rejected_blocks = 0 - async def _build_block(self, plain_proof: PlainProof | PlainProofV4, template: BlockTemplate): + async def _build_block( + self, + plain_proof: PlainProof | PlainProofV4 | Fp16PlainProof, + template: BlockTemplate, + ): + # V5 (FP16 / A100) now proves like every other ZK scheme: the miner's + # Fp16PlainProof is the opener bundle, and the prover (worker ``_prove_fp16``) + # turns it into the header-bound Fp16ZkCertificate that rides in ProofData + # (public_data = b""). It is no longer submit-direct — the plaintext proof is + # never the certificate. if self.proof_pool is not None: public_data, proof_data = await self.proof_pool.prove( int(template.required_cert_version), @@ -47,7 +61,9 @@ async def _build_block(self, plain_proof: PlainProof | PlainProofV4, template: B return ProofGenerator.generate_block(plain_proof, template, self.debug_mode) async def submit_plain_proof( - self, plain_proof: PlainProof | PlainProofV4, template: BlockTemplate + self, + plain_proof: PlainProof | PlainProofV4 | Fp16PlainProof, + template: BlockTemplate, ) -> dict[str, Any]: """ Submit a block built from a plain proof and the current template. diff --git a/miner/pearl-gateway/tests/test_zk_certificate.py b/miner/pearl-gateway/tests/test_zk_certificate.py index fe9a16213..a81a55447 100644 --- a/miner/pearl-gateway/tests/test_zk_certificate.py +++ b/miner/pearl-gateway/tests/test_zk_certificate.py @@ -8,6 +8,7 @@ CertificateProof, CertificateVersion, ZKCertificate, + _max_proof_data_size, ) from pearl_mining import MIN_MOE_PUBLICDATA_SIZE, PUBLICDATA_SIZE @@ -18,7 +19,10 @@ def _public_data(cert_version: CertificateVersion) -> bytes: - # V1 pins public data to PUBLICDATA_SIZE; V2/V3/V4 length-prefix a larger blob. + # V1 pins public data to PUBLICDATA_SIZE; V2/V3/V4 length-prefix a larger + # blob; V5 (FP16) carries no public data at all (the statement is in proof_data). + if cert_version == CertificateVersion.PLAIN_FP16: + return b"" size = ( PUBLICDATA_SIZE if cert_version == CertificateVersion.ZK_DENSE else MIN_MOE_PUBLICDATA_SIZE ) @@ -49,10 +53,11 @@ def test_serialize_round_trip(cert_version): restored = ZKCertificate.deserialize(wire) expected = struct.pack(" ZK_MAX_BLOB_SIZE + assert len(big_proof) <= _max_proof_data_size(CertificateVersion.PLAIN_FP16) + certificate = ZKCertificate( + HEADER_HASH, + CertificateProof(b"", big_proof), + CertificateVersion.PLAIN_FP16, + ) + restored = ZKCertificate.deserialize(certificate.serialize()) + assert restored.cert_version == CertificateVersion.PLAIN_FP16 + assert bytes(restored.proof.proof_data) == big_proof + + +def test_v5_deserialize_rejects_oversize_proof(): + # Just past the V5 ceiling must still be rejected on deserialize. + over = _max_proof_data_size(CertificateVersion.PLAIN_FP16) + 1 + with pytest.raises(ValueError, match="exceeds max size"): + ZKCertificate.deserialize(_v5_wire(bytes(over))) + + def test_v4_rejects_truncated_certificate(): wire = _v4_wire(b"public", PROOF_DATA, b"\x02" + b"".join(ANCESTOR_BYTES)) for end in range(len(wire)): @@ -139,8 +216,11 @@ def test_ancestor_count_limit_for_each_version(cert_version): HEADER_HASH, CertificateProof(_public_data(cert_version), PROOF_DATA), cert_version ) header = PearlHeader.deserialize(ANCESTOR_BYTES[0]) + # Versions that accept ancestors reject >2; versions that do not reject any. certificate.ancestor_headers = [header] * ( - 3 if cert_version == CertificateVersion.PLAIN_FP8 else 1 + 3 + if cert_version in (CertificateVersion.PLAIN_FP8, CertificateVersion.PLAIN_FP16) + else 1 ) with pytest.raises(ValueError): certificate.serialize() @@ -185,9 +265,11 @@ def test_v4_block_framing(count): @pytest.mark.parametrize("cert_version", list(CertificateVersion)) def test_all_versions_reject_oversized_proofs(cert_version): + # The proof-data cap is version-aware (V5/FP16 carries a ~256 KiB wrapped ZK + # proof; V1-V4 keep 60 KB), so size each over-limit blob to its own cap. proof = CertificateProof( _public_data(cert_version), - bytes(ZKCertificate.ZK_MAX_PROOF_DATA_SIZE + 1), + bytes(_max_proof_data_size(cert_version) + 1), ) with pytest.raises(ValueError, match="Proof data is too large"): diff --git a/miner/pearl-gemm/docs/sm80_feasibility.md b/miner/pearl-gemm/docs/sm80_feasibility.md new file mode 100644 index 000000000..2440cef61 --- /dev/null +++ b/miner/pearl-gemm/docs/sm80_feasibility.md @@ -0,0 +1,58 @@ +# SM80 (A100 / GA100) FP16 GEMM — feasibility probe + +**Verdict: GO. Backend: raw CUDA (`mma.sync.m16n8k16.f32.f16`) via `torch.utils.cpp_extension.load_inline` with `-arch=sm_80`.** + +## What was tested + +The FP16 scheme's verifier replays the A100 `HMMA.16816.F32` accumulation, +modeled in `zk-pow/src/api/fp16/accumulate.rs` (`a100_dot` / `a100_matmul`): the +k axis in groups of `G = 8`, per-group alignment exponent `eta`, truncate-toward- +zero onto `2^(eta-24)`, exact integer sum, round-toward-zero to FP32 after every +group. That model was **measured from this exact silicon**, so a straight sm_80 +FP16 tensor-core GEMM with FP32 accumulation and a pinned ascending-k reduction +(no split-k, no atomics) should reproduce it bit-for-bit natively. + +The probe (`feas.py`, archived) compiles a single-warp kernel that computes one +`16x8` FP32 output tile = `A(16xK) · B(8xK)ᵀ`, looping over k in steps of 16 with +one `mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32` per chunk, chaining the +FP32 accumulator forward (no split-k). It compares the output **bit pattern** +(`float32` → `uint32`) against a Python integer-exact port of `a100_dot` +(`tests/helpers/a100_fp16_reference.py`, itself validated bit-exact against all +238 reference vectors in `testdata/a100_dot_vectors.txt`). + +## Result + +Hardware: NVIDIA CMP 170HX (GA100, compute cap 8.0), CUDA 12.8, nvcc `-arch=sm_80`. + +``` +K=16: 0/128 mismatches +K=32: 0/128 +K=64: 0/128 +K=128: 0/128 +K=256: 0/128 +TOTAL: 0 / 640 => BIT-EXACT +``` + +The native sm_80 `mma.sync.m16n8k16` chain with pinned k-order **is** the +verifier model, bit-for-bit, on real GA100 tensor cores. + +## Backend choice: raw CUDA, not CuTe + +`pyproject.toml` pins `nvidia-cutlass-dsl[cu13]>=4.6.0`, but **4.5.0** is what is +installed. Rather than fight that toolchain pin on sm_80 (and because the +existing `_kernel_sm120.py` warp-mma path is deeply specialized for the *FP8* +lottery datapath — f8f6f4 atoms, peel/unscale, hit-signal), the bit-exact FP16 +tile is shipped as a small hand-written CUDA kernel compiled with +`-arch=sm_80` and loaded via `cpp_extension`. This is the "proven to work" +fallback named in the task brief and keeps the FP16 path independent of the FP8 +CuTe stack. + +## Scope shipped vs deferred + +- **Shipped:** the bit-exact sm_80 FP16→FP32 GEMM tile (the datapath the verifier + replays and the ticket hashes), `Arch.SM80` + protocol constants, the Python + oracle, and an on-GPU bit-exact + determinism test. +- **Deferred (documented, not implemented):** on-GPU lottery hit-signal, the C'' + peel/denoise, and the FP16 noisy-quant / noise-line / tensor-hash kernels. + These are the FP8-style fusion follow-ons; the GEMM tile is the core + correctness target and is complete. diff --git a/miner/pearl-gemm/examples/gpu_fp16_win.py b/miner/pearl-gemm/examples/gpu_fp16_win.py new file mode 100644 index 000000000..671b95c06 --- /dev/null +++ b/miner/pearl-gemm/examples/gpu_fp16_win.py @@ -0,0 +1,138 @@ +"""On-GPU FP16/A100 winning-tile driver + end-to-end plaintext consensus verify. + +Runs the real sm_80 lottery search on the local CMP 170HX at the committed-fixture +geometry (h=4, w=64, k=256; M=8, N=128) with EASY nbits and the honest_fixture +header, decodes the latched winner, assembles the Fp16PlainProof from the GPU tile, +and verifies it through pearl_mining.verify_fp16_plain_proof (the consensus +plaintext oracle). Also checks byte-identity to the committed plaintext fixture and +dumps (header | u32 len | plain_proof_bytes) for the Rust ZK verify. +""" +import struct, sys +from pathlib import Path +import numpy as np +import torch + +from pearl_gemm.fp16_miner import search_block, Fp16JobParams, Fp16OperandParams, difficulty_bound +from pearl_gemm.fp16_pipeline import AxisPattern + +M, N, K, R = 8, 128, 256, 32 +NBITS = 0x207FFFFF +GEN_SEED = 0xDEADBEEF0BADF00D +U64 = (1 << 64) - 1 +BLAKE, FOLD = 2, 1 # DimType codes used by pearl_gemm.AxisPattern.new + + +class Gen: + """Byte-identical to Rust Gen / miner_base test _Gen (xorshift64 + f32->f16).""" + def __init__(self, seed): self.s = seed & U64 + def _next(self): + self.s ^= (self.s << 13) & U64 + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & U64 + return self.s + def operand(self, n): + out = np.empty(n, np.float16) + for i in range(n): + r = self._next() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = ((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(np.float32(sign * mant * (2.0 ** exp))) + return out + + +def honest_header(): + return (struct.pack("=0.30 -> {wt.report.f_bp>=0.30} ; rho>=1.2 -> {wt.report.rho>=1.2}") + print(f" jackpot ticket = {wt.ticket.hex()}") + print(f" ticket(LE int) <= bound ? {ticket_le <= bound} (clears EASY difficulty)") + print(f" seed_a = {wt.seed_a.hex()}") + print(f" pow_key = {wt.seeds.pow_key.hex()}") + print(f" root_a = {wt.seeds.root_a.hex()}") + print(f" root_b = {wt.seeds.root_b.hex()}") + + # Dump a few operand values for the record. + print(f" opened_a_rows[0,:6] = {wt.opened_a_rows[0,:6].cpu().numpy().tolist()}") + print(f" opened_b_rows[0,:6] = {wt.opened_b_rows[0,:6].cpu().numpy().tolist()}") + + # ---- Assemble + verify the plaintext consensus certificate (path b) ---- + import pearl_mining + from miner_base.fp16_block_submission import create_fp16_proof + from miner_base.layout import AxisPattern as MbPattern, DimType + from miner_base.params import HashId + + mb_rp = MbPattern(((4, DimType.BLAKE),)) + mb_cp = MbPattern(((4, DimType.BLAKE), (16, DimType.FOLD))) + proof = create_fp16_proof( + header, a.view(np.uint16), b.view(np.uint16), k=K, m=M, n=N, + rows_pattern=mb_rp, cols_pattern=mb_cp, + tile_row=wt.tile_row, tile_col=wt.tile_col, hash_id=HashId.BLAKE3_CHUNK_1024, + ) + print(f"\n=== Plaintext certificate (Fp16PlainProof) from the GPU tile ===") + print(f" values_a.row_indices = {list(proof.values_a.row_indices)}") + print(f" values_b.row_indices = {list(proof.values_b.row_indices)[:4]}..{list(proof.values_b.row_indices)[-2:]}") + print(f" a.num_rows={proof.a.num_rows} b.num_rows={proof.b.num_rows} k={proof.k} r={proof.r}") + + ok, msg = pearl_mining.verify_fp16_plain_proof( + pearl_mining.IncompleteBlockHeader.from_bytes(header), proof, None) + print(f" verify_fp16_plain_proof -> ok={ok} msg={msg!r}") + assert ok, f"consensus plaintext verifier REJECTED the GPU tile: {msg}" + + # Byte-identity to the committed Go/Rust fixture (proves the GPU found the + # canonical honest winner). + fx = Path("/home/jon/projects/pearl/node/zkpow/testdata/fp16_plain_proof_a100.bin") + pbytes = bytes(proof.to_bytes()) + if fx.exists(): + blob = fx.read_bytes() + plen = struct.unpack_from(" {out}") + print("\nRESULT: GPU-found FP16/A100 tile WINS and is ACCEPTED by the consensus plaintext verifier.") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/miner/pearl-gemm/src/pearl_gemm/__init__.py b/miner/pearl-gemm/src/pearl_gemm/__init__.py index c6a820a28..c12d8d12a 100644 --- a/miner/pearl-gemm/src/pearl_gemm/__init__.py +++ b/miner/pearl-gemm/src/pearl_gemm/__init__.py @@ -8,6 +8,16 @@ per-process PoW hit signal (``HitSignal``). """ +from .api import ( + fp16_commit, + fp16_gemm, + fp16_miner, + fp16_noise_lines, + fp16_noisy_quant, + fp16_pipeline, + fp16_policy, + fp16_search, +) from .api import ( LABEL_E1, LABEL_E2, @@ -60,6 +70,14 @@ ) __all__ = [ + "fp16_commit", + "fp16_gemm", + "fp16_miner", + "fp16_noise_lines", + "fp16_noisy_quant", + "fp16_pipeline", + "fp16_policy", + "fp16_search", "BLOCK_SCALE_GROUP", "GroupedFp8GemmConfig", "GroupedMixedGemmConfig", diff --git a/miner/pearl-gemm/src/pearl_gemm/_utils/_arch.py b/miner/pearl-gemm/src/pearl_gemm/_utils/_arch.py index 3b451f194..aa6f2313f 100644 --- a/miner/pearl-gemm/src/pearl_gemm/_utils/_arch.py +++ b/miner/pearl-gemm/src/pearl_gemm/_utils/_arch.py @@ -1,10 +1,11 @@ """Architecture families (one per compute-capability major) and the launch gate. -SM90: Hopper (WGMMA into register accumulators, promoted FP8 accumulation, -clusters). SM100: datacenter Blackwell (tcgen05, TMEM, clusters). SM120: -workstation and consumer Blackwell (warp-level ``mma.sync``, ~99 KB smem, no -TMEM/clusters). Each host declares the families it runs on through -``require_arch``. +SM80: Ampere datacenter (A100/GA100, warp-level ``mma.sync``, FP32-accumulated +FP16 tensor cores; the FP16 scheme's native target). SM90: Hopper (WGMMA into +register accumulators, promoted FP8 accumulation, clusters). SM100: datacenter +Blackwell (tcgen05, TMEM, clusters). SM120: workstation and consumer Blackwell +(warp-level ``mma.sync``, ~99 KB smem, no TMEM/clusters). Each host declares the +families it runs on through ``require_arch``. """ from enum import Enum @@ -12,12 +13,18 @@ import cutlass.utils import torch -from ..protocol_constants import SM90_CC_MAJOR, SM100_CC_MAJOR, SM120_CC_MAJOR +from ..protocol_constants import ( + SM80_CC_MAJOR, + SM90_CC_MAJOR, + SM100_CC_MAJOR, + SM120_CC_MAJOR, +) class Arch(Enum): """One compute-capability major, named after its lead SM target.""" + SM80 = SM80_CC_MAJOR SM90 = SM90_CC_MAJOR SM100 = SM100_CC_MAJOR SM120 = SM120_CC_MAJOR diff --git a/miner/pearl-gemm/src/pearl_gemm/api.py b/miner/pearl-gemm/src/pearl_gemm/api.py index 90b56ed72..d4c1de94e 100644 --- a/miner/pearl-gemm/src/pearl_gemm/api.py +++ b/miner/pearl-gemm/src/pearl_gemm/api.py @@ -1,5 +1,18 @@ """Caller-owned functional API for the new-scheme operations.""" +# FP16 (A100 / sm_80) scheme primitives, exposed as submodule namespaces so the +# bit-exact PoUW datapath is reachable as `pearl_gemm.fp16_*` without colliding +# with the FP8-family flat exports below (e.g. both schemes have a `noise_lines`). +from . import ( + fp16_commit, + fp16_gemm, + fp16_miner, + fp16_noise_lines, + fp16_noisy_quant, + fp16_pipeline, + fp16_policy, + fp16_search, +) from .grouped_fp8_gemm import ( GroupedFp8GemmConfig, grouped_fp8_gemm, @@ -60,6 +73,14 @@ ) __all__ = [ + "fp16_commit", + "fp16_gemm", + "fp16_miner", + "fp16_noise_lines", + "fp16_noisy_quant", + "fp16_pipeline", + "fp16_policy", + "fp16_search", "GroupedFp8GemmConfig", "GroupedMixedGemmConfig", "Hit", diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_commit/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/__init__.py new file mode 100644 index 000000000..df126df41 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/__init__.py @@ -0,0 +1,21 @@ +"""Bit-exact A100 (``sm_80``) keyed-BLAKE3 Merkle commitment over FP16 operand +rows for the FP16 proof-of-useful-work scheme. + +Reproduces ``zk-pow/src/api/fp16/commitment.rs::commit_operand`` -- the +``pearl_blake3::MerkleTree::with_chunk_len`` keyed Merkle root directly over the +FP16 rows (little-endian ``u16`` row-major, zero-padded to the ``HashId`` +chunk length) -- bit-for-bit on real GA100 silicon. This is the operand +commitment root that goes into the FP16 certificate. +""" + +from ._host import ( + ALLOWED_CHUNK_LENS, + DEFAULT_CHUNK_LEN, + commit_operand, +) + +__all__ = [ + "ALLOWED_CHUNK_LENS", + "DEFAULT_CHUNK_LEN", + "commit_operand", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_host.py new file mode 100644 index 000000000..0cd604cb9 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_host.py @@ -0,0 +1,125 @@ +"""Host launch for the bit-exact A100 (``sm_80``) FP16 operand commitment. + +Reproduces ``zk-pow/src/api/fp16/commitment.rs::commit_operand`` -- i.e. +``pearl_blake3::MerkleTree::with_chunk_len(hash_id.pad(rows_to_bytes(rows)), +key, hash_id.chunk_len())`` -- on real GA100 silicon, returning the 32-byte +keyed-BLAKE3 Merkle root bit-for-bit against the verifier. + +The committed byte image is the FP16 rows as little-endian ``u16`` row-major, +zero-padded up to a multiple of ``chunk_len`` (``HashId::pad``). That padded +image is uploaded as ``u32`` words and reduced to the root entirely on the GPU: +one keyed-BLAKE3 non-root chunk CV per ``chunk_len``-byte leaf (chunk counter = +leaf index), keyed non-root parent compressions up the tree (lone odd nodes +promoted), and a ROOT-finalized final combine -- with the single-leaf tree +special-cased to the ROOT-finalized hash of its one chunk, exactly as the +reference's ``MerkleTree::with_chunk_len``. + +The BLAKE3 compression + tree reduction run in a small hand-written CUDA +extension compiled with ``nvcc -arch=sm_80`` (loaded through +``torch.utils.cpp_extension``), exactly like ``fp16_gemm`` / +``fp16_noisy_quant`` / ``fp16_noise_lines``; the compression is the one agent B +validated bit-identical to the ``blake3`` crate, reused verbatim. +""" + +from __future__ import annotations + +import functools +import os + +import numpy as np +import torch + +from .._utils._arch import Arch, require_arch + +_SUPPORTED_ARCHS = (Arch.SM80,) + +# Leaf sizes the reference tree accepts (``pearl_blake3::ALLOWED_CHUNK_LENS`` / +# ``HashId::chunk_len``); the FP16 scheme's operand ``HashId`` is one of these. +ALLOWED_CHUNK_LENS = (128, 256, 512, 1024) +# The operand ``HashId`` the FP16 certificate/verifier default to +# (``HashId::Blake3Chunk1024``); operands may use any allowed length. +DEFAULT_CHUNK_LEN = 1024 + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_commit_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +def _key_words(key: bytes, device: torch.device) -> torch.Tensor: + """The 8 little-endian ``u32`` words of the 32-byte ``key``, on ``device``.""" + if len(key) != 32: + raise ValueError(f"key must be 32 bytes, got {len(key)}") + words = [int.from_bytes(key[4 * i : 4 * i + 4], "little") for i in range(8)] + signed = [w - (1 << 32) if w >= (1 << 31) else w for w in words] + return torch.tensor(signed, dtype=torch.int32, device=device) + + +def _rows_to_u16(rows, num_rows: int, k: int) -> np.ndarray: + """``num_rows x k`` FP16 bit patterns as a flat ``uint16`` array.""" + if isinstance(rows, torch.Tensor): + arr = rows.detach().cpu().contiguous().view(torch.int16).numpy().view(np.uint16) + else: + arr = np.asarray(rows) + arr = arr.reshape(-1).astype(np.uint16, copy=False) + if arr.size != num_rows * k: + raise ValueError(f"operand is not num_rows x k ({arr.size} != {num_rows}*{k})") + return arr + + +def _padded_u32(rows_u16: np.ndarray, chunk_len: int) -> tuple[np.ndarray, int]: + """Little-endian byte image zero-padded to a ``chunk_len`` multiple, as ``u32``. + + Returns ``(words, num_leaves)``. + """ + raw = rows_u16.astype(" bytes: + """Keyed-BLAKE3 Merkle root over the FP16 operand rows (32 bytes). + + ``rows`` is a ``num_rows x k`` FP16 operand (torch ``int16``/``uint16`` view + or any array of ``u16`` bit patterns), row-major; ``key`` is the 32-byte + per-tree BLAKE3 key; ``chunk_len`` is the operand ``HashId::chunk_len`` (one + of 128/256/512/1024). Returns the root bit-exact to ``commit_operand(rows, + num_rows, k, HashId::from(chunk_len), key)``. + """ + if chunk_len not in ALLOWED_CHUNK_LENS: + raise ValueError(f"chunk_len must be one of {ALLOWED_CHUNK_LENS}, got {chunk_len}") + dev = ( + torch.device("cuda", device) + if isinstance(device, int) + else (device or torch.device("cuda")) + ) + require_arch("fp16_commit", dev, *_SUPPORTED_ARCHS) + + rows_u16 = _rows_to_u16(rows, num_rows, k) + words, num_leaves = _padded_u32(rows_u16, chunk_len) + + data32 = torch.from_numpy(words.view(np.int32)).to(dev) + key_t = _key_words(key, dev) + out = _extension().fp16_commit_root(data32, key_t, int(num_leaves), int(chunk_len)) + root_words = out.cpu().numpy().view(np.uint32) + return b"".join(int(w).to_bytes(4, "little") for w in root_words) diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_kernel_sm80.cu new file mode 100644 index 000000000..3be48cc56 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_commit/_kernel_sm80.cu @@ -0,0 +1,301 @@ +// Bit-exact A100 (sm_80) keyed-BLAKE3 Merkle commitment over FP16 operand rows. +// +// Reproduces zk-pow/src/api/fp16/commitment.rs::commit_operand -- i.e. +// pearl_blake3::MerkleTree::with_chunk_len(hash_id.pad(rows_to_bytes(rows)), +// key, hash_id.chunk_len()) -- producing the 32-byte Merkle root bit-for-bit. +// +// Tree discipline (see pearl-blake3/src/merkle.rs + hasher.rs): +// * Committed bytes: FP16 rows as little-endian u16 row-major, zero-padded up +// to a multiple of chunk_len (done on the host). +// * Leaf i hash = keyed BLAKE3 *non-root* chunk CV of that chunk_len-byte leaf +// with the BLAKE3 chunk counter = i. Every allowed chunk_len (128/256/512/ +// 1024) is <= one native BLAKE3 chunk (1024), so a leaf is one chunk of +// chunk_len/64 full 64-byte blocks: first block flags |= CHUNK_START, last +// block flags |= CHUNK_END, base flag KEYED_HASH, counter = i throughout. +// * Internal nodes: keyed non-root parent compression of (left||right); a lone +// odd node is promoted unchanged. +// * When a layer has exactly two nodes, the root is their keyed *root*- +// finalized parent compression. +// * Single-leaf tree (padded image <= chunk_len): root is the ROOT-finalized +// keyed hash of the one chunk, not a non-root chunk CV. +// +// The BLAKE3 compression is the one agent B validated bit-identical to the +// `blake3` crate on this GA100 (fp16_noise_lines/_kernel_sm80.cu), reused +// verbatim; only the leaf/parent/root wrappers and the tree reduction are new. + +#include + +// ---- BLAKE3 keyed compression (from fp16_noise_lines; crate-identical) ---- + +__constant__ unsigned int BLAKE3_IV[8] = { + 0x6A09E667u, 0xBB67AE85u, 0x3C6EF372u, 0xA54FF53Au, + 0x510E527Fu, 0x9B05688Cu, 0x1F83D9ABu, 0x5BE0CD19u}; + +// Domain-separation flags (pearl_blake3::hasher). +#define B3F_CHUNK_START 1u +#define B3F_CHUNK_END 2u +#define B3F_PARENT 4u +#define B3F_ROOT 8u +#define B3F_KEYED_HASH 16u + +__device__ __forceinline__ unsigned int rotr32(unsigned int x, unsigned int n) { + return (x >> n) | (x << (32u - n)); +} + +// One BLAKE3 compression of a single 64-byte message block `m` under chaining +// value `cv`, at `counter` (lo/hi), block length 64, with `flags`. Writes the +// full 16-word output: out[0..8] = s[0..8]^s[8..16] (the next chaining value / +// 32-byte hash output); out[8..16] = s[8..16]^cv[0..8]. +__device__ void blake3_compress(const unsigned int cv[8], const unsigned int m[16], + unsigned int counter_lo, unsigned int counter_hi, + unsigned int flags, unsigned int out[16]) { + unsigned int s[16]; +#pragma unroll + for (int i = 0; i < 8; ++i) s[i] = cv[i]; + s[8] = BLAKE3_IV[0]; + s[9] = BLAKE3_IV[1]; + s[10] = BLAKE3_IV[2]; + s[11] = BLAKE3_IV[3]; + s[12] = counter_lo; + s[13] = counter_hi; + s[14] = 64u; // block_len (always a full 64-byte block here) + s[15] = flags; + + unsigned int v[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = m[i]; + + const int PERM[16] = {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}; + +#define G(a, b, c, d, x, y) \ + s[a] = s[a] + s[b] + (x); \ + s[d] = rotr32(s[d] ^ s[a], 16); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 12); \ + s[a] = s[a] + s[b] + (y); \ + s[d] = rotr32(s[d] ^ s[a], 8); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 7); + + for (int round = 0; round < 7; ++round) { + G(0, 4, 8, 12, v[0], v[1]); + G(1, 5, 9, 13, v[2], v[3]); + G(2, 6, 10, 14, v[4], v[5]); + G(3, 7, 11, 15, v[6], v[7]); + G(0, 5, 10, 15, v[8], v[9]); + G(1, 6, 11, 12, v[10], v[11]); + G(2, 7, 8, 13, v[12], v[13]); + G(3, 4, 9, 14, v[14], v[15]); + if (round < 6) { + unsigned int t[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) t[i] = v[PERM[i]]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = t[i]; + } + } +#undef G + +#pragma unroll + for (int i = 0; i < 8; ++i) { + out[i] = s[i] ^ s[i + 8]; + out[i + 8] = s[i + 8] ^ cv[i]; + } +} + +// ---- Merkle wrappers ---- + +// Keyed BLAKE3 chunk chaining value of one leaf: `words_per_leaf` u32 words +// (= chunk_len/4, a multiple of 16) starting at `leaf`, counter = leaf index. +// `root` toggles ROOT finalization on the last block. +__device__ void leaf_cv(const unsigned int* __restrict__ data, long leaf, + int words_per_leaf, const unsigned int key[8], bool root, + unsigned int out_cv[8]) { + unsigned int cv[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) cv[i] = key[i]; + + int num_blocks = words_per_leaf / 16; // 64-byte blocks in this leaf + const unsigned int* base = data + leaf * (long)words_per_leaf; + unsigned int counter_lo = (unsigned int)leaf; + unsigned int counter_hi = (unsigned int)((unsigned long long)leaf >> 32); + + for (int b = 0; b < num_blocks; ++b) { + unsigned int m[16]; +#pragma unroll + for (int w = 0; w < 16; ++w) m[w] = base[b * 16 + w]; + unsigned int flags = B3F_KEYED_HASH; + if (b == 0) flags |= B3F_CHUNK_START; + if (b == num_blocks - 1) { + flags |= B3F_CHUNK_END; + if (root) flags |= B3F_ROOT; + } + unsigned int o[16]; + blake3_compress(cv, m, counter_lo, counter_hi, flags, o); +#pragma unroll + for (int i = 0; i < 8; ++i) cv[i] = o[i]; + } +#pragma unroll + for (int i = 0; i < 8; ++i) out_cv[i] = cv[i]; +} + +// Keyed parent compression of (left||right); `root` toggles ROOT finalization. +__device__ void parent_cv(const unsigned int left[8], const unsigned int right[8], + const unsigned int key[8], bool root, unsigned int out_cv[8]) { + unsigned int m[16]; +#pragma unroll + for (int i = 0; i < 8; ++i) { + m[i] = left[i]; + m[i + 8] = right[i]; + } + unsigned int flags = B3F_KEYED_HASH | B3F_PARENT | (root ? B3F_ROOT : 0u); + unsigned int o[16]; + blake3_compress(key, m, 0u, 0u, flags, o); +#pragma unroll + for (int i = 0; i < 8; ++i) out_cv[i] = o[i]; +} + +// ---- Kernels ---- + +// One thread per leaf: compute the non-root leaf CVs into `cvs` (8 u32 each). +__global__ void leaves_kernel(const unsigned int* __restrict__ data, long num_leaves, + int words_per_leaf, const unsigned int* __restrict__ key, + unsigned int* __restrict__ cvs) { + long tid = (long)blockIdx.x * blockDim.x + threadIdx.x; + if (tid >= num_leaves) return; + unsigned int k[8], cv[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) k[i] = key[i]; + leaf_cv(data, tid, words_per_leaf, k, /*root=*/false, cv); +#pragma unroll + for (int i = 0; i < 8; ++i) cvs[tid * 8 + i] = cv[i]; +} + +// Single-leaf tree: ROOT-finalized keyed hash of the one chunk. +__global__ void single_leaf_root_kernel(const unsigned int* __restrict__ data, + int words_per_leaf, + const unsigned int* __restrict__ key, + unsigned int* __restrict__ out) { + if (blockIdx.x || threadIdx.x) return; + unsigned int k[8], cv[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) k[i] = key[i]; + leaf_cv(data, 0, words_per_leaf, k, /*root=*/true, cv); +#pragma unroll + for (int i = 0; i < 8; ++i) out[i] = cv[i]; +} + +// One layer of the reduction: out[j] = parent_cv(in[2j], in[2j+1]) for a full +// pair, else carry in[2j] (lone odd node). Never applies ROOT (handled apart). +__global__ void combine_kernel(const unsigned int* __restrict__ in, long in_len, + const unsigned int* __restrict__ key, + unsigned int* __restrict__ out) { + long j = (long)blockIdx.x * blockDim.x + threadIdx.x; + long out_len = (in_len + 1) / 2; + if (j >= out_len) return; + unsigned int k[8], res[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) k[i] = key[i]; + long l = 2 * j; + if (l + 1 < in_len) { + unsigned int left[8], right[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) { + left[i] = in[l * 8 + i]; + right[i] = in[(l + 1) * 8 + i]; + } + parent_cv(left, right, k, /*root=*/false, res); + } else { +#pragma unroll + for (int i = 0; i < 8; ++i) res[i] = in[l * 8 + i]; + } +#pragma unroll + for (int i = 0; i < 8; ++i) out[j * 8 + i] = res[i]; +} + +// Final ROOT-finalized combine of exactly two nodes. +__global__ void root_kernel(const unsigned int* __restrict__ in, + const unsigned int* __restrict__ key, + unsigned int* __restrict__ out) { + if (blockIdx.x || threadIdx.x) return; + unsigned int k[8], left[8], right[8], res[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) { + k[i] = key[i]; + left[i] = in[i]; + right[i] = in[8 + i]; + } + parent_cv(left, right, k, /*root=*/true, res); +#pragma unroll + for (int i = 0; i < 8; ++i) out[i] = res[i]; +} + +// ---- Host launcher ---- + +// `data32`: padded operand image as u32 (num_leaves * chunk_len/4 words). +// `key`: 8 u32 BLAKE3 key words. Returns the 32-byte root as 8 u32 words +// (little-endian byte order within each word gives the root bytes). +torch::Tensor fp16_commit_root(torch::Tensor data32, torch::Tensor key, + long num_leaves, long chunk_len) { + TORCH_CHECK(data32.is_cuda() && data32.scalar_type() == torch::kInt32, + "data32 must be an int32 CUDA tensor"); + TORCH_CHECK(key.is_cuda() && key.scalar_type() == torch::kInt32 && key.numel() == 8, + "key must be an int32 CUDA tensor of 8 words"); + TORCH_CHECK(chunk_len == 128 || chunk_len == 256 || chunk_len == 512 || chunk_len == 1024, + "chunk_len must be one of 128/256/512/1024"); + TORCH_CHECK(num_leaves >= 1, "num_leaves must be >= 1"); + int words_per_leaf = (int)(chunk_len / 4); + TORCH_CHECK(data32.numel() == num_leaves * words_per_leaf, + "data32 length must equal num_leaves * chunk_len/4"); + data32 = data32.contiguous(); + key = key.contiguous(); + + auto u32 = torch::dtype(torch::kInt32).device(data32.device()); + auto out = torch::empty({8}, u32); + const unsigned int* data_p = (const unsigned int*)data32.data_ptr(); + const unsigned int* key_p = (const unsigned int*)key.data_ptr(); + + if (num_leaves == 1) { + single_leaf_root_kernel<<<1, 1>>>(data_p, words_per_leaf, key_p, + (unsigned int*)out.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "single_leaf_root launch failed"); + return out; + } + + // Leaf layer. + auto cur = torch::empty({num_leaves * 8}, u32); + { + int threads = 128; + long blocks = (num_leaves + threads - 1) / threads; + leaves_kernel<<>>(data_p, num_leaves, words_per_leaf, key_p, + (unsigned int*)cur.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "leaves launch failed"); + } + + // Reduce pairwise until exactly two nodes remain. + long len = num_leaves; + while (len > 2) { + long out_len = (len + 1) / 2; + auto nxt = torch::empty({out_len * 8}, u32); + int threads = 128; + long blocks = (out_len + threads - 1) / threads; + combine_kernel<<>>((const unsigned int*)cur.data_ptr(), len, key_p, + (unsigned int*)nxt.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "combine launch failed"); + cur = nxt; + len = out_len; + } + + // Final ROOT combine of the two surviving nodes. + root_kernel<<<1, 1>>>((const unsigned int*)cur.data_ptr(), key_p, + (unsigned int*)out.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "root launch failed"); + return out; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fp16_commit_root", &fp16_commit_root, + "A100 sm_80 keyed-BLAKE3 Merkle root over FP16 operand rows", + pybind11::arg("data32"), pybind11::arg("key"), pybind11::arg("num_leaves"), + pybind11::arg("chunk_len")); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/__init__.py new file mode 100644 index 000000000..06cf4a522 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/__init__.py @@ -0,0 +1,11 @@ +"""Bit-exact A100 (``sm_80``) FP16 -> FP32 GEMM for the FP16 proof-of-useful-work +scheme. + +The single public entry, :func:`fp16_gemm_a100`, computes the FP16 GEMM tile the +scheme's verifier replays, bit-for-bit, on real GA100 tensor cores. See +``docs/sm80_feasibility.md`` for the feasibility verdict and backend choice. +""" + +from ._host import fp16_gemm_a100 + +__all__ = ["fp16_gemm_a100"] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_host.py new file mode 100644 index 000000000..52d3bbf75 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_host.py @@ -0,0 +1,85 @@ +"""Host launch for the bit-exact A100 (``sm_80``) FP16 -> FP32 GEMM tile. + +This is the datapath the FP16 proof-of-useful-work scheme's verifier replays +(``zk-pow/src/api/fp16/accumulate.rs``). A plain ``sm_80`` FP16 tensor-core GEMM +with FP32 accumulation and a pinned ascending-k reduction (no split-k, no +atomics) reproduces that model bit-for-bit on real GA100 silicon, because the +model was measured from this exact ``HMMA.16816.F32`` datapath. + +The kernel is a small hand-written CUDA extension compiled with +``nvcc -arch=sm_80`` (loaded through ``torch.utils.cpp_extension``). The CuTe +path was not used: the repo's ``nvidia-cutlass-dsl`` is pinned ``>=4.6.0`` but +4.5.0 is installed, and the existing warp-mma kernel (``_kernel_sm120.py``) is +specialized for the FP8 lottery datapath. See ``docs/sm80_feasibility.md``. +""" + +from __future__ import annotations + +import functools +import os + +import torch + +from .._utils._arch import Arch, require_arch + +_SUPPORTED_ARCHS = (Arch.SM80,) + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_gemm_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +def fp16_gemm_a100( + a: torch.Tensor, + b: torch.Tensor, + *, + acc: torch.Tensor | None = None, + out: torch.Tensor | None = None, +) -> torch.Tensor: + """The A100 ``sm_80`` bit-exact FP16 GEMM tile ``D = a @ b.T (+ acc)``. + + ``a`` is ``(m, k)`` float16 and ``b`` is ``(n, k)`` float16 -- the transposed + logical right operand, so ``D[i, j]`` accumulates ``sum_u a[i, u] * b[j, u]``, + exactly as ``a100_matmul``'s ``b`` is laid out. ``acc`` is an optional + ``(m, n)`` float32 carry-in (``+0`` when omitted). Returns the ``(m, n)`` + float32 output tile; every element matches the verifier's replay of the A100 + ``HMMA.16816.F32`` accumulation bit-for-bit. + + Requires ``k % 16 == 0``, ``m % 16 == 0``, ``n % 8 == 0`` (the native + ``mma.sync.m16n8k16`` tile granularity). The reduction order over ``k`` is + pinned (ascending, FP32 accumulator chained across the whole axis; no + split-k, no atomics), which is what makes the result deterministic and + bit-exact against the verifier. + """ + if a.ndim != 2 or b.ndim != 2: + raise ValueError("a and b must be 2D") + if a.dtype != torch.float16 or b.dtype != torch.float16: + raise ValueError("a and b must be float16") + m, k = a.shape + n, bk = b.shape + if bk != k: + raise ValueError(f"b must have k={k}, got {bk}") + require_arch("fp16_gemm_a100", a.device, *_SUPPORTED_ARCHS) + a = a.contiguous() + b = b.contiguous() + if acc is not None: + if acc.shape != (m, n) or acc.dtype != torch.float32: + raise ValueError("acc must be (m, n) float32") + acc = acc.contiguous() + d = _extension().fp16_gemm_a100(a, b, acc) + if out is not None: + if out.shape != (m, n) or out.dtype != torch.float32: + raise ValueError("out must be (m, n) float32") + out.copy_(d) + return out + return d diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_kernel_sm80.cu new file mode 100644 index 000000000..ea83b646a --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_gemm/_kernel_sm80.cu @@ -0,0 +1,111 @@ +// Bit-exact A100 (sm_80) FP16 -> FP32 GEMM tile. +// +// Reproduces the FP16 scheme verifier's accumulation model +// (zk-pow/src/api/fp16/accumulate.rs) natively: the native HMMA.16816.F32 +// datapath *is* the model (the model was measured from this silicon). Each warp +// computes one 16x8 output subtile D = A(16xK) . B(8xK)^T with FP32 accumulation +// chained in ascending k order (groups of 16 per mma.sync, no split-k, no +// atomics), carrying c0..c3 forward across the whole k axis. This fixed +// reduction order is what makes the tile match the verifier bit-for-bit. +// +// A: (M, K) row-major FP16 (logical left operand) +// B: (N, K) row-major FP16 (the transposed logical right operand: row j is +// logical column j, exactly a100_matmul's `b`) +// C: (M, N) row-major FP32 carry-in, or null for +0 +// D: (M, N) row-major FP32 output +// Requires K % 16 == 0, M % 16 == 0, N % 8 == 0. + +#include +#include + +__device__ __forceinline__ unsigned pack2(const __half* p, int i0, int i1) { + __half2 h = __halves2half2(p[i0], p[i1]); + return *reinterpret_cast(&h); +} + +__global__ void fp16_gemm_a100_kernel( + const __half* __restrict__ A, + const __half* __restrict__ B, + const float* __restrict__ C, + float* __restrict__ D, + int M, int N, int K) { + // One warp (one block) owns one 16x8 output subtile. + // grid.x indexes the N tiles (8 cols each), grid.y the M tiles (16 rows each). + int m0 = blockIdx.y * 16; + int n0 = blockIdx.x * 8; + if (m0 >= M || n0 >= N) return; + + int lane = threadIdx.x & 31; + int gid = lane >> 2; // 0..7 + int t4 = lane & 3; // 0..3 + + const __half* Am = A + (long)m0 * K; // rows m0..m0+15 + const __half* Bn = B + (long)n0 * K; // rows n0..n0+7 (logical cols) + + float c0 = 0.f, c1 = 0.f, c2 = 0.f, c3 = 0.f; + if (C != nullptr) { + const float* Ct = C + (long)m0 * N + n0; + c0 = Ct[(gid) * N + t4 * 2]; + c1 = Ct[(gid) * N + t4 * 2 + 1]; + c2 = Ct[(gid + 8) * N + t4 * 2]; + c3 = Ct[(gid + 8) * N + t4 * 2 + 1]; + } + + for (int k0 = 0; k0 < K; k0 += 16) { + unsigned a0 = pack2(Am, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned a1 = pack2(Am, (gid + 8) * K + k0 + t4 * 2, (gid + 8) * K + k0 + t4 * 2 + 1); + unsigned a2 = pack2(Am, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + unsigned a3 = pack2(Am, (gid + 8) * K + k0 + t4 * 2 + 8, (gid + 8) * K + k0 + t4 * 2 + 9); + unsigned b0 = pack2(Bn, (gid) * K + k0 + t4 * 2, (gid) * K + k0 + t4 * 2 + 1); + unsigned b1 = pack2(Bn, (gid) * K + k0 + t4 * 2 + 8, (gid) * K + k0 + t4 * 2 + 9); + asm volatile( + "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 " + "{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};\n" + : "+f"(c0), "+f"(c1), "+f"(c2), "+f"(c3) + : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(b0), "r"(b1)); + } + + float* Dt = D + (long)m0 * N + n0; + Dt[(gid) * N + t4 * 2] = c0; + Dt[(gid) * N + t4 * 2 + 1] = c1; + Dt[(gid + 8) * N + t4 * 2] = c2; + Dt[(gid + 8) * N + t4 * 2 + 1] = c3; +} + +torch::Tensor fp16_gemm_a100(torch::Tensor A, torch::Tensor B, + c10::optional C) { + TORCH_CHECK(A.is_cuda() && B.is_cuda(), "A and B must be CUDA tensors"); + TORCH_CHECK(A.scalar_type() == torch::kFloat16, "A must be float16"); + TORCH_CHECK(B.scalar_type() == torch::kFloat16, "B must be float16"); + TORCH_CHECK(A.dim() == 2 && B.dim() == 2, "A and B must be 2D"); + TORCH_CHECK(A.is_contiguous() && B.is_contiguous(), "A and B must be contiguous"); + int M = A.size(0), K = A.size(1); + int N = B.size(0), Kb = B.size(1); + TORCH_CHECK(K == Kb, "A and B must share K"); + TORCH_CHECK(K % 16 == 0, "K must be a multiple of 16"); + TORCH_CHECK(M % 16 == 0, "M must be a multiple of 16"); + TORCH_CHECK(N % 8 == 0, "N must be a multiple of 8"); + + const float* Cptr = nullptr; + torch::Tensor Ct; + if (C.has_value()) { + Ct = C.value(); + TORCH_CHECK(Ct.is_cuda() && Ct.scalar_type() == torch::kFloat32, "C must be float32 CUDA"); + TORCH_CHECK(Ct.is_contiguous() && Ct.size(0) == M && Ct.size(1) == N, "C must be (M,N) contiguous"); + Cptr = (const float*)Ct.data_ptr(); + } + + auto D = torch::empty({M, N}, torch::dtype(torch::kFloat32).device(A.device())); + dim3 grid(N / 8, M / 16); + dim3 block(32, 1); + fp16_gemm_a100_kernel<<>>( + (const __half*)A.data_ptr(), (const __half*)B.data_ptr(), + Cptr, (float*)D.data_ptr(), M, N, K); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_gemm_a100 launch failed"); + return D; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fp16_gemm_a100", &fp16_gemm_a100, "A100 sm_80 bit-exact FP16->FP32 GEMM", + pybind11::arg("A"), pybind11::arg("B"), pybind11::arg("C") = c10::nullopt); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_miner/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/__init__.py new file mode 100644 index 000000000..3b4de0ab8 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/__init__.py @@ -0,0 +1,54 @@ +"""Host-side FP16 (A100 / ``sm_80``) lottery-search driver for the FP16 +proof-of-useful-work scheme. + +The standalone analogue of the FP8 ``_launch_stages``: from a job header and the +full plaintext FP16 operands, it derives the bit-exact seed chain +(``zk-pow/src/api/fp16/noise.rs`` + ``plain_proof.rs``), commits both operands, +chains the GA100-validated FP16 sm_80 kernels (``fp16_commit`` -> +``fp16_noise_lines`` -> ``fp16_noisy_quant`` -> ``fp16_search``), runs the +full-matrix lottery search, and decodes the latched hit into a verifiable winning +tile (opened rows + sliced noise + ``seed_a`` + ticket + host-side policy report). + +The seed-chain host reproduction (:mod:`pearl_gemm.fp16_miner._seed_chain`) is +torch-free and bit-for-bit against the Rust reference. +""" + +from ._host import ( + Fp16JobParams, + Fp16OperandParams, + SeedChain, + WinningTile, + derive_seed_chain, + difficulty_bound, + search_block, +) +from ._seed_chain import ( + commitment_keys, + encode_p_a, + encode_p_b, + encode_pattern, + jackpot_pow_key, + key_a, + key_b, + noise_seeds, + subkey, +) + +__all__ = [ + "Fp16JobParams", + "Fp16OperandParams", + "SeedChain", + "WinningTile", + "commitment_keys", + "derive_seed_chain", + "difficulty_bound", + "encode_p_a", + "encode_p_b", + "encode_pattern", + "jackpot_pow_key", + "key_a", + "key_b", + "noise_seeds", + "search_block", + "subkey", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_host.py new file mode 100644 index 000000000..9e9bee5b5 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_host.py @@ -0,0 +1,346 @@ +"""Host-side FP16 (A100 / ``sm_80``) lottery-search driver. + +The standalone analogue of the FP8 ``_launch_stages``: from a job header and the +full plaintext FP16 operands, derive the seed chain, chain the GA100-validated +FP16 sm_80 kernels, run the full-matrix lottery search, and decode the latched +hit into a verifiable winning tile. + +Data flow (mirrors ``zk-pow/src/api/fp16/plain_proof.rs::parse_proof`` run +*forward* -- the miner holds the plaintext operands, so it commits and derives +rather than parsing a proof): + +1. **Keys.** ``keyA = H_"key-A"(proposed_header)``, ``keyB = + H_"key-B"(ancestor_header)`` (:mod:`._seed_chain`). The miner proposes at depth + 0, so ``ancestor_header == proposed_header`` unless one is supplied. +2. **Commit.** :func:`pearl_gemm.fp16_commit.commit_operand` commits A under + ``keyA`` and B under ``keyB`` -> Merkle ``root_A`` / ``root_B``. +3. **Seeds.** ``pA``/``pB`` are encoded (:func:`._seed_chain.encode_p_a` / + ``encode_p_b``) and ``(seedA, seedB) = noise_seeds(keys, roots, p)`` (B-then-A). + ``pow_key = subkey("…/jackpot", seedA)``. +4. **Noise.** :func:`pearl_gemm.fp16_noise_lines.sample_noise` draws ``E_A`` + (all ``m`` rows), ``E_B`` (all ``n`` cols) and the shared ``F_A``/``F_B`` bases. +5. **Noisy-quantize.** :func:`pearl_gemm.fp16_noisy_quant.noisy_quantize` (via + the ``fp16_pipeline`` padding helper) rebuilds ``A'`` and ``B'``. +6. **Search.** :func:`pearl_gemm.fp16_search.search` scans every ``h x w`` tile of + ``A' @ B'^T`` on-GPU and latches the first (lowest flat index) tile whose + jackpot ticket clears ``nbits``. +7. **Decode.** The search latches on difficulty only (mirroring fp8), but + ``verify_tile`` also requires policy admissibility, so pick the lowest-index + tile clearing BOTH (re-scanning the per-tile tickets only if the difficulty + latch is policy-inadmissible), then slice the opened A rows + ``[tr*h,(tr+1)*h)`` / B rows ``[tc*w,(tc+1)*w)`` and the matching ``E`` noise + factors and return the winning tile. + +The opened rows + sliced noise + ``seedA`` are exactly the witness +``zk-pow/src/api/fp16/verify.rs::verify_tile`` consumes: noisy-quantize is +row-independent, so the tile rebuilt from the slice is bit-identical to the +searched ``A'``/``B'`` tile. Everything is gated to ``sm_80`` via ``require_arch``. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional + +import torch + +from .._utils._arch import Arch, require_arch +from ..fp16_commit import DEFAULT_CHUNK_LEN, commit_operand +from ..fp16_noise_lines import sample_noise +from ..fp16_noisy_quant import noisy_quantize +from ..fp16_pipeline import AxisPattern +from ..fp16_pipeline._host import _rebuild_operand +from ..fp16_policy import PolicyReport, replay_and_evaluate +from ..fp16_search import difficulty_bound, search +from . import _seed_chain + +_SUPPORTED_ARCHS = (Arch.SM80,) + +# The FP16 scheme's fixed device (A100) and noise rank. +_A100_DEVICE_TAG = 0 +NOISE_RANK = 32 + + +@dataclass(frozen=True) +class Fp16OperandParams: + """One operand's committed-tree public parameters (``Fp16OperandParams``).""" + + num_rows: int + pattern: AxisPattern + chunk_len: int = DEFAULT_CHUNK_LEN + + @property + def hash_id(self) -> int: + try: + return _seed_chain.HASH_ID_FROM_CHUNK_LEN[self.chunk_len] + except KeyError: + raise ValueError( + f"chunk_len must be one of {sorted(_seed_chain.HASH_ID_FROM_CHUNK_LEN)}, " + f"got {self.chunk_len}" + ) from None + + +@dataclass(frozen=True) +class Fp16JobParams: + """The public statement for one FP16 search job (mirrors ``Fp16JobParams``). + + ``a`` is the A-side (rows, ``m``) operand, ``b`` the B-side (cols, ``n``). + ``nbits`` is the compact difficulty target the search latches on. + ``ancestor_header`` defaults to the proposed header (depth-0 coincidence: + the miner proposes at depth 0, so ``σ_Δ == σ̂``); supply it only for a + non-trivial ancestor. ``device_tag`` and ``r`` are fixed for A100. + """ + + k: int + a: Fp16OperandParams + b: Fp16OperandParams + nbits: int + r: int = NOISE_RANK + device_tag: int = _A100_DEVICE_TAG + ancestor_header: Optional[bytes] = None + + +@dataclass +class SeedChain: + """The derived host seed chain (all 32-byte, torch-free).""" + + key_a: bytes + key_b: bytes + root_a: bytes + root_b: bytes + p_a: bytes + p_b: bytes + seed_a: bytes + seed_b: bytes + pow_key: bytes + + +@dataclass +class WinningTile: + """The decoded, verifiable winner (or ``found=False`` -- no tile cleared + ``nbits``). + + ``opened_a_rows`` is the ``(h, k)`` and ``opened_b_rows`` the ``(w, k)`` FP16 + (float16) operand strip the tile opened; ``e_a``/``e_b`` are the matching + ``(h, r)`` / ``(w, r)`` sliced ``E`` factors and ``f_a``/``f_b`` the shared + ``(k, r)`` ``F`` bases (all float16 views of the FP16 bit patterns) -- exactly + the witness ``verify.rs::verify_tile`` consumes. ``report`` is the host-side + ``fp16_policy`` admissibility verdict on the latched tile (``None`` when no + winner). ``seed_a`` keys the jackpot ticket. + """ + + found: bool + tile_row: int + tile_col: int + opened_a_rows: Optional[torch.Tensor] + opened_b_rows: Optional[torch.Tensor] + e_a: Optional[torch.Tensor] + f_a: Optional[torch.Tensor] + e_b: Optional[torch.Tensor] + f_b: Optional[torch.Tensor] + seed_a: bytes + ticket: bytes + report: Optional[PolicyReport] + seeds: SeedChain = field(repr=False, default=None) + + +def _as_f16(t: torch.Tensor) -> torch.Tensor: + """View an ``int16``/``uint16`` FP16-bit-pattern tensor as ``float16``.""" + if t.dtype == torch.float16: + return t + if t.dtype in (torch.int16, torch.uint16): + return t.view(torch.float16) + raise ValueError(f"expected float16 / int16 FP16 bit patterns, got {t.dtype}") + + +def _to_f16_rows(rows, num_rows: int, k: int, device: torch.device) -> torch.Tensor: + """Normalize a ``num_rows x k`` FP16 operand (any ``u16`` bit-pattern array or + torch tensor) to a contiguous ``float16`` CUDA tensor on ``device``.""" + if isinstance(rows, torch.Tensor): + t = rows + else: + import numpy as np + + arr = np.ascontiguousarray(rows) + if arr.dtype == np.float16: + t = torch.from_numpy(arr) + else: + t = torch.from_numpy(arr.view(np.uint16).astype(np.int16)) + t = t.reshape(num_rows, k).to(device) + return _as_f16(t).contiguous() + + +def derive_seed_chain( + header_bytes: bytes, + a_rows, + b_rows, + params: Fp16JobParams, + device: torch.device | int | None = None, +) -> SeedChain: + """Commit both operands and derive the full seed chain (steps 1-3). + + ``header_bytes`` is the 76-byte serialized proposed header. ``a_rows`` / + ``b_rows`` are the ``m x k`` / ``n x k`` FP16 operands (``u16`` bit patterns). + """ + dev = torch.device("cuda", device) if isinstance(device, int) else (device or torch.device("cuda")) + require_arch("fp16_miner", dev, *_SUPPORTED_ARCHS) + + ancestor = params.ancestor_header if params.ancestor_header is not None else bytes(header_bytes) + ka, kb = _seed_chain.commitment_keys(bytes(header_bytes), ancestor) + + m, n, k = params.a.num_rows, params.b.num_rows, params.k + a16 = _to_f16_rows(a_rows, m, k, dev) + b16 = _to_f16_rows(b_rows, n, k, dev) + + root_a = commit_operand(a16.view(torch.int16), m, k, ka, params.a.chunk_len, dev) + root_b = commit_operand(b16.view(torch.int16), n, k, kb, params.b.chunk_len, dev) + + p_a = _seed_chain.encode_p_a(k, params.r, params.device_tag, m, params.a.hash_id, params.a.pattern) + p_b = _seed_chain.encode_p_b( + ancestor, k, params.r, params.device_tag, n, params.b.hash_id, params.b.pattern + ) + seed_a, seed_b = _seed_chain.noise_seeds(ka, kb, root_a, root_b, p_a, p_b) + pow_key = _seed_chain.jackpot_pow_key(seed_a) + return SeedChain( + key_a=ka, key_b=kb, root_a=root_a, root_b=root_b, p_a=p_a, p_b=p_b, + seed_a=seed_a, seed_b=seed_b, pow_key=pow_key, + ) + + +def search_block( + header_bytes: bytes, + a_rows, + b_rows, + params: Fp16JobParams, + device: torch.device | int | None = None, +) -> WinningTile: + """Run the full FP16 lottery search for one job on ``sm_80``. + + ``header_bytes`` is the 76-byte serialized proposed header; ``a_rows`` is the + ``m x k`` and ``b_rows`` the ``n x k`` FP16 operand (``u16`` bit patterns or a + float16 tensor). Derives the seed chain, rebuilds ``A'``/``B'``, scans every + ``h x w`` tile, and on the first winner returns a :class:`WinningTile` with the + opened rows, sliced noise, ``seed_a``, ticket and the host-side + :class:`~pearl_gemm.fp16_policy.PolicyReport` admissibility verdict. When no + tile clears ``nbits``, returns ``found=False``. + """ + dev = torch.device("cuda", device) if isinstance(device, int) else (device or torch.device("cuda")) + require_arch("fp16_miner", dev, *_SUPPORTED_ARCHS) + + m, n, k, r = params.a.num_rows, params.b.num_rows, params.k, params.r + rows_pattern, cols_pattern = params.a.pattern, params.b.pattern + h, w = rows_pattern.tile_size(), cols_pattern.tile_size() + if m % h != 0: + raise ValueError(f"m={m} is not a multiple of h={h}") + if n % w != 0: + raise ValueError(f"n={n} is not a multiple of w={w}") + + a16 = _to_f16_rows(a_rows, m, k, dev) + b16 = _to_f16_rows(b_rows, n, k, dev) + + chain = derive_seed_chain(header_bytes, a16, b16, params, dev) + + # 4. Deterministic FP16 noise for ALL rows/cols (E keyed off the GLOBAL + # row/col index, so the slice for any tile is exactly that tile's noise). + noise = sample_noise(chain.seed_a, chain.seed_b, k, r, range(m), range(n), dev) + e_a, f_a = _as_f16(noise.e_a), _as_f16(noise.f_a) + e_b, f_b = _as_f16(noise.e_b), _as_f16(noise.f_b) + + # 5. Rebuild A' and B' (noisy-quantize; row-independent, so the per-tile slice + # below is bit-identical to the Rust verify_tile rebuild from the opening). + built_a = _rebuild_operand(a16, e_a, f_a, r) + built_b = _rebuild_operand(b16, e_b, f_b, r) + + def _no_winner() -> WinningTile: + return WinningTile( + found=False, tile_row=-1, tile_col=-1, + opened_a_rows=None, opened_b_rows=None, + e_a=None, f_a=None, e_b=None, f_b=None, + seed_a=chain.seed_a, ticket=b"", report=None, seeds=chain, + ) + + def _evaluate(tr: int, tc: int) -> PolicyReport: + """Host-side fp16_policy admissibility of tile ``(tr, tc)`` on the A'/B' slices.""" + a_prime_tile = built_a.noised_part[tr * h : (tr + 1) * h].contiguous() + b_prime_tile = built_b.noised_part[tc * w : (tc + 1) * w].contiguous() + _tile, rep = replay_and_evaluate(a_prime_tile, b_prime_tile) + return rep + + # 6. Full-matrix lottery search. The kernel latches the lowest flat-index tile + # clearing ``nbits`` on DIFFICULTY ALONE (mirroring fp8). But ``verify_tile`` + # also requires POLICY admissibility (f_bp >= 0.30, rho >= 1.2), and consensus + # only ever checks the OPENED tile's own difficulty + policy -- it does not pin + # a particular tile index -- so the submittable block is the lowest-index tile + # clearing BOTH. Take the difficulty latch first (the common case: honest + # operands are almost always admissible); only if it fails policy do we + # re-scan the per-tile tickets for the lowest-index tile clearing difficulty + # AND policy. Returning the raw latch when it is inadmissible would hand the + # submitter a tile the verifier rejects, silently missing a valid block. + hit = search(built_a.noised_part, built_b.noised_part, chain.pow_key, params.nbits, + rows_pattern, cols_pattern) + if not hit.found: + return _no_winner() + + tr, tc, ticket = hit.tile_row, hit.tile_col, hit.ticket + report = _evaluate(tr, tc) + if not report.accept: + import numpy as np + + _, tickets = search( + built_a.noised_part, built_b.noised_part, chain.pow_key, params.nbits, + rows_pattern, cols_pattern, collect_tickets=True, + ) + bound = difficulty_bound(params.nbits, int(h), int(w), int(k)) + ntc = n // w + words = tickets.numpy().reshape(-1, 8).astype(np.uint64) + chosen = None + for flat in range(words.shape[0]): + le = sum(int(words[flat, i]) << (32 * i) for i in range(8)) + if le > bound: # does not clear the jackpot difficulty + continue + cand_tr, cand_tc = divmod(flat, ntc) + cand_report = _evaluate(cand_tr, cand_tc) + if cand_report.accept: + ticket = b"".join((int(words[flat, i]) & 0xFFFFFFFF).to_bytes(4, "little") for i in range(8)) + chosen = (cand_tr, cand_tc, cand_report) + break + if chosen is None: + # Difficulty winners exist but none are policy-admissible: no valid block. + return _no_winner() + tr, tc, report = chosen + + # 7. Decode the winning tile into the opening + sliced noise. + # + # Tiling is CONTIGUOUS: the committed A100 patterns have dense tile offsets + # (``P.tile_offsets() == range(P.tile_size())`` with ``total() == tile_size()``), + # so tile ``(tr, tc)`` occupies exactly the global rows ``[tr*h, (tr+1)*h)`` / + # ``[tc*w, (tc+1)*w)``. Those global indices ARE the certificate opening's + # ``row_indices`` -- the cert's ``base + P.tile_offsets()`` with ``base = tr*h`` + # (``tr=tc=0`` is the origin tile). The CPU assembler + # ``miner_base.fp16_block_submission.create_fp16_proof`` opens them from the + # full committed trees, and the verifier's ``parse_proof`` accepts them and + # keys the E noise on them (matching the full-matrix search here). No tile + # base/stride translation is needed, so the GA100-validated kernel math is + # untouched. + opened_a = a16[tr * h : (tr + 1) * h].contiguous() + opened_b = b16[tc * w : (tc + 1) * w].contiguous() + e_a_tile = e_a[tr * h : (tr + 1) * h].contiguous() + e_b_tile = e_b[tc * w : (tc + 1) * w].contiguous() + + return WinningTile( + found=True, tile_row=tr, tile_col=tc, + opened_a_rows=opened_a, opened_b_rows=opened_b, + e_a=e_a_tile, f_a=f_a, e_b=e_b_tile, f_b=f_b, + seed_a=chain.seed_a, ticket=ticket, report=report, seeds=chain, + ) + + +__all__ = [ + "Fp16JobParams", + "Fp16OperandParams", + "SeedChain", + "WinningTile", + "derive_seed_chain", + "difficulty_bound", + "search_block", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_seed_chain.py b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_seed_chain.py new file mode 100644 index 000000000..910006323 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_miner/_seed_chain.py @@ -0,0 +1,172 @@ +"""Torch-free, bit-exact host reproduction of the FP16 scheme's seed chain. + +Reproduces ``zk-pow/src/api/fp16/noise.rs`` + ``plain_proof.rs`` key/seed +derivation on the host, so the miner driver can derive the same jackpot ``pow_key`` +the verifier will re-derive from the certificate -- without parsing a proof (the +miner already holds the plaintext operands and commits them itself): + + keyA = H_"key-A"(proposed_header) (A-side tree key) + keyB = H_"key-B"(ancestor_header) (B-side tree key) + seedB = H_"seed-B"(root_B || keyB || pB) (B then ...) + seedA = H_"seed-A"(root_A || seedB || keyA || pA) (... A) + pow_key = subkey("pearl/v4/FP8/jackpot", seedA) (jackpot ticket key) + +where every ``H_label(msg)`` is a keyed BLAKE3 ``keyed_hash(key=subkey(label), msg)`` +and ``subkey(label, parent) = BLAKE3(label, key=parent)`` (unkeyed BLAKE3 of the +label when ``parent`` is ``None``) -- exactly ``pearl_blake3::blake3_digest`` and +``noise.rs::subkey`` / ``hash_labelled``. + +``pA`` / ``pB`` are the per-side public-parameter encodings +(``Fp16JobParams::encode_p_a`` / ``encode_p_b``), reproduced byte-for-byte here, +including the committed ``AxisPattern`` wire form (``crate::api::layout``). + +Nothing here touches CUDA, so it is importable under any Python and shared by the +standalone sm_80 harness and CI. +""" + +from __future__ import annotations + +import blake3 + +# FP16 transcript labels (``noise.rs``): a distinct domain from the FP8 labels so +# the two schemes never derive the same seed from the same inputs. The jackpot +# label is deliberately the shared FP8/v4 one (``noise.rs``: the jackpot key = +# ``subkey("pearl/v4/FP8/jackpot", seed_a)``). +LABEL_KEY_A = b"pearl/v4/FP16/key-A" +LABEL_KEY_B = b"pearl/v4/FP16/key-B" +LABEL_SEED_A = b"pearl/v4/FP16/seed-A" +LABEL_SEED_B = b"pearl/v4/FP16/seed-B" +LABEL_JACKPOT = b"pearl/v4/FP8/jackpot" + +# ``crate::api::layout``: 6 fixed dim-byte slots, length split at <= 64, trailing +# slots padded with a length-1 ``DimType::None`` (=3) byte. +_PATTERN_NUM_DIMS = 6 +_PATTERN_MAX_DIM_LEN = 64 +_PATTERN_PAD_BYTE = 3 # DimType::None + +# ``HashId`` discriminants (``crate::api::fp8::public_params::HashId``), keyed by +# the Merkle chunk length. +HASH_ID_FROM_CHUNK_LEN = {128: 0, 256: 1, 512: 2, 1024: 3} + + +def subkey(label: bytes, parent: bytes | None = None) -> bytes: + """``blake3_digest(label, parent)`` -- the 32-byte role key. + + Unkeyed BLAKE3 of ``label`` when ``parent`` is ``None``, else keyed BLAKE3 of + ``label`` under the 32-byte ``parent`` key. + """ + if parent is None: + return blake3.blake3(label).digest(length=32) + if len(parent) != 32: + raise ValueError(f"parent key must be 32 bytes, got {len(parent)}") + return blake3.blake3(label, key=parent).digest(length=32) + + +def _hash_labelled(message: bytes, label: bytes) -> bytes: + """``H_label(message)`` = ``keyed_hash(key=subkey(label), message)`` + (``noise.rs::hash_labelled``).""" + return blake3.blake3(message, key=subkey(label)).digest(length=32) + + +def key_a(proposed_header: bytes) -> bytes: + """``keyA = H_"key-A"(proposed_header)`` -- the A-side tree/opening key.""" + return _hash_labelled(proposed_header, LABEL_KEY_A) + + +def key_b(ancestor_header: bytes) -> bytes: + """``keyB = H_"key-B"(ancestor_header)`` -- the B-side tree/opening key.""" + return _hash_labelled(ancestor_header, LABEL_KEY_B) + + +def commitment_keys(proposed_header: bytes, ancestor_header: bytes) -> tuple[bytes, bytes]: + """``(keyA, keyB)`` -- the per-side opening keys (``noise.rs::commitment_keys``).""" + return key_a(proposed_header), key_b(ancestor_header) + + +def noise_seeds( + key_a_bytes: bytes, + key_b_bytes: bytes, + root_a: bytes, + root_b: bytes, + p_a: bytes, + p_b: bytes, +) -> tuple[bytes, bytes]: + """``(seedA, seedB)`` derived B-then-A (``noise.rs::noise_seeds``): + + seedB = H_"seed-B"(root_B || keyB || pB) + seedA = H_"seed-A"(root_A || seedB || keyA || pA) + """ + seed_b = _hash_labelled(root_b + key_b_bytes + p_b, LABEL_SEED_B) + seed_a = _hash_labelled(root_a + seed_b + key_a_bytes + p_a, LABEL_SEED_A) + return seed_a, seed_b + + +def jackpot_pow_key(seed_a: bytes) -> bytes: + """``pow_key = subkey("pearl/v4/FP8/jackpot", seedA)`` -- the key the search + kernel (and ``compute_jackpot_ticket``) folds the tile under.""" + return subkey(LABEL_JACKPOT, seed_a) + + +def encode_pattern(pattern) -> bytes: + """The committed ``AxisPattern`` wire form (``crate::api::layout::encode``): + exactly 6 bytes, one per split dim ``(length - 1) << 2 | type`` (greedy split + at the largest divisor <= 64 of the remaining run), trailing slots padded with + a length-1 ``DimType::None`` byte. ``pattern.dims`` is the canonical + ``(length, dim_type)`` list (lengths >= 2, no adjacent same-type).""" + dim_bytes: list[int] = [] + for length, dim_type in pattern.dims: + rest = int(length) + while rest > 1: + part = None + for d in range(min(_PATTERN_MAX_DIM_LEN, rest), 1, -1): + if rest % d == 0: + part = d + break + if part is None: + raise ValueError( + f"dim length {length} has a prime factor > {_PATTERN_MAX_DIM_LEN} " + "and cannot be serialized" + ) + dim_bytes.append(((part - 1) << 2) | int(dim_type)) + rest //= part + if len(dim_bytes) > _PATTERN_NUM_DIMS: + raise ValueError( + f"pattern needs more than {_PATTERN_NUM_DIMS} dim bytes to serialize" + ) + out = bytearray([_PATTERN_PAD_BYTE] * _PATTERN_NUM_DIMS) + out[: len(dim_bytes)] = bytes(dim_bytes) + return bytes(out) + + +def encode_p_a(k: int, r: int, device_tag: int, m: int, hash_id_a: int, pattern_a) -> bytes: + """``pA = k ‖ r ‖ device ‖ m ‖ hash_id_A ‖ P_A`` + (``Fp16JobParams::encode_p_a``). All integers little-endian u32, tags one byte.""" + return b"".join( + [ + int(k).to_bytes(4, "little"), + int(r).to_bytes(4, "little"), + bytes([int(device_tag) & 0xFF]), + int(m).to_bytes(4, "little"), + bytes([int(hash_id_a) & 0xFF]), + encode_pattern(pattern_a), + ] + ) + + +def encode_p_b( + ancestor_header: bytes, k: int, r: int, device_tag: int, n: int, hash_id_b: int, pattern_b +) -> bytes: + """``pB = σ_Δ ‖ k ‖ r ‖ device ‖ n ‖ hash_id_B ‖ P_B`` + (``Fp16JobParams::encode_p_b``): the ancestor header leads, then the same + layout as :func:`encode_p_a` for the B side.""" + return b"".join( + [ + bytes(ancestor_header), + int(k).to_bytes(4, "little"), + int(r).to_bytes(4, "little"), + bytes([int(device_tag) & 0xFF]), + int(n).to_bytes(4, "little"), + bytes([int(hash_id_b) & 0xFF]), + encode_pattern(pattern_b), + ] + ) diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/__init__.py new file mode 100644 index 000000000..fb36755a9 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/__init__.py @@ -0,0 +1,32 @@ +"""Bit-exact A100 (``sm_80``) FP16 deterministic noise-line generation for the +FP16 proof-of-useful-work scheme. + +Reproduces ``zk-pow/src/api/fp16/noise.rs``'s ``sample_line`` / ``sample_noise`` +bit-for-bit on real GA100 silicon: per-line keyed-BLAKE3 XOF, exact integer +``isqrt`` L2 normalization to the shared constant norm, and RNE rounding to FP16. +Produces the ``E`` ``(rows x r)`` and ``F`` ``(k x r)`` factors as ``u16``. +""" + +from ._host import ( + FACTOR_E, + FACTOR_F, + LABEL_NOISE_LINE, + SIDE_A, + SIDE_B, + Noise16, + line_key, + noise_lines, + sample_noise, +) + +__all__ = [ + "FACTOR_E", + "FACTOR_F", + "LABEL_NOISE_LINE", + "SIDE_A", + "SIDE_B", + "Noise16", + "line_key", + "noise_lines", + "sample_noise", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_host.py new file mode 100644 index 000000000..e04fe5baf --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_host.py @@ -0,0 +1,148 @@ +"""Host launch for the bit-exact A100 (``sm_80``) FP16 noise-line generation. + +Reproduces ``zk-pow/src/api/fp16/noise.rs``'s ``sample_line`` / ``sample_noise`` +on real GA100 silicon, bit-for-bit against the verifier. Each line is a keyed +BLAKE3 XOF draw normalized to the shared constant L2 norm and cast to FP16: + +1. ``line_key = subkey(LABEL_NOISE_LINE, seed)`` -- keyed BLAKE3 of the 24-byte + label ``pearl/v4/FP16/noise-line`` under the 32-byte ``seed``, computed on the + host with the ``blake3`` crate-equivalent package (same keyed semantics as + ``blake3_digest(label, Some(seed))``). +2. For each line index: keyed-BLAKE3-XOF the 64-byte address material + ``side | factor | line(u32 LE)`` under ``line_key`` to ``rank`` bytes, decode + to signed integers, L2-normalize with the exact integer ``isqrt`` + one-BF16 + division recipe, and round each entry to FP16 (``u16``). + +The BLAKE3 compression + normalization run in a small hand-written CUDA +extension compiled with ``nvcc -arch=sm_80`` (loaded through +``torch.utils.cpp_extension``), exactly like ``fp16_gemm`` / ``fp16_noisy_quant``. +The ``line_key`` derivation (one keyed BLAKE3 per seed, not per line) is done on +the host and passed to the kernel as 8 little-endian ``u32`` words, mirroring how +the FP8 ``noise_lines`` kernel takes its side noise-line key. +""" + +from __future__ import annotations + +import functools +import os +from dataclasses import dataclass + +import blake3 +import torch + +from .._utils._arch import Arch, require_arch + +_SUPPORTED_ARCHS = (Arch.SM80,) + +# The FP16 noise-line transcript label (``LABEL_NOISE_LINE`` in the reference). +LABEL_NOISE_LINE = b"pearl/v4/FP16/noise-line" + +# Address discriminants (committed wire bytes), matching ``Side`` / ``NoiseFactor``. +SIDE_A = 0 +SIDE_B = 1 +FACTOR_E = 0 +FACTOR_F = 1 + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_noise_lines_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +def line_key(seed: bytes) -> bytes: + """``subkey(LABEL_NOISE_LINE, seed)`` -- the per-seed noise-line key. + + Keyed BLAKE3 of the label under the 32-byte ``seed``, identical to the + reference's ``blake3_digest(LABEL_NOISE_LINE, Some(seed))``. + """ + if len(seed) != 32: + raise ValueError(f"seed must be 32 bytes, got {len(seed)}") + return blake3.blake3(LABEL_NOISE_LINE, key=seed).digest(length=32) + + +def _line_key_words(seed: bytes, device: torch.device) -> torch.Tensor: + """The 8 little-endian ``u32`` words of :func:`line_key`, on ``device``.""" + key = line_key(seed) + words = [int.from_bytes(key[4 * i : 4 * i + 4], "little") for i in range(8)] + # int32 view of the u32 words (two's-complement reinterpretation is fine; the + # kernel reads them as raw 32-bit words). + signed = [w - (1 << 32) if w >= (1 << 31) else w for w in words] + return torch.tensor(signed, dtype=torch.int32, device=device) + + +def _indices_tensor(indices, device: torch.device) -> torch.Tensor: + t = torch.as_tensor(indices, dtype=torch.int32, device=device) + if t.ndim != 1: + raise ValueError("indices must be 1D") + return t.contiguous() + + +def noise_lines( + seed: bytes, + side: int, + factor: int, + indices, + r: int, + device: torch.device | int | None = None, +) -> torch.Tensor: + """Draw normalized FP16 noise lines for ``indices`` under ``seed``. + + Returns a ``(len(indices), r)`` ``int16`` tensor of FP16 bit patterns (view + as ``uint16``), each row the keyed-BLAKE3 line for ``(side, factor, index)``, + bit-exact to ``sample_line(subkey(LABEL_NOISE_LINE, seed), side, factor, + index, r)``. + """ + dev = torch.device("cuda", device) if isinstance(device, int) else (device or torch.device("cuda")) + require_arch("fp16_noise_lines", dev, *_SUPPORTED_ARCHS) + key = _line_key_words(seed, dev) + idx = _indices_tensor(indices, dev) + return _extension().fp16_noise_lines(key, int(side), int(factor), idx, int(r)) + + +@dataclass +class Noise16: + """Both operands' FP16 noise factors (mirrors the Rust ``Noise16``). + + ``e_a``/``e_b`` are ``(|a_rows|, r)`` / ``(|b_cols|, r)``; ``f_a``/``f_b`` are + ``(k, r)``. All are ``int16`` FP16 bit patterns (view as ``uint16``). + """ + + e_a: torch.Tensor + f_a: torch.Tensor + e_b: torch.Tensor + f_b: torch.Tensor + + +def sample_noise( + seed_a: bytes, + seed_b: bytes, + k: int, + r: int, + a_rows, + b_cols, + device: torch.device | int | None = None, +) -> Noise16: + """Draw the four FP16 noise factors for one tile, matching ``sample_noise``. + + ``E_A`` keys off ``seed_a`` (``Side::A``, ``NoiseFactor::E``, per ``a_rows``); + ``E_B``, ``F_A``, ``F_B`` all key off ``seed_b`` with distinct ``Side`` / + ``NoiseFactor`` addresses (``F`` bases are the shared ``0..k`` basis). The + layout is the reference's: ``E`` row-major ``(rows x r)``, ``F`` row-major + ``(k x r)``. + """ + dev = torch.device("cuda", device) if isinstance(device, int) else (device or torch.device("cuda")) + f_lines = list(range(k)) + e_a = noise_lines(seed_a, SIDE_A, FACTOR_E, a_rows, r, dev) + e_b = noise_lines(seed_b, SIDE_B, FACTOR_E, b_cols, r, dev) + f_a = noise_lines(seed_b, SIDE_A, FACTOR_F, f_lines, r, dev) + f_b = noise_lines(seed_b, SIDE_B, FACTOR_F, f_lines, r, dev) + return Noise16(e_a=e_a, f_a=f_a, e_b=e_b, f_b=f_b) diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_kernel_sm80.cu new file mode 100644 index 000000000..eba631196 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noise_lines/_kernel_sm80.cu @@ -0,0 +1,224 @@ +// Bit-exact A100 (sm_80) FP16 deterministic noise-line generation. +// +// Reproduces the FP16 scheme verifier's keyed-BLAKE3 noise lines +// (zk-pow/src/api/fp16/noise.rs) element-for-element. One line is: +// +// key = subkey(LABEL_NOISE_LINE, seed) (host-derived keyed BLAKE3) +// material = [side:u8, factor:u8, line:u32 LE] zero-padded to 64 bytes +// bytes = keyed-BLAKE3-XOF(key, material)[0 .. rank] +// x_i = sign * magnitude, sign = 1-2*(b>>7), magnitude = (b&0x7F)+1 +// norm = floor(||x||_2 * 32) via EXACT integer isqrt of sumsq*32^2 +// scale = bf16(256*32) / bf16(norm) (one BF16 division) +// entry_i = fp16( bf16( bf16(x_i) * scale ) ) (RNE to FP16, u16) +// +// The ONLY difference from the FP8 recipe is the final cast target: FP16 (u16) +// rather than e4m3. Every BF16 op decodes exactly to f32, runs in f32 and +// rounds back RNE; the final cast is RNE-to-FP16 (__float2half_rn). The line +// key is derived on the host (blake3 keyed hash of the 24-byte label under the +// seed) and passed in as 8 little-endian u32 words, exactly as the FP8 +// noise_lines kernel takes its side noise-line key. +// +// Thread mapping: one thread per line (count lines, each `rank` entries). The +// line index is indices[tid] (arbitrary global E rows/cols, or 0..k for F). + +#include +#include + +// ---- BF16 helpers (bit-exact to crate::api::fp8::{compute,dtype}) ---- + +__device__ __forceinline__ float bf16_to_f32(unsigned short bits) { + return __uint_as_float((unsigned int)bits << 16); +} + +// f32 -> BF16 round-to-nearest-ties-to-even (dtype::f32_to_bf16). Works on the +// raw bit pattern, so the sign rides through unchanged (matches the reference). +__device__ __forceinline__ unsigned short f32_to_bf16(float x) { + unsigned int bits = __float_as_uint(x); + unsigned int round_bit = (bits >> 16) & 1u; + return (unsigned short)((bits + 0x7FFFu + round_bit) >> 16); +} + +__device__ __forceinline__ unsigned short bf16_mul(unsigned short a, unsigned short b) { + return f32_to_bf16(bf16_to_f32(a) * bf16_to_f32(b)); +} + +__device__ __forceinline__ unsigned short bf16_div(unsigned short a, unsigned short b) { + return f32_to_bf16(bf16_to_f32(a) / bf16_to_f32(b)); +} + +// ---- BLAKE3 keyed single-block XOF (standard BLAKE3, bit-identical to the +// blake3 crate the reference hashes with) ---- + +__constant__ unsigned int BLAKE3_IV[8] = { + 0x6A09E667u, 0xBB67AE85u, 0x3C6EF372u, 0xA54FF53Au, + 0x510E527Fu, 0x9B05688Cu, 0x1F83D9ABu, 0x5BE0CD19u}; + +// Flags of a one-shot (single 64-byte block) keyed BLAKE3 hash: +// CHUNK_START | CHUNK_END | ROOT | KEYED_HASH = 1 | 2 | 8 | 16 = 27. +#define BLAKE3_SINGLE_KEYED_FLAGS 27u + +__device__ __forceinline__ unsigned int rotr32(unsigned int x, unsigned int n) { + return (x >> n) | (x << (32u - n)); +} + +// One BLAKE3 compression of a single 64-byte message block `m` under chaining +// value `cv`, for output-block counter `counter_lo` (hi word always 0 for our +// message sizes). Produces the full 16-word output (XOF): out[0..8] = +// state[0..8] ^ state[8..16]; out[8..16] = state[8..16] ^ cv[0..8]. +__device__ void blake3_compress_xof(const unsigned int cv[8], const unsigned int m[16], + unsigned int counter_lo, unsigned int flags, + unsigned int out[16]) { + unsigned int s[16]; +#pragma unroll + for (int i = 0; i < 8; ++i) s[i] = cv[i]; + s[8] = BLAKE3_IV[0]; + s[9] = BLAKE3_IV[1]; + s[10] = BLAKE3_IV[2]; + s[11] = BLAKE3_IV[3]; + s[12] = counter_lo; + s[13] = 0u; + s[14] = 64u; // block_len (always a full 64-byte block here) + s[15] = flags; + + unsigned int v[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = m[i]; + + // The fixed BLAKE3 message permutation. + const int PERM[16] = {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}; + +#define G(a, b, c, d, x, y) \ + s[a] = s[a] + s[b] + (x); \ + s[d] = rotr32(s[d] ^ s[a], 16); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 12); \ + s[a] = s[a] + s[b] + (y); \ + s[d] = rotr32(s[d] ^ s[a], 8); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 7); + + for (int round = 0; round < 7; ++round) { + G(0, 4, 8, 12, v[0], v[1]); + G(1, 5, 9, 13, v[2], v[3]); + G(2, 6, 10, 14, v[4], v[5]); + G(3, 7, 11, 15, v[6], v[7]); + G(0, 5, 10, 15, v[8], v[9]); + G(1, 6, 11, 12, v[10], v[11]); + G(2, 7, 8, 13, v[12], v[13]); + G(3, 4, 9, 14, v[14], v[15]); + if (round < 6) { + unsigned int t[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) t[i] = v[PERM[i]]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = t[i]; + } + } +#undef G + +#pragma unroll + for (int i = 0; i < 8; ++i) { + out[i] = s[i] ^ s[i + 8]; + out[i + 8] = s[i + 8] ^ cv[i]; + } +} + +// Exact floor integer sqrt of a u64. +__device__ __forceinline__ unsigned long long isqrt_u64(unsigned long long v) { + if (v == 0ull) return 0ull; + unsigned long long c = (unsigned long long)sqrt((double)v); + // Clamp either side of the double rounding to the exact floor. + while (c > 0ull && c * c > v) --c; + while ((c + 1ull) * (c + 1ull) <= v) ++c; + return c; +} + +// ---- Kernel: one keyed-BLAKE3 noise line per thread ---- + +__global__ void fp16_noise_lines_kernel(const unsigned int* __restrict__ line_key, + unsigned char side, unsigned char factor, + const int* __restrict__ indices, int count, int rank, + unsigned short* __restrict__ out) { + int tid = blockIdx.x * blockDim.x + threadIdx.x; + if (tid >= count) return; + + unsigned int cv[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) cv[i] = line_key[i]; + + unsigned int line = (unsigned int)indices[tid]; + unsigned int m[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) m[i] = 0u; + // material = side | factor<<8 | line(u32 LE), zero-padded to one block. + m[0] = (unsigned int)side | ((unsigned int)factor << 8) | ((line & 0xFFFFu) << 16); + m[1] = line >> 16; + + // Keyed-BLAKE3-XOF `rank` bytes (64 per output block). + // rank is small (protocol r = 32); support arbitrary rank via the counter. + unsigned long long sumsq = 0ull; + unsigned char bytes[256]; // rank well below this in every use + for (int off = 0; off < rank; off += 64) { + unsigned int w[16]; + blake3_compress_xof(cv, m, (unsigned int)(off / 64), BLAKE3_SINGLE_KEYED_FLAGS, w); +#pragma unroll + for (int b = 0; b < 64; ++b) { + int idx = off + b; + if (idx < rank) bytes[idx] = (unsigned char)((w[b >> 2] >> (8 * (b & 3))) & 0xFFu); + } + } + for (int i = 0; i < rank; ++i) { + unsigned int mag = (unsigned int)(bytes[i] & 0x7F) + 1u; + sumsq += (unsigned long long)mag * (unsigned long long)mag; + } + + unsigned long long norm_scaled = isqrt_u64(sumsq * 1024ull); // INT_SQRT_PREC^2 = 1024 + unsigned short numer = f32_to_bf16(8192.0f); // NOISE_TARGET_NORM * 32 + unsigned short denom = f32_to_bf16((float)norm_scaled); + unsigned short scale_bf = bf16_div(numer, denom); + float scale_f = bf16_to_f32(scale_bf); + + unsigned short* line_out = out + (long)tid * rank; + for (int i = 0; i < rank; ++i) { + unsigned char b = bytes[i]; + int sign = 1 - 2 * (int)(b >> 7); + int mag = (int)(b & 0x7F) + 1; + float xi = (float)(sign * mag); // |xi| <= 128, exact in bf16 and f32 + unsigned short prod_bf = f32_to_bf16(xi * scale_f); + line_out[i] = __half_as_ushort(__float2half_rn(bf16_to_f32(prod_bf))); + } +} + +// ---- Host launcher ---- + +torch::Tensor fp16_noise_lines(torch::Tensor line_key, long side, long factor, + torch::Tensor indices, long rank) { + TORCH_CHECK(line_key.is_cuda() && line_key.scalar_type() == torch::kInt32, + "line_key must be an int32 CUDA tensor of 8 words"); + TORCH_CHECK(line_key.numel() == 8, "line_key must have 8 u32 words (32 bytes)"); + TORCH_CHECK(indices.is_cuda() && indices.scalar_type() == torch::kInt32, + "indices must be an int32 CUDA tensor"); + TORCH_CHECK(rank > 0 && rank <= 256, "rank must be in 1..=256"); + line_key = line_key.contiguous(); + indices = indices.contiguous(); + int count = (int)indices.numel(); + + auto opts = torch::dtype(torch::kInt16).device(line_key.device()); + auto out = torch::empty({count, (long)rank}, opts); + if (count == 0) return out; + + int threads = 128; + int blocks = (count + threads - 1) / threads; + fp16_noise_lines_kernel<<>>( + (const unsigned int*)line_key.data_ptr(), (unsigned char)side, (unsigned char)factor, + (const int*)indices.data_ptr(), count, (int)rank, (unsigned short*)out.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_noise_lines launch failed"); + return out; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fp16_noise_lines", &fp16_noise_lines, + "A100 sm_80 keyed-BLAKE3 FP16 noise-line generation (u16 E/F factors)", + pybind11::arg("line_key"), pybind11::arg("side"), pybind11::arg("factor"), + pybind11::arg("indices"), pybind11::arg("rank")); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/__init__.py new file mode 100644 index 000000000..62c1c3feb --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/__init__.py @@ -0,0 +1,17 @@ +"""Bit-exact A100 (``sm_80``) FP16 fused noisy quantization for the FP16 +proof-of-useful-work scheme. + +Reproduces ``zk-pow/src/api/fp16/quantization.rs``'s ``noisy_quantize`` +bit-for-bit on real GA100 tensor cores: per-row norms + BF16 scale derivation and +the fused ``alpha*X + beta*(E@F^T)`` noised quantize, with the noise matmul on the +committed :func:`pearl_gemm.fp16_gemm.fp16_gemm_a100` datapath. +""" + +from ._host import ( + BuiltRows16, + noised_elementwise, + noisy_quantize, + row_scales, +) + +__all__ = ["BuiltRows16", "noised_elementwise", "noisy_quantize", "row_scales"] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_host.py new file mode 100644 index 000000000..c5dad2ca2 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_host.py @@ -0,0 +1,123 @@ +"""Host launch for the bit-exact A100 (``sm_80``) FP16 fused noisy quantization. + +Reproduces ``zk-pow/src/api/fp16/quantization.rs``'s ``noisy_quantize`` on real +GA100 silicon, bit-for-bit against the verifier. The pipeline is: + +1. ``N = E @ F^T`` on the committed A100 FP16 datapath -- the same + :func:`pearl_gemm.fp16_gemm.fp16_gemm_a100` kernel the verifier replays. With + ``e`` ``(num_rows, r)`` and ``f`` ``(k, r)`` (both fp16), ``fp16_gemm_a100(e, + f)`` returns the ``(num_rows, k)`` f32 tile ``N[i, j] = sum_t e[i,t] f[j,t]``, + matching ``a100_matmul(e, f, None, num_rows, k, r)`` exactly. +2. Per-row ``row_norms`` (sequential-f32 ``sumsq``, grid-rounded BF16 ``l2``, + BF16 ``linf``), floored to ``2^-32``, then ``derive_row_scales`` in BF16. +3. The fused elementwise ``noised = fma_f32(alpha*x, beta*N)`` -> clamp +-65504 + -> RNE-to-FP16. + +The two bespoke passes are a small hand-written CUDA extension compiled with +``nvcc -arch=sm_80`` (loaded through ``torch.utils.cpp_extension``), exactly like +``fp16_gemm``. All BF16/FP16 rounding is replicated bit-for-bit from the Rust +helpers; see ``_kernel_sm80.cu``. +""" + +from __future__ import annotations + +import functools +import os +from dataclasses import dataclass + +import torch + +from .._utils._arch import Arch, require_arch +from ..fp16_gemm import fp16_gemm_a100 + +_SUPPORTED_ARCHS = (Arch.SM80,) + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_noisy_quant_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +@dataclass +class BuiltRows16: + """The rebuilt FP16 operand plus per-row scales (mirrors the Rust struct). + + ``noised_part`` is ``(num_rows, k)`` float16; ``alpha``, ``beta``, ``l2`` are + ``(num_rows,)`` int16 tensors carrying BF16 bit patterns (view as uint16). + """ + + noised_part: torch.Tensor + alpha: torch.Tensor + beta: torch.Tensor + l2: torch.Tensor + + +def row_scales(rows: torch.Tensor, r: int) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Per-row ``(alpha, beta, l2)`` BF16 bit patterns for an ``(num_rows, k)`` + FP16 operand, bit-exact to ``row_norms`` + flooring + ``derive_row_scales``. + + Returns three ``(num_rows,)`` int16 tensors (BF16 bits; ``.view(torch.uint16)`` + or ``numpy.view(uint16)`` to read the patterns). + """ + if rows.ndim != 2 or rows.dtype != torch.float16: + raise ValueError("rows must be a 2D float16 tensor") + require_arch("fp16_row_scales", rows.device, *_SUPPORTED_ARCHS) + alpha, beta, l2 = _extension().fp16_row_scales(rows.contiguous(), int(r)) + return alpha, beta, l2 + + +def noised_elementwise( + rows: torch.Tensor, noise: torch.Tensor, alpha: torch.Tensor, beta: torch.Tensor +) -> torch.Tensor: + """Fused ``RNE_fp16(clamp(fma_f32(alpha*rows, beta*noise)))``. + + ``noise`` is the ``(num_rows, k)`` f32 ``E@F^T`` tile; ``alpha``/``beta`` are + the per-row int16 BF16 scales from :func:`row_scales`. Returns ``(num_rows, + k)`` float16. + """ + require_arch("fp16_noised_elementwise", rows.device, *_SUPPORTED_ARCHS) + return _extension().fp16_noised_elementwise( + rows.contiguous(), noise.contiguous(), alpha, beta + ) + + +def noisy_quantize( + rows: torch.Tensor, e: torch.Tensor, f: torch.Tensor, r: int +) -> BuiltRows16: + """Fused per-row noisy quantization of an FP16 operand (sm_80). + + ``rows`` is ``(num_rows, k)`` float16; ``e`` is ``(num_rows, r)`` and ``f`` is + ``(k, r)`` float16 noise lines, so ``N = E @ F^T`` is ``(num_rows, k)`` -- the + noise is built on the committed ``fp16_gemm_a100`` datapath here, exactly as + the reference's ``a100_matmul(e, f, None, num_rows, k, r)``. Returns the + noised FP16 operand and the per-row BF16 scales as a :class:`BuiltRows16`. + + Note the ``fp16_gemm_a100`` tile granularity applies to the noise matmul: + ``num_rows % 16 == 0``, ``k % 8 == 0``, ``r % 16 == 0``. + """ + if rows.ndim != 2 or rows.dtype != torch.float16: + raise ValueError("rows must be a 2D float16 tensor") + if e.ndim != 2 or f.ndim != 2 or e.dtype != torch.float16 or f.dtype != torch.float16: + raise ValueError("e and f must be 2D float16 tensors") + num_rows, k = rows.shape + if e.shape[0] != num_rows or e.shape[1] != r: + raise ValueError(f"e must be (num_rows={num_rows}, r={r}), got {tuple(e.shape)}") + if f.shape[0] != k or f.shape[1] != r: + raise ValueError(f"f must be (k={k}, r={r}), got {tuple(f.shape)}") + require_arch("fp16_noisy_quantize", rows.device, *_SUPPORTED_ARCHS) + + # N = E @ F^T on the committed A100 FP16 datapath (bit-exact to a100_matmul). + noise = fp16_gemm_a100(e.contiguous(), f.contiguous()) # (num_rows, k) f32 + + alpha, beta, l2 = row_scales(rows, r) + noised_part = noised_elementwise(rows, noise, alpha, beta) + return BuiltRows16(noised_part=noised_part, alpha=alpha, beta=beta, l2=l2) diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_kernel_sm80.cu new file mode 100644 index 000000000..79dad5885 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_noisy_quant/_kernel_sm80.cu @@ -0,0 +1,215 @@ +// Bit-exact A100 (sm_80) FP16 fused noisy quantization. +// +// Reproduces the FP16 scheme verifier's per-row fused noisy quantize +// (zk-pow/src/api/fp16/quantization.rs) element-for-element: +// +// row_norms(row): sumsq = sequential-f32 sum of fp16_to_f32(x)^2 +// l2 = grid4(RNE_bf16(sqrtf(sumsq / k))) +// linf = RNE_bf16(max |x|) +// floor: l2, linf = bf16_max(., f32_to_bf16(2^-32)) +// derive_row_scales: noised_bound = bf16_fma(delta_r, l2, linf) +// alpha = bf16_div(MAX_FP16, noised_bound) +// beta = bf16_mul(bf16_mul(alpha, l2), delta_over_std) +// elementwise: noised = fmaf(alpha_f32, fp16_to_f32(x), beta_f32 * N) +// clamped = clamp(noised, -65504, 65504) +// code = RNE_fp16(clamped) +// +// The noise tile N = E @ F^T is produced by the committed fp16_gemm_a100 kernel +// (passed in as an (num_rows x k) f32 tensor) and consumed here as N[i*k + j]. +// +// Every BF16 op is done in f32 (operands decoded exactly) and rounded back to +// BF16 with the reference's exact RNE; the elementwise FMA is a single-rounding +// f32 fmaf; the final cast is RNE-to-FP16. FP32 ops that the reference rounds +// separately use __f*_rn intrinsics so nvcc never contracts a mul+add into an +// fma and changes a bit. + +#include +#include +#include + +// ---- BF16 helpers (bit-exact to crate::api::fp8::{compute,dtype}) ---- + +__device__ __forceinline__ float bf16_to_f32(unsigned short bits) { + return __uint_as_float((unsigned int)bits << 16); +} + +// f32 -> BF16 round-to-nearest-ties-to-even (dtype::f32_to_bf16). +__device__ __forceinline__ unsigned short f32_to_bf16(float x) { + unsigned int bits = __float_as_uint(x); + unsigned int round_bit = (bits >> 16) & 1u; + return (unsigned short)((bits + 0x7FFFu + round_bit) >> 16); +} + +__device__ __forceinline__ unsigned short bf16_mul(unsigned short a, unsigned short b) { + return f32_to_bf16(bf16_to_f32(a) * bf16_to_f32(b)); +} + +__device__ __forceinline__ unsigned short bf16_div(unsigned short a, unsigned short b) { + return f32_to_bf16(bf16_to_f32(a) / bf16_to_f32(b)); +} + +// torch.maximum: exact, returns one of the inputs (compute::bf16_max). +__device__ __forceinline__ unsigned short bf16_max(unsigned short a, unsigned short b) { + return (bf16_to_f32(a) >= bf16_to_f32(b)) ? a : b; +} + +// Single-rounding FMA a*b + c in BF16 (compute::bf16_fma): TwoSum in f64 + +// round-to-odd fixup, then f32 -> BF16 RNE. BF16 operands make a*b exact in f64. +__device__ __forceinline__ unsigned short bf16_fma(unsigned short a, unsigned short b, + unsigned short c) { + double a64 = (double)bf16_to_f32(a); + double b64 = (double)bf16_to_f32(b); + double c64 = (double)bf16_to_f32(c); + double p = a64 * b64; // exact + double s = p + c64; // f64 RNE of the exact sum x = a*b + c + double t = s - c64; + double r = (p - t) + (c64 - (s - t)); // TwoSum residual: x - s, exact + float s32 = (float)s; + double err = (s - (double)s32) + r; // sign(x - s32); nonzero iff x != s32 + bool fix = (err != 0.0) && ((__float_as_uint(s32) & 1u) == 0u) && isfinite(s32); + float rounded = s32; + if (fix) { + rounded = (err > 0.0) ? nextafterf(s32, CUDART_INF_F) + : nextafterf(s32, -CUDART_INF_F); + } + return f32_to_bf16(rounded); +} + +// prequant::round_l2_to_grid: round to nearest multiple of 4 ulps, ties up. +__device__ __forceinline__ unsigned short round_l2_to_grid(unsigned short l2) { + return (unsigned short)((l2 + 2u) & ~3u); +} + +__constant__ float MAX_FP16_F = 65504.0f; + +// ---- Kernel 1: per-row norms + scale derivation (one thread per row) ---- +// +// delta_r, delta_over_std, max_fp16_bf, floor_bf are host-precomputed BF16 bits +// (identical f64 path to the reference's delta_r_bf16 / delta_over_std_bf16). + +__global__ void fp16_row_scales_kernel(const __half* __restrict__ rows, int num_rows, int k, + unsigned short delta_r, unsigned short delta_over_std, + unsigned short max_fp16_bf, unsigned short floor_bf, + unsigned short* __restrict__ alpha_out, + unsigned short* __restrict__ beta_out, + unsigned short* __restrict__ l2_out) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i >= num_rows) return; + + const __half* row = rows + (long)i * k; + float sumsq = 0.0f; + float absmax = 0.0f; + for (int j = 0; j < k; ++j) { + float v = __half2float(row[j]); + // Sequential f32 fold; forbid fma-contraction so mul and add round apart. + sumsq = __fadd_rn(sumsq, __fmul_rn(v, v)); + absmax = fmaxf(absmax, fabsf(v)); + } + float rms = __fsqrt_rn(__fdiv_rn(sumsq, (float)k)); + unsigned short l2 = round_l2_to_grid(f32_to_bf16(rms)); + unsigned short linf = f32_to_bf16(absmax); + + l2 = bf16_max(l2, floor_bf); + linf = bf16_max(linf, floor_bf); + + unsigned short noised_bound = bf16_fma(delta_r, l2, linf); + unsigned short alpha = bf16_div(max_fp16_bf, noised_bound); + unsigned short beta = bf16_mul(bf16_mul(alpha, l2), delta_over_std); + + alpha_out[i] = alpha; + beta_out[i] = beta; + l2_out[i] = l2; +} + +// ---- Kernel 2: fused elementwise noised quantize (one thread per element) ---- + +__global__ void fp16_noised_elementwise_kernel(const __half* __restrict__ rows, + const float* __restrict__ noise, + const unsigned short* __restrict__ alpha, + const unsigned short* __restrict__ beta, + int num_rows, int k, __half* __restrict__ out) { + long idx = (long)blockIdx.x * blockDim.x + threadIdx.x; + long total = (long)num_rows * k; + if (idx >= total) return; + int i = (int)(idx / k); + + float af = bf16_to_f32(alpha[i]); + float bf = bf16_to_f32(beta[i]); + float x = __half2float(rows[idx]); + // beta*N rounded first (f32), then a single-rounding fmaf = Rust mul_add. + float bn = __fmul_rn(bf, noise[idx]); + float noised = fmaf(af, x, bn); + float clamped = noised < -MAX_FP16_F ? -MAX_FP16_F : (noised > MAX_FP16_F ? MAX_FP16_F : noised); + out[idx] = __float2half_rn(clamped); +} + +// ---- Host launchers ---- + +// delta_r_bf16 / delta_over_std_bf16: computed on host with the same f64 path. +static unsigned short host_f32_to_bf16(float x) { + unsigned int bits; + memcpy(&bits, &x, sizeof(bits)); + unsigned int round_bit = (bits >> 16) & 1u; + return (unsigned short)((bits + 0x7FFFu + round_bit) >> 16); +} + +std::vector fp16_row_scales(torch::Tensor rows, long r) { + TORCH_CHECK(rows.is_cuda() && rows.scalar_type() == torch::kFloat16, "rows must be fp16 CUDA"); + TORCH_CHECK(rows.dim() == 2 && rows.is_contiguous(), "rows must be 2D contiguous"); + int num_rows = rows.size(0), k = rows.size(1); + + const double NOISE_TARGET_NORM = 256.0; + const double DELTA = 0.5; + double sqrt_r = sqrt((double)r); + unsigned short delta_r = host_f32_to_bf16((float)(DELTA * sqrt_r)); + unsigned short delta_over_std = + host_f32_to_bf16((float)(DELTA * sqrt_r / (NOISE_TARGET_NORM * NOISE_TARGET_NORM))); + unsigned short max_fp16_bf = host_f32_to_bf16(65504.0f); + unsigned short floor_bf = host_f32_to_bf16(1.0f / 4294967296.0f); // 2^-32 + + auto opts = torch::dtype(torch::kInt16).device(rows.device()); + auto alpha = torch::empty({num_rows}, opts); + auto beta = torch::empty({num_rows}, opts); + auto l2 = torch::empty({num_rows}, opts); + + int threads = 128; + int blocks = (num_rows + threads - 1) / threads; + fp16_row_scales_kernel<<>>( + (const __half*)rows.data_ptr(), num_rows, k, delta_r, delta_over_std, max_fp16_bf, floor_bf, + (unsigned short*)alpha.data_ptr(), (unsigned short*)beta.data_ptr(), + (unsigned short*)l2.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_row_scales launch failed"); + return {alpha, beta, l2}; +} + +torch::Tensor fp16_noised_elementwise(torch::Tensor rows, torch::Tensor noise, torch::Tensor alpha, + torch::Tensor beta) { + TORCH_CHECK(rows.is_cuda() && rows.scalar_type() == torch::kFloat16, "rows must be fp16 CUDA"); + TORCH_CHECK(noise.is_cuda() && noise.scalar_type() == torch::kFloat32, "noise must be f32 CUDA"); + TORCH_CHECK(rows.dim() == 2 && rows.is_contiguous(), "rows must be 2D contiguous"); + TORCH_CHECK(noise.sizes() == rows.sizes() && noise.is_contiguous(), "noise must match rows"); + int num_rows = rows.size(0), k = rows.size(1); + TORCH_CHECK(alpha.numel() == num_rows && beta.numel() == num_rows, "scales must be per-row"); + alpha = alpha.contiguous(); + beta = beta.contiguous(); + + auto out = torch::empty({num_rows, k}, torch::dtype(torch::kFloat16).device(rows.device())); + long total = (long)num_rows * k; + int threads = 256; + long blocks = (total + threads - 1) / threads; + fp16_noised_elementwise_kernel<<<(unsigned)blocks, threads>>>( + (const __half*)rows.data_ptr(), (const float*)noise.data_ptr(), + (const unsigned short*)alpha.data_ptr(), (const unsigned short*)beta.data_ptr(), num_rows, k, + (__half*)out.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_noised_elementwise launch failed"); + return out; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fp16_row_scales", &fp16_row_scales, + "A100 sm_80 per-row FP16 noisy-quant norms+scales (bf16 alpha,beta,l2)", + pybind11::arg("rows"), pybind11::arg("r")); + m.def("fp16_noised_elementwise", &fp16_noised_elementwise, + "A100 sm_80 fused noised elementwise quantize to FP16", pybind11::arg("rows"), + pybind11::arg("noise"), pybind11::arg("alpha"), pybind11::arg("beta")); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/__init__.py new file mode 100644 index 000000000..47d41c6ed --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/__init__.py @@ -0,0 +1,36 @@ +"""Bit-exact A100 (``sm_80``) FP16 end-to-end tile pipeline for the FP16 +proof-of-useful-work scheme. + +Chains the GA100-validated FP16 kernels (``fp16_noisy_quant`` -> ``fp16_policy``) +and the scheme-neutral lottery extractor to reproduce +``zk-pow/src/api/fp16/verify.rs::verify_tile`` / ``verify_tile_proof`` +bit-for-bit on real GA100 silicon: rebuild the noised operands, replay and score +the A100 tile, fold it into the keyed-BLAKE3 jackpot ticket, and (for the proof +path) check the difficulty target. See :mod:`pearl_gemm.fp16_pipeline._host`. +""" + +from ._host import ( + TileVerify, + pipeline, + verify_tile, + verify_tile_proof, +) +from ._layout import ( + AxisPattern, + check_jackpot_difficulty, + compute_jackpot_ticket, + lane_assignment, + xor_fold_extract, +) + +__all__ = [ + "AxisPattern", + "TileVerify", + "check_jackpot_difficulty", + "compute_jackpot_ticket", + "lane_assignment", + "pipeline", + "verify_tile", + "verify_tile_proof", + "xor_fold_extract", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_host.py new file mode 100644 index 000000000..4b53a0b0c --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_host.py @@ -0,0 +1,186 @@ +"""End-to-end FP16 (A100 / ``sm_80``) tile-pipeline driver. + +Chains the already-built, GA100-validated sibling kernels to reproduce +``zk-pow/src/api/fp16/verify.rs::verify_tile`` bit-for-bit on real GA100 silicon: + +1. :func:`pearl_gemm.fp16_noisy_quant.noisy_quantize` rebuilds each noised FP16 + operand ``A' = Q(alpha*A + beta*(E_a@F_a^T))`` (and ``B'``), with the + ``E@F^T`` noise on the committed :func:`pearl_gemm.fp16_gemm.fp16_gemm_a100` + datapath. (``row_norms`` is folded into ``noisy_quantize`` here.) +2. :func:`pearl_gemm.fp16_policy.replay_and_evaluate` replays the ``h x w`` tile + with the same bit-exact A100 accumulation and scores the unpredictable- + accumulation-steps policy -> ``(tile, report)``. +3. The scheme-neutral lottery extractor folds the tile into the jackpot ticket: + :func:`pearl_gemm.fp16_pipeline._layout.lane_assignment` -> + :func:`~pearl_gemm.fp16_pipeline._layout.xor_fold_extract` -> + :func:`~pearl_gemm.fp16_pipeline._layout.compute_jackpot_ticket`. + +The module *drives* the sibling hosts (it does not reimplement their kernels) and +keeps the noised operands on-device between stages 1 and 2. Everything is gated +to ``sm_80`` via ``require_arch``. The native GEMM tile grid needs ``m % 16 == 0`` +for the ``E@F^T`` matmul, so the A side (``h`` as small as 4) is zero-padded up to +a multiple of 16 and sliced back -- bit-exact, since GEMM rows are independent. +""" + +from __future__ import annotations + +from dataclasses import dataclass + +import torch + +from .._utils._arch import Arch, require_arch +from ..fp16_noisy_quant import BuiltRows16, noisy_quantize +from ..fp16_policy import PolicyReport, replay_and_evaluate +from ._layout import ( + AxisPattern, + check_jackpot_difficulty, + compute_jackpot_ticket, + lane_assignment, + xor_fold_extract, +) + +_SUPPORTED_ARCHS = (Arch.SM80,) + + +@dataclass +class TileVerify: + """The pipeline output (mirrors the Rust ``TileVerify``, with the extracted + 64-byte ``message`` surfaced alongside the ticket). + + ``tile`` is the ``(h, w)`` float32 replayed tile; ``report`` the policy + report; ``message`` the 64-byte XOR-fold extract; ``ticket`` the 32-byte + keyed-BLAKE3 jackpot digest. + """ + + tile: torch.Tensor + report: PolicyReport + message: bytes + ticket: bytes + built_a: BuiltRows16 + built_b: BuiltRows16 + + +def _rebuild_operand(rows: torch.Tensor, e: torch.Tensor, f: torch.Tensor, r: int) -> BuiltRows16: + """``noisy_quantize`` with the A100 GEMM's ``m % 16 == 0`` requirement handled + by zero-padding the rows (and their ``E`` factor) up to a multiple of 16 and + slicing the per-row outputs back. Bit-exact: GEMM rows are independent, so the + padded zero rows never perturb the real rows' ``E@F^T`` or per-row scales.""" + num_rows = rows.shape[0] + m16 = (num_rows + 15) & ~15 + if m16 == num_rows: + return noisy_quantize(rows, e, f, r) + pad_rows = torch.zeros((m16 - num_rows, rows.shape[1]), dtype=rows.dtype, device=rows.device) + pad_e = torch.zeros((m16 - num_rows, e.shape[1]), dtype=e.dtype, device=e.device) + built = noisy_quantize( + torch.cat([rows, pad_rows], dim=0), torch.cat([e, pad_e], dim=0), f, r + ) + return BuiltRows16( + noised_part=built.noised_part[:num_rows].contiguous(), + alpha=built.alpha[:num_rows].contiguous(), + beta=built.beta[:num_rows].contiguous(), + l2=built.l2[:num_rows].contiguous(), + ) + + +def pipeline( + a_rows: torch.Tensor, + b_rows: torch.Tensor, + e_a: torch.Tensor, + f_a: torch.Tensor, + e_b: torch.Tensor, + f_b: torch.Tensor, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + seed_a: bytes, + r: int, +) -> TileVerify: + """Run the full FP16 tile pipeline on ``sm_80``, reproducing ``verify_tile``. + + ``a_rows`` is ``(h, k)`` and ``b_rows`` is ``(w, k)`` float16 (the opened, + committed operands); ``e_a``/``f_a`` (``(h, r)`` / ``(k, r)``) and + ``e_b``/``f_b`` (``(w, r)`` / ``(k, r)``) are the deterministic FP16 noise + factors. ``rows_pattern``/``cols_pattern`` are the committed extractor + patterns (their ``tile_size()`` must equal ``h``/``w``), and ``seed_a`` is the + 32-byte jackpot key. + + Returns a :class:`TileVerify` for *any* tile (admissible or not); unlike the + Rust ``verify_tile`` it does not raise on rejection -- call :func:`verify_tile` + for that bail-on-reject contract. Keeps the noised operands on-device between + the rebuild and the replay. + """ + if a_rows.ndim != 2 or b_rows.ndim != 2: + raise ValueError("a_rows and b_rows must be 2D") + if a_rows.dtype != torch.float16 or b_rows.dtype != torch.float16: + raise ValueError("a_rows and b_rows must be float16") + h, k = a_rows.shape + w, kb = b_rows.shape + if kb != k: + raise ValueError(f"a_rows and b_rows must share k ({k} != {kb})") + if rows_pattern.tile_size() != h: + raise ValueError(f"rows_pattern tile_size {rows_pattern.tile_size()} != h {h}") + if cols_pattern.tile_size() != w: + raise ValueError(f"cols_pattern tile_size {cols_pattern.tile_size()} != w {w}") + require_arch("fp16_pipeline", a_rows.device, *_SUPPORTED_ARCHS) + + # 1. Rebuild the noised FP16 operands (noise on the committed A100 datapath). + built_a = _rebuild_operand(a_rows.contiguous(), e_a.contiguous(), f_a.contiguous(), r) + built_b = _rebuild_operand(b_rows.contiguous(), e_b.contiguous(), f_b.contiguous(), r) + + # 2. Replay the A100 tile on-device and score the accumulation policy. + tile, report = replay_and_evaluate(built_a.noised_part, built_b.noised_part) + + # 3. Fold the tile into the jackpot ticket over the committed lane layout. + tile_bits = tile.view(torch.int32).reshape(-1).cpu().numpy().view("uint32") + lanes = lane_assignment(rows_pattern, cols_pattern) + message = xor_fold_extract(tile_bits, lanes) + ticket = compute_jackpot_ticket(seed_a, message) + return TileVerify( + tile=tile, report=report, message=message, ticket=ticket, built_a=built_a, built_b=built_b + ) + + +def verify_tile( + a_rows: torch.Tensor, + b_rows: torch.Tensor, + e_a: torch.Tensor, + f_a: torch.Tensor, + e_b: torch.Tensor, + f_b: torch.Tensor, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + seed_a: bytes, + r: int, +) -> TileVerify: + """:func:`pipeline` with the Rust ``verify_tile`` bail-on-reject contract: + raises :class:`ValueError` when the policy rejects the tile, otherwise returns + the :class:`TileVerify`.""" + v = pipeline(a_rows, b_rows, e_a, f_a, e_b, f_b, rows_pattern, cols_pattern, seed_a, r) + if not v.report.accept: + raise ValueError( + f"the jackpot is not admissible (f_bp={v.report.f_bp:.4f}, rho={v.report.rho:.4f})" + ) + return v + + +def verify_tile_proof( + a_rows: torch.Tensor, + b_rows: torch.Tensor, + e_a: torch.Tensor, + f_a: torch.Tensor, + e_b: torch.Tensor, + f_b: torch.Tensor, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + seed_a: bytes, + r: int, + nbits: int, +) -> TileVerify: + """:func:`verify_tile` plus the difficulty-target check (Rust + ``verify_tile_proof``): raises if the tile is inadmissible or the jackpot does + not clear ``nbits`` scaled by ``h*w*k``.""" + v = verify_tile(a_rows, b_rows, e_a, f_a, e_b, f_b, rows_pattern, cols_pattern, seed_a, r) + h, k = a_rows.shape + w = b_rows.shape[0] + if not check_jackpot_difficulty(v.ticket, nbits, int(h), int(w), int(k)): + raise ValueError("Jackpot condition not satisfied: hash does not meet difficulty target") + return v diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_layout.py b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_layout.py new file mode 100644 index 000000000..240395f6e --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_pipeline/_layout.py @@ -0,0 +1,184 @@ +"""Scheme-neutral lottery extractor: the committed mixed-radix tile layout, the +XOR-fold message extractor, the keyed-BLAKE3 jackpot ticket, and the difficulty +check -- torch-free, bit-for-bit against the Rust verifier. + +These four helpers are reused verbatim by the FP16 verifier from the FP8 modules +(``crate::api::layout::{AxisPattern, lane_assignment}``, +``crate::api::fp8::utils::xor_fold_extract``, +``crate::api::fp8::transcript::compute_jackpot_ticket``, and +``crate::api::proof_utils::check_jackpot_difficulty``); the FP16 tile-pipeline +driver folds its replayed tile into the ticket through them. Nothing here touches +CUDA, so the standalone sm_80 harness and the CI test share this exact code. +""" + +from __future__ import annotations + +import struct +from dataclasses import dataclass + +import blake3 + +# DimType discriminants (``crate::api::layout::DimType``). +NULL = 0 +FOLD = 1 +BLAKE = 2 +NONE = 3 + +# 16 Blake lanes = 16 u32 entries = 64-byte jackpot message (one BLAKE3 block). +JACKPOT_ENTRIES = 16 + +# The FP8/v4 jackpot label; the FP16 scheme folds through the same transcript. +LABEL_JACKPOT = b"pearl/v4/FP8/jackpot" + +_U32 = 0xFFFFFFFF + + +@dataclass(frozen=True) +class AxisPattern: + """A typed mixed-radix pattern for one tile axis (``crate::api::layout``). + + ``dims`` is an ordered low-stride-first list of ``(length, DimType)`` with + implicit stride = product of the preceding lengths. Constructed canonical: + length-1 dims dropped, adjacent same-type dims merged -- matching + ``AxisPattern::new`` so the offset enumerations are identical. + """ + + dims: tuple[tuple[int, int], ...] + + @staticmethod + def new(dims) -> "AxisPattern": + canonical: list[list[int]] = [] + for length, dim_type in dims: + if length < 1: + raise ValueError("dim length must be >= 1") + if length == 1: + continue + if canonical and canonical[-1][1] == dim_type: + canonical[-1][0] *= length + else: + canonical.append([length, dim_type]) + if canonical and canonical[-1][1] == NULL: + raise ValueError("trailing Null dim is redundant; omit it") + return AxisPattern(tuple((l, t) for l, t in canonical)) + + def _offsets_where(self, include) -> list[int]: + offsets = [0] + stride = 1 + for length, t in self.dims: + if include(t): + base = len(offsets) + for d in range(1, length): + for i in range(base): + offsets.append(offsets[i] + d * stride) + stride *= length + return offsets + + def fold_offsets(self) -> list[int]: + return self._offsets_where(lambda t: t == FOLD) + + def blake_offsets(self) -> list[int]: + return self._offsets_where(lambda t: t == BLAKE) + + def tile_offsets(self) -> list[int]: + return self._offsets_where(lambda t: t != NULL) + + def _product(self, include) -> int: + p = 1 + for length, t in self.dims: + if include(t): + p *= length + return p + + def fold_size(self) -> int: + return self._product(lambda t: t == FOLD) + + def blake_size(self) -> int: + return self._product(lambda t: t == BLAKE) + + def tile_size(self) -> int: + return self.fold_size() * self.blake_size() + + +def lane_assignment(rows: AxisPattern, cols: AxisPattern) -> list[list[int]]: + """Map each of the 16 lanes to its subtile's flat row-major tile indices, + bit-for-bit with ``crate::api::layout::lane_assignment``. + + Lane ``rank(b_r) * |B_c| + rank(b_c)`` folds subtile ``(A_r + b_r) x (A_c + + b_c)`` row-major over the sorted fold offsets; flat indices address the + ``rows.tile_size() x cols.tile_size()`` output tile. + """ + + def subtile_positions(axis: AxisPattern) -> list[list[int]]: + tile = axis.tile_offsets() + fold = axis.fold_offsets() + pos = {off: i for i, off in enumerate(tile)} + return [[pos[a + b] for a in fold] for b in axis.blake_offsets()] + + row_subtiles = subtile_positions(rows) + col_subtiles = subtile_positions(cols) + n_cols = cols.tile_size() + lanes: list[list[int]] = [] + for rs in row_subtiles: + for cs in col_subtiles: + lanes.append([r * n_cols + c for r in rs for c in cs]) + return lanes + + +def xor_fold_extract(tile_bits, lane_indices: list[list[int]]) -> bytes: + """The 64-byte lottery message: per lane, a rolling + ``(acc*0x9E3779B1 + f32_bits).rotate_left(13)`` over the lane's cells, + little-endian; bit-for-bit with ``crate::api::fp8::utils::xor_fold_extract``. + + ``tile_bits`` is the flat row-major tile as f32 *bit patterns* (``u32``), so + ``-0.0`` (``0x80000000``) and ``+0.0`` fold differently, exactly as the + reference hashes ``f32::to_bits()``. + """ + if len(lane_indices) != JACKPOT_ENTRIES: + raise ValueError(f"expected {JACKPOT_ENTRIES} lanes, got {len(lane_indices)}") + out = bytearray(4 * JACKPOT_ENTRIES) + for lane, idxs in enumerate(lane_indices): + acc = 0 + for i in idxs: + acc = (acc * 0x9E3779B1) & _U32 + acc = (acc + (int(tile_bits[i]) & _U32)) & _U32 + acc = ((acc << 13) | (acc >> 19)) & _U32 # rotate_left(13) + out[lane * 4 : lane * 4 + 4] = struct.pack(" bytes: + """``H_"jackpot"(message; seed_a)`` -- the 32-byte jackpot digest, bit-for-bit + with ``crate::api::fp8::transcript::compute_jackpot_ticket``. + + ``subkey = BLAKE3(LABEL_JACKPOT, key=seed_a)``; then + ``jackpot = BLAKE3(message, key=subkey)``. + """ + if len(seed_a) != 32: + raise ValueError(f"seed_a must be 32 bytes, got {len(seed_a)}") + subkey = blake3.blake3(LABEL_JACKPOT, key=seed_a).digest(length=32) + return blake3.blake3(message, key=subkey).digest(length=32) + + +def nbits_to_difficulty(nbits: int) -> int: + """Bitcoin compact ``nbits`` -> absolute U256 target (``proof_utils``).""" + exponent = nbits >> 24 + mantissa = nbits & 0x00FFFFFF + if mantissa == 0 or exponent == 0 or (mantissa & 0x00800000): + return 0 + if exponent <= 3: + return mantissa >> (8 * (3 - exponent)) + return (mantissa << (8 * (exponent - 3))) & ((1 << 256) - 1) + + +def check_jackpot_difficulty(jackpot: bytes, nbits: int, h: int, w: int, k: int) -> bool: + """Whether the jackpot clears the difficulty target, bit-for-bit with + ``crate::api::proof_utils::check_jackpot_difficulty``: + ``le(jackpot) <= min(U256::MAX, target * saturating(h*w*k))``. + """ + umax = (1 << 256) - 1 + target = nbits_to_difficulty(nbits) + adjustment = h * w * k + if adjustment > 0xFFFFFFFF: # u32 checked_mul -> u32::MAX on overflow + adjustment = 0xFFFFFFFF + bound = umax if adjustment != 0 and target > umax // adjustment else target * adjustment + return int.from_bytes(jackpot, "little") <= bound diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_policy/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/__init__.py new file mode 100644 index 000000000..2f72edf8b --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/__init__.py @@ -0,0 +1,18 @@ +"""Bit-exact A100 (``sm_80``) FP16 "unpredictable accumulation steps" policy. + +Replays the FP16 proof-of-useful-work tile on real GA100 tensor cores with the +same bit-exact accumulation as :mod:`pearl_gemm.fp16_gemm`, additionally emitting +the per-group policy census and folding it into the tile-global ``f_bp`` / ``rho`` +/ ``accept`` report -- bit-for-bit against the verifier's +``zk-pow/src/api/fp16/policy.rs``. ``fp16_gemm`` is left untouched; this is a +standalone, census-capable module. +""" + +from ._host import ( + PolicyReport, + evaluate, + policy_census, + replay_and_evaluate, +) + +__all__ = ["PolicyReport", "evaluate", "policy_census", "replay_and_evaluate"] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_host.py new file mode 100644 index 000000000..06c4cfb24 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_host.py @@ -0,0 +1,147 @@ +"""Host launch for the bit-exact A100 (``sm_80``) FP16 accumulation policy. + +Reproduces the FP16 scheme's "unpredictable accumulation steps" jackpot policy +(``zk-pow/src/api/fp16/policy.rs`` :: ``replay_and_evaluate`` / ``evaluate``) on +real GA100 silicon, bit-for-bit against the verifier. The kernel replays the +``m x n`` tile with the *same* bit-exact A100 accumulation as +:func:`pearl_gemm.fp16_gemm.fp16_gemm_a100` (``zk-pow/src/api/fp16/accumulate.rs`` +:: ``a100_dot``) but in software, which is what lets it emit the per-group +census the native ``HMMA`` instruction hides: per group, whether the step is a +*breakpoint* (the accumulator alignment or the final FP32 round-toward-zero +discarded a nonzero bit) and how many products truncated. + +The kernel fuses the per-cell reduction of ``evaluate`` in-device, emitting per +cell the three integers it consumes -- ``n_bp`` (breakpoint steps), ``n_runs`` +(maximal runs of non-breakpoint steps; empty no-op groups extend the surrounding +run, exactly as ``PolicyStep::default()`` does) and ``n_pt`` (products truncated +outside breakpoints) -- plus the recomputed FP32 tile. The host folds those +per-cell integers into the tile totals ``breakpoints`` and ``numerator`` and the +f64 ``f_bp`` / ``rho`` / ``accept``, matching ``evaluate`` bit-for-bit. + +The kernel is a small hand-written CUDA extension compiled with +``nvcc -arch=sm_80`` (loaded through ``torch.utils.cpp_extension``), exactly like +``fp16_gemm`` / ``fp16_noisy_quant`` / ``fp16_noise_lines``. ``fp16_gemm`` is left +untouched; this is a standalone, census-capable module. +""" + +from __future__ import annotations + +import functools +import math +import os +from dataclasses import dataclass + +import torch + +from .._utils._arch import Arch, require_arch + +_SUPPORTED_ARCHS = (Arch.SM80,) + +# Mirrors zk-pow/src/api/fp16/{accumulate,policy}.rs. +GROUP = 8 +NOISE_RANK = 32 +MIN_FBP = 0.30 +MIN_RHO = 1.2 + + +@dataclass +class PolicyReport: + """The outcome of the policy over one opened tile (mirrors the Rust struct). + + ``f_bp`` and ``rho`` are Python floats (IEEE f64, bit-identical to the Rust + ``f64`` divisions); ``breakpoints`` and ``numerator`` are the exact integer + tile totals; ``accept`` is ``f_bp >= 0.30 and rho >= 1.2``. + """ + + f_bp: float + rho: float + accept: bool + breakpoints: int + numerator: int + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_policy_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +def policy_census( + a: torch.Tensor, b: torch.Tensor +) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + """Raw per-cell census for the ``m x n`` tile ``a @ b.T``. + + ``a`` is ``(m, k)`` float16 and ``b`` is ``(n, k)`` float16 (the transposed + logical right operand, as in :func:`pearl_gemm.fp16_gemm.fp16_gemm_a100`). + Returns ``(tile, n_bp, n_runs, n_pt)``: the ``(m, n)`` float32 recomputed + tile and three ``(m, n)`` int64 per-cell census tensors. + """ + if a.ndim != 2 or b.ndim != 2: + raise ValueError("a and b must be 2D") + if a.dtype != torch.float16 or b.dtype != torch.float16: + raise ValueError("a and b must be float16") + m, k = a.shape + n, bk = b.shape + if bk != k: + raise ValueError(f"b must have k={k}, got {bk}") + require_arch("fp16_policy_census", a.device, *_SUPPORTED_ARCHS) + tile, n_bp, n_runs, n_pt = _extension().fp16_policy_census(a.contiguous(), b.contiguous()) + return tile, n_bp, n_runs, n_pt + + +def evaluate( + n_bp: torch.Tensor, n_runs: torch.Tensor, n_pt: torch.Tensor, k: int +) -> PolicyReport: + """Fold the per-cell census into the tile :class:`PolicyReport`. + + Bit-for-bit mirror of ``policy.rs`` :: ``evaluate``: + ``numerator = sum_cells[ GROUP*n_bp + NOISE_RANK*n_runs + n_pt ]``, + ``breakpoints = sum_cells n_bp``, + ``f_bp = breakpoints / (cells * ceil(k/GROUP))``, + ``rho = numerator / (cells * k)`` (both f64), + ``accept = f_bp >= MIN_FBP and rho >= MIN_RHO``. + """ + cells = n_bp.numel() + if cells == 0 or k <= 0: + raise ValueError("empty tile") + # Exact integer totals (Python ints are unbounded). + breakpoints = int(n_bp.sum().item()) + numerator = int( + (GROUP * n_bp.to(torch.int64) + NOISE_RANK * n_runs.to(torch.int64) + n_pt.to(torch.int64)) + .sum() + .item() + ) + steps_per_cell = math.ceil(k / GROUP) + f_bp = breakpoints / float(cells * steps_per_cell) + rho = numerator / float(cells * k) + return PolicyReport( + f_bp=f_bp, + rho=rho, + accept=f_bp >= MIN_FBP and rho >= MIN_RHO, + breakpoints=breakpoints, + numerator=numerator, + ) + + +def replay_and_evaluate( + a: torch.Tensor, b: torch.Tensor +) -> tuple[torch.Tensor, PolicyReport]: + """A100 ``sm_80`` replay + policy evaluation of the ``m x n`` tile ``a @ b.T``. + + Convenience wrapper over :func:`policy_census` + :func:`evaluate`, the sm_80 + analogue of ``policy.rs`` :: ``replay_and_evaluate``. ``a`` is ``(m, k)`` and + ``b`` is ``(n, k)`` float16. Returns the ``(m, n)`` float32 tile (bit-exact + to the verifier's replay) and the :class:`PolicyReport`. + """ + k = int(a.shape[1]) + tile, n_bp, n_runs, n_pt = policy_census(a, b) + report = evaluate(n_bp, n_runs, n_pt, k) + return tile, report diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_kernel_sm80.cu new file mode 100644 index 000000000..9451efa0f --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_policy/_kernel_sm80.cu @@ -0,0 +1,257 @@ +// Bit-exact A100 (sm_80) FP16 "unpredictable accumulation steps" policy census. +// +// Replays the FP16 scheme verifier's per-cell accumulation +// (zk-pow/src/api/fp16/accumulate.rs :: a100_dot with census = Some) and fuses +// the per-cell policy reduction (zk-pow/src/api/fp16/policy.rs :: evaluate) +// in-kernel. One thread owns one output cell (i, j) of the m x n tile and: +// +// * reproduces the integer accumulation model natively in software (NOT the +// native HMMA datapath): the k axis is split into groups of GROUP = 8 +// products, each group aligns onto the 2^(eta - W) grid (W = 24) by +// truncation toward zero, sums exactly, then rounds the sum toward zero back +// to FP32. This software path is what exposes the census the HMMA +// instruction hides; +// * emits, per group, the two census quantities a100_dot records -- +// breakpoint (the accumulator alignment OR the final FP32 round-toward-zero +// discarded a nonzero bit) and products_truncated (how many of the group's +// products lost nonzero bits in their right-shift alignment) -- and folds +// them into the per-cell integers evaluate() consumes: +// n_bp = # breakpoint steps, +// n_runs = # maximal runs of non-breakpoint steps (empty no-op groups are +// non-breakpoint steps with 0 truncations, so they extend the +// surrounding run, exactly as PolicyStep::default() does), +// n_pt = sum of products_truncated over non-breakpoint steps. +// +// The kernel writes the recomputed FP32 tile (bit-exact to the verifier's +// replay / fp16_gemm) and the per-cell (n_bp, n_runs, n_pt). The host folds the +// per-cell integers into the tile totals (breakpoints, numerator) and the f64 +// f_bp / rho / accept, matching evaluate() bit-for-bit. +// +// All intermediate magnitudes are bounded: a group sum is < 2^30 (8 products +// each < 2^26 plus an accumulator term < 2^25), so a 64-bit signed accumulator +// is exact and no i128 is needed (unlike the Rust reference, whose i128 is only +// for headroom). Every shift operand is non-negative (signs are applied +// separately), so a plain logical >> is the Rust truncating shift_i128. +// +// A: (m, k) row-major FP16 (logical left operand) +// B: (n, k) row-major FP16 (transposed logical right operand: row j is +// logical column j, exactly a100_matmul's `b`) +// k is arbitrary (>= 1); no tile-granularity constraint (software path). + +#include +#include + +#define POLICY_W 24 +#define POLICY_GROUP 8 +// i32::MIN / 2, the Rust "no exponent" sentinel. +#define POLICY_NEG (-1073741824) +#define FP32_MIN_EXP (-149) + +// ---- FP16 operand decomposition (dtype::decompose_fp16) ---- +// value = sign * sig * 2^(eps - 10); eps clamped to -14 for subnormals. +__device__ __forceinline__ void decompose_fp16(unsigned short bits, int* sign, + long long* sig, int* eps) { + unsigned exp = (bits >> 10) & 0x1F; + long long man = (long long)(bits & 0x03FF); + *sign = (bits & 0x8000) ? -1 : 1; + if (exp == 0 && man == 0) { + *sign = 1; + *sig = 0; + *eps = 0; + } else if (exp == 0) { + *sig = man; // subnormal + *eps = -14; + } else { + *sig = 0x400 | man; // normal: implicit 1 + *eps = (int)exp - 15; + } +} + +// ---- FP32 accumulator decomposition (accumulate::acc_parts) ---- +// value = sign * sig * 2^ulp; el is the stored exponent for the alignment max +// (clamped to -126 for subnormals), POLICY_NEG for a zero accumulator. +__device__ __forceinline__ void acc_parts(float c, long long* sign, + unsigned long long* sig, int* el, int* ulp) { + unsigned int bits = __float_as_uint(c); + if ((bits & 0x7FFFFFFFu) == 0u) { // +/-0 + *sign = 1; + *sig = 0ull; + *el = POLICY_NEG; + *ulp = 0; + return; + } + *sign = (bits >> 31) ? -1 : 1; + int exp_field = (int)((bits >> 23) & 0xFF); + unsigned long long man = (unsigned long long)(bits & 0x7FFFFFu); + if (exp_field > 0) { + int el_v = exp_field - 127; + *sig = 0x800000ull | man; // 24-bit significand (implicit 1) + *el = el_v; + *ulp = el_v - 23; + } else { + *sig = man; // subnormal + *el = -126; + *ulp = FP32_MIN_EXP; + } +} + +// `x >> (-s)` truncating toward zero for s<0, `x << s` for s>=0. x is always +// non-negative here (prod, cm), so a logical shift is the Rust shift_i128. +// Guards shifts >= 64 (x < 2^24, so the result is 0, as i128 >> gives). +__device__ __forceinline__ long long shift_nonneg(long long x, int s) { + if (s >= 0) return x << s; + int rs = -s; + if (rs >= 64) return 0; + return x >> rs; +} + +// Rounds the integer s * 2^unit toward zero to FP32 (accumulate::rz_to_f32). +// |s| < 2^30 so a u64 magnitude is exact. Returns the FP32 value. +__device__ __forceinline__ float rz_to_f32(long long s, int unit) { + if (s == 0) return 0.0f; + double sign = (s < 0) ? -1.0 : 1.0; + unsigned long long a = (unsigned long long)(s < 0 ? -s : s); + int nb = 63 - __clzll(a); // floor(log2|s|) + int keep = nb + unit - 23; + if (keep < FP32_MIN_EXP) keep = FP32_MIN_EXP; + int drop = keep - unit; + if (drop < 0) drop = 0; + if (drop > 127) drop = 127; + unsigned long long truncated = (drop >= 64) ? 0ull : ((a >> drop) << drop); + double val = sign * (double)truncated * ldexp(1.0, unit); + return (float)val; +} + +// One output cell's a100_dot + fused policy census reduction. +__global__ void fp16_policy_kernel(const __half* __restrict__ A, + const __half* __restrict__ B, + int m, int n, int k, + float* __restrict__ D, + long long* __restrict__ N_bp, + long long* __restrict__ N_runs, + long long* __restrict__ N_pt) { + int cell = blockIdx.x * blockDim.x + threadIdx.x; + if (cell >= m * n) return; + int i = cell / n; + int j = cell % n; + const __half* a = A + (long)i * k; + const __half* b = B + (long)j * k; + + float cur = 0.0f; + long long n_bp = 0, n_runs = 0, n_pt = 0; + bool in_run = false; + + for (int g0 = 0; g0 < k; g0 += POLICY_GROUP) { + int g1 = min(g0 + POLICY_GROUP, k); + long long csgn; + unsigned long long cm; + int cel, culp; + acc_parts(cur, &csgn, &cm, &cel, &culp); + + // Alignment exponent over nonzero products and the accumulator. + int eta = cel; + for (int u = g0; u < g1; ++u) { + int sa, sb; + long long ma, mb; + int ea, eb; + decompose_fp16(__half_as_ushort(a[u]), &sa, &ma, &ea); + decompose_fp16(__half_as_ushort(b[u]), &sb, &mb, &eb); + if (ma != 0 && mb != 0) { + int e = ea + eb; + if (e > eta) eta = e; + } + } + if (eta == POLICY_NEG) { + // Empty no-op group: a non-breakpoint step with 0 truncations. It + // extends the surrounding run and contributes nothing else. + if (!in_run) { n_runs += 1; in_run = true; } + continue; + } + int unit = eta - POLICY_W; + + long long sum = 0; + unsigned int products_truncated = 0; + for (int u = g0; u < g1; ++u) { + int sa, sb; + long long ma, mb; + int ea, eb; + decompose_fp16(__half_as_ushort(a[u]), &sa, &ma, &ea); + decompose_fp16(__half_as_ushort(b[u]), &sb, &mb, &eb); + if (ma == 0 || mb == 0) continue; + long long prod = ma * mb; // < 2^22, exact + int sh = (ea + eb) - 20 - unit; // product LSB is 2^(ea+eb-20) + long long aligned = shift_nonneg(prod, sh); + if (sh < 0) { + int nbits = (-sh < 62) ? -sh : 62; // prod < 2^22: 62 covers it + if ((prod & (((long long)1 << nbits) - 1)) != 0) products_truncated += 1; + } + sum += (long long)(sa * sb) * aligned; + } + // Accumulator term. + int csh = culp - unit; + long long acc_aligned = shift_nonneg((long long)cm, csh); + bool acc_truncated = false; + if (csh < 0 && cm != 0ull) { + int nbits = (-csh < 63) ? -csh : 63; // cm < 2^24: 63 covers it + if ((cm & (((unsigned long long)1 << nbits) - 1)) != 0ull) acc_truncated = true; + } + sum += csgn * acc_aligned; + + float nw = rz_to_f32(sum, unit); + // rz dropped a nonzero bit iff the result differs from the exact sum. + bool rz_dropped = ((double)nw) != ((double)sum) * ldexp(1.0, unit); + bool breakpoint = acc_truncated || rz_dropped; + + if (breakpoint) { + n_bp += 1; + in_run = false; + } else { + n_pt += (long long)products_truncated; + if (!in_run) { n_runs += 1; in_run = true; } + } + cur = nw; + } + + D[cell] = cur; + N_bp[cell] = n_bp; + N_runs[cell] = n_runs; + N_pt[cell] = n_pt; +} + +// ---- Host launcher ---- +// Returns {D (m,n) f32, n_bp (m,n) i64, n_runs (m,n) i64, n_pt (m,n) i64}. +std::vector fp16_policy_census(torch::Tensor A, torch::Tensor B) { + TORCH_CHECK(A.is_cuda() && B.is_cuda(), "A and B must be CUDA tensors"); + TORCH_CHECK(A.scalar_type() == torch::kFloat16, "A must be float16"); + TORCH_CHECK(B.scalar_type() == torch::kFloat16, "B must be float16"); + TORCH_CHECK(A.dim() == 2 && B.dim() == 2, "A and B must be 2D"); + TORCH_CHECK(A.is_contiguous() && B.is_contiguous(), "A and B must be contiguous"); + int m = A.size(0), k = A.size(1); + int n = B.size(0), kb = B.size(1); + TORCH_CHECK(k == kb, "A and B must share k"); + TORCH_CHECK(k >= 1, "k must be >= 1"); + + auto f32 = torch::dtype(torch::kFloat32).device(A.device()); + auto i64 = torch::dtype(torch::kInt64).device(A.device()); + auto D = torch::empty({m, n}, f32); + auto N_bp = torch::empty({m, n}, i64); + auto N_runs = torch::empty({m, n}, i64); + auto N_pt = torch::empty({m, n}, i64); + int cells = m * n; + if (cells == 0) return {D, N_bp, N_runs, N_pt}; + + int threads = 128; + int blocks = (cells + threads - 1) / threads; + fp16_policy_kernel<<>>( + (const __half*)A.data_ptr(), (const __half*)B.data_ptr(), m, n, k, + (float*)D.data_ptr(), (long long*)N_bp.data_ptr(), + (long long*)N_runs.data_ptr(), (long long*)N_pt.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_policy_census launch failed"); + return {D, N_bp, N_runs, N_pt}; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fp16_policy_census", &fp16_policy_census, + "A100 sm_80 bit-exact FP16 accumulation policy census (tile + per-cell n_bp/n_runs/n_pt)", + pybind11::arg("A"), pybind11::arg("B")); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_search/__init__.py b/miner/pearl-gemm/src/pearl_gemm/fp16_search/__init__.py new file mode 100644 index 000000000..2965f0989 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_search/__init__.py @@ -0,0 +1,21 @@ +"""Bit-exact A100 (``sm_80``) full-matrix FP16 lottery search for the FP16 +proof-of-useful-work scheme. + +The FP16 analogue of the lottery fused inside the FP8 ``mixed_gemm``: scan every +committed tile of a noised matmul ``A' @ B'^T`` on real GA100 silicon and latch +the FIRST tile (lowest flat tile index) whose keyed-BLAKE3 jackpot ticket clears +the difficulty threshold. The per-tile ``a100_dot`` accumulation, the 16-lane +XOR-fold, the keyed-BLAKE3 ticket, and the 256-bit difficulty compare are all +bit-for-bit with the verifier (reusing the GA100-validated ``fp16_policy`` / +``fp16_commit`` math). Policy is not evaluated here -- the host driver runs +``fp16_policy`` on the latched tile before submission. See +:mod:`pearl_gemm.fp16_search._host`. +""" + +from ._host import SearchHit, difficulty_bound, search + +__all__ = [ + "SearchHit", + "difficulty_bound", + "search", +] diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_search/_host.py b/miner/pearl-gemm/src/pearl_gemm/fp16_search/_host.py new file mode 100644 index 000000000..67c553ff0 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_search/_host.py @@ -0,0 +1,196 @@ +"""Host launch for the bit-exact A100 (``sm_80``) full-matrix FP16 lottery search. + +The FP16 analogue of the lottery fused inside the FP8 ``mixed_gemm``: scan every +committed tile of a noised matmul ``A' @ B'^T`` on-GPU and latch the FIRST tile +(lowest flat tile index) whose jackpot ticket clears the difficulty threshold. + +Per tile ``(tr, tc)`` over the ``(m/h) x (n/w)`` grid the kernel recomputes the +``h x w`` tile with the SAME bit-exact A100 accumulation as +:func:`pearl_gemm.fp16_policy.replay_and_evaluate` / +:func:`pearl_gemm.fp16_gemm.fp16_gemm_a100` (``a100_dot``), folds the tile's f32 +bit patterns into the 64-byte XOR-fold message over the committed 16-lane layout +(:func:`pearl_gemm.fp16_pipeline.lane_assignment` / +:func:`~pearl_gemm.fp16_pipeline.xor_fold_extract`), computes +``ticket = keyed-BLAKE3(message, key=pow_key)`` (the host-precomputed jackpot +subkey, exactly as fp8 passes ``pow_key`` into ``mixed_gemm``), and tests +``le(ticket) <= bound`` where ``bound`` is the host-precomputed 256-bit target of +:func:`pearl_gemm.fp16_pipeline.check_jackpot_difficulty`. + +**Policy is NOT evaluated here.** Latching is purely on the jackpot difficulty +threshold, mirroring fp8 (which filters policy-inadmissible winners host-side at +submission). The host driver runs :func:`pearl_gemm.fp16_policy` on the latched +tile afterwards. + +The kernel is a small hand-written CUDA extension compiled with +``nvcc -arch=sm_80`` (loaded through ``torch.utils.cpp_extension``), exactly like +``fp16_gemm`` / ``fp16_policy`` / ``fp16_commit``; the ``a100_dot`` accumulation +and the keyed-BLAKE3 compression are reused verbatim from those GA100-validated +siblings. +""" + +from __future__ import annotations + +import functools +import os +from dataclasses import dataclass + +import torch + +from .._utils._arch import Arch, require_arch +from ..fp16_pipeline._layout import ( + AxisPattern, + JACKPOT_ENTRIES, + lane_assignment, + nbits_to_difficulty, +) + +_SUPPORTED_ARCHS = (Arch.SM80,) + +_U256_MAX = (1 << 256) - 1 + + +@dataclass(frozen=True) +class SearchHit: + """The first-winner latch (or ``found=False`` when no tile cleared ``nbits``). + + ``tile_row`` / ``tile_col`` are the winning tile's grid coordinates (lowest + flat index ``tile_row * (n // w) + tile_col`` wins ties). ``ticket`` is the + 32-byte keyed-BLAKE3 jackpot digest of that tile. The host driver reconstructs + the absolute operand rows/cols from ``(tile_row, tile_col)`` and the tile + geometry ``(h, w)`` -- rows ``[tile_row*h, tile_row*h + h)`` of ``A'`` and + rows ``[tile_col*w, tile_col*w + w)`` of ``B'`` -- then runs ``fp16_policy`` + on it before submission. + """ + + found: bool + tile_row: int + tile_col: int + ticket: bytes + + +def difficulty_bound(nbits: int, h: int, w: int, k: int) -> int: + """The 256-bit win bound ``min(U256::MAX, difficulty(nbits) * sat_u32(h*w*k))``. + + Bit-for-bit with ``crate::api::proof_utils::check_jackpot_difficulty`` / + :func:`pearl_gemm.fp16_pipeline.check_jackpot_difficulty`: a ticket wins iff + ``le(ticket) <= bound``. + """ + target = nbits_to_difficulty(nbits) + adjustment = min(h * w * k, 0xFFFFFFFF) # u32 checked_mul saturates to u32::MAX + if adjustment != 0 and target > _U256_MAX // adjustment: + return _U256_MAX + return target * adjustment + + +@functools.lru_cache(maxsize=1) +def _extension(): + """Compile (once) and return the loaded ``sm_80`` CUDA extension.""" + from torch.utils.cpp_extension import load + + src = os.path.join(os.path.dirname(__file__), "_kernel_sm80.cu") + return load( + name="pearl_fp16_search_sm80", + sources=[src], + extra_cuda_cflags=["-arch=sm_80", "-O3"], + verbose=False, + ) + + +def _u32_words_tensor(value: int, device: torch.device) -> torch.Tensor: + """``value`` as 8 little-endian ``u32`` words (word 0 least significant), as a + signed int32 CUDA tensor on ``device``.""" + words = [(value >> (32 * i)) & 0xFFFFFFFF for i in range(8)] + signed = [w - (1 << 32) if w >= (1 << 31) else w for w in words] + return torch.tensor(signed, dtype=torch.int32, device=device) + + +def _lanes_tensor( + rows_pattern: AxisPattern, cols_pattern: AxisPattern, h: int, w: int, device: torch.device +) -> torch.Tensor: + """The precomputed ``16 x (h*w/16)`` lane-index table, flattened to int32 on + ``device``. Computed host-side so the kernel is pattern-agnostic.""" + lanes = lane_assignment(rows_pattern, cols_pattern) + if len(lanes) != JACKPOT_ENTRIES: + raise ValueError(f"expected {JACKPOT_ENTRIES} lanes, got {len(lanes)}") + lane_len = len(lanes[0]) + if any(len(lane) != lane_len for lane in lanes): + raise ValueError("all lanes must have the same fold size") + if lane_len * JACKPOT_ENTRIES != h * w: + raise ValueError(f"lane table covers {lane_len * JACKPOT_ENTRIES} cells, tile is {h * w}") + flat = [idx for lane in lanes for idx in lane] + return torch.tensor(flat, dtype=torch.int32, device=device) + + +def search( + a_prime: torch.Tensor, + b_prime: torch.Tensor, + pow_key: bytes, + nbits: int, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + collect_tickets: bool = False, +): + """Full-matrix FP16 lottery search over ``a_prime @ b_prime.T`` on ``sm_80``. + + ``a_prime`` is ``(m, k)`` float16 (the noised A') and ``b_prime`` is + ``(n, k)`` float16 (the noised, transposed B': row ``j`` is logical column + ``j``). ``pow_key`` is the 32-byte jackpot subkey (the host precomputes + ``BLAKE3("pearl/v4/FP8/jackpot", key=seed_a)``). ``nbits`` is the compact + difficulty. The committed tile is ``h = rows_pattern.tile_size()`` by + ``w = cols_pattern.tile_size()``; the 16-lane fold layout is precomputed from + the patterns host-side and passed to the kernel, so the kernel is + pattern-agnostic. + + Returns a :class:`SearchHit` for the first tile (lowest flat tile index + ``tr * (n // w) + tc``) whose ticket clears ``nbits`` scaled by ``h*w*k``, or + ``found=False`` when none does. When ``collect_tickets`` is set, returns + ``(SearchHit, tickets)`` where ``tickets`` is an ``(num_tiles, 8)`` uint32 + CPU tensor of every tile's ticket words (for validation/debugging). + """ + if a_prime.ndim != 2 or b_prime.ndim != 2: + raise ValueError("a_prime and b_prime must be 2D") + if a_prime.dtype != torch.float16 or b_prime.dtype != torch.float16: + raise ValueError("a_prime and b_prime must be float16") + if len(pow_key) != 32: + raise ValueError(f"pow_key must be 32 bytes, got {len(pow_key)}") + m, k = a_prime.shape + n, kb = b_prime.shape + if kb != k: + raise ValueError(f"a_prime and b_prime must share k ({k} != {kb})") + h = rows_pattern.tile_size() + w = cols_pattern.tile_size() + if m % h != 0: + raise ValueError(f"m={m} is not a multiple of h={h}") + if n % w != 0: + raise ValueError(f"n={n} is not a multiple of w={w}") + require_arch("fp16_search", a_prime.device, *_SUPPORTED_ARCHS) + + dev = a_prime.device + lanes = _lanes_tensor(rows_pattern, cols_pattern, h, w, dev) + key_words = [int.from_bytes(pow_key[4 * i : 4 * i + 4], "little") for i in range(8)] + key_signed = [kw - (1 << 32) if kw >= (1 << 31) else kw for kw in key_words] + key_t = torch.tensor(key_signed, dtype=torch.int32, device=dev) + bound_t = _u32_words_tensor(difficulty_bound(nbits, int(h), int(w), int(k)), dev) + + found, min_idx, latch, tickets = _extension().fp16_search( + a_prime.contiguous(), b_prime.contiguous(), lanes, key_t, bound_t, + int(h), int(w), 1 if collect_tickets else 0, + ) + + found_h = bool(found.cpu().item()) + if found_h: + latch_w = latch.cpu().numpy() + tile_row = int(latch_w[0]) + tile_col = int(latch_w[1]) + ticket_words = latch_w[2:10].view("uint32") + ticket = b"".join(int(tw).to_bytes(4, "little") for tw in ticket_words) + hit = SearchHit(found=True, tile_row=tile_row, tile_col=tile_col, ticket=ticket) + else: + hit = SearchHit(found=False, tile_row=-1, tile_col=-1, ticket=b"") + + if collect_tickets: + ntc = n // w + num_tiles = (m // h) * ntc + tickets_u32 = tickets.cpu().numpy().view("uint32").reshape(num_tiles, 8) + return hit, torch.from_numpy(tickets_u32.copy()) + return hit diff --git a/miner/pearl-gemm/src/pearl_gemm/fp16_search/_kernel_sm80.cu b/miner/pearl-gemm/src/pearl_gemm/fp16_search/_kernel_sm80.cu new file mode 100644 index 000000000..40a52a204 --- /dev/null +++ b/miner/pearl-gemm/src/pearl_gemm/fp16_search/_kernel_sm80.cu @@ -0,0 +1,418 @@ +// Bit-exact A100 (sm_80) full-matrix FP16 lottery search + first-winner latch. +// +// The FP16 analogue of the lottery fused inside the FP8 `mixed_gemm`: scan every +// committed tile of a noised matmul A'@B'^T on-GPU and latch the FIRST tile (by +// flat tile index) whose jackpot ticket clears the difficulty threshold. +// +// For each tile (tr, tc) over the (m/h) x (n/w) grid: +// * compute the h x w tile A'[tr-block] @ B'[tc-block]^T with the SAME +// bit-exact A100 accumulation as fp16_policy / fp16_gemm +// (zk-pow/src/api/fp16/accumulate.rs :: a100_dot) -- reused verbatim here, +// minus the policy census the search does not need, so each cell is the +// identical f32 bit pattern; +// * fold the tile's f32 BIT patterns into a 64-byte message over the committed +// 16-lane layout (crate::api::fp8::utils::xor_fold_extract): per lane a +// rolling acc = (acc*0x9E3779B1 + f32_bits).rotate_left(13) over the lane's +// cells, 16 u32 little-endian; +// * ticket = keyed-BLAKE3(message, key = pow_key) -- pow_key is the jackpot +// subkey the host precomputes (BLAKE3("pearl/v4/FP8/jackpot", key=seed_a)), +// exactly like fp8 passes pow_key into mixed_gemm. A 64-byte message is one +// full BLAKE3 block / one chunk, so the ticket is a single ROOT-finalized +// keyed compression (reused verbatim from fp16_commit / fp16_noise_lines, +// the compression agent B validated bit-identical to the `blake3` crate); +// * win iff le(ticket) <= bound, where bound = min(U256::MAX, difficulty(nbits) +// * saturating_u32(h*w*k)) is precomputed host-side (exact bigint) and passed +// in as 8 little-endian u32 words -- a 256-bit little-endian compare here is +// bit-for-bit crate::api::proof_utils::check_jackpot_difficulty. +// +// First-winner discipline (deterministic, lowest flat tile index wins ties): +// the scan kernel (one block per tile) does atomicMin over the winning tiles' +// flat indices, so the latched index is independent of block completion order. +// A second single-block kernel then recomputes that one tile to fill the ticket, +// avoiding both a per-tile ticket scratch and any racy "store my ticket under a +// lock" across the grid. +// +// A: (m, k) row-major FP16 (noised left operand A') +// B: (n, k) row-major FP16 (noised, transposed right operand B': row j is +// logical column j, exactly a100_matmul's `b`) +// k is arbitrary (>= 1); no tile-granularity constraint (software path). + +#include +#include + +#define SEARCH_W 24 +#define SEARCH_GROUP 8 +// i32::MIN / 2, the Rust "no exponent" sentinel. +#define SEARCH_NEG (-1073741824) +#define FP32_MIN_EXP (-149) + +// ---- FP16 operand decomposition (dtype::decompose_fp16) ---- +__device__ __forceinline__ void decompose_fp16(unsigned short bits, int* sign, + long long* sig, int* eps) { + unsigned exp = (bits >> 10) & 0x1F; + long long man = (long long)(bits & 0x03FF); + *sign = (bits & 0x8000) ? -1 : 1; + if (exp == 0 && man == 0) { + *sign = 1; + *sig = 0; + *eps = 0; + } else if (exp == 0) { + *sig = man; // subnormal + *eps = -14; + } else { + *sig = 0x400 | man; // normal: implicit 1 + *eps = (int)exp - 15; + } +} + +// ---- FP32 accumulator decomposition (accumulate::acc_parts) ---- +__device__ __forceinline__ void acc_parts(float c, long long* sign, + unsigned long long* sig, int* el, int* ulp) { + unsigned int bits = __float_as_uint(c); + if ((bits & 0x7FFFFFFFu) == 0u) { // +/-0 + *sign = 1; + *sig = 0ull; + *el = SEARCH_NEG; + *ulp = 0; + return; + } + *sign = (bits >> 31) ? -1 : 1; + int exp_field = (int)((bits >> 23) & 0xFF); + unsigned long long man = (unsigned long long)(bits & 0x7FFFFFu); + if (exp_field > 0) { + int el_v = exp_field - 127; + *sig = 0x800000ull | man; // 24-bit significand (implicit 1) + *el = el_v; + *ulp = el_v - 23; + } else { + *sig = man; // subnormal + *el = -126; + *ulp = FP32_MIN_EXP; + } +} + +// `x >> (-s)` truncating toward zero for s<0, `x << s` for s>=0 (x non-negative). +__device__ __forceinline__ long long shift_nonneg(long long x, int s) { + if (s >= 0) return x << s; + int rs = -s; + if (rs >= 64) return 0; + return x >> rs; +} + +// Rounds the integer s * 2^unit toward zero to FP32 (accumulate::rz_to_f32). +__device__ __forceinline__ float rz_to_f32(long long s, int unit) { + if (s == 0) return 0.0f; + double sign = (s < 0) ? -1.0 : 1.0; + unsigned long long a = (unsigned long long)(s < 0 ? -s : s); + int nb = 63 - __clzll(a); + int keep = nb + unit - 23; + if (keep < FP32_MIN_EXP) keep = FP32_MIN_EXP; + int drop = keep - unit; + if (drop < 0) drop = 0; + if (drop > 127) drop = 127; + unsigned long long truncated = (drop >= 64) ? 0ull : ((a >> drop) << drop); + double val = sign * (double)truncated * ldexp(1.0, unit); + return (float)val; +} + +// One output cell's a100_dot (fp16_policy's accumulation, census dropped). +__device__ float a100_dot(const __half* __restrict__ a, const __half* __restrict__ b, int k) { + float cur = 0.0f; + for (int g0 = 0; g0 < k; g0 += SEARCH_GROUP) { + int g1 = min(g0 + SEARCH_GROUP, k); + long long csgn; + unsigned long long cm; + int cel, culp; + acc_parts(cur, &csgn, &cm, &cel, &culp); + + int eta = cel; + for (int u = g0; u < g1; ++u) { + int sa, sb; + long long ma, mb; + int ea, eb; + decompose_fp16(__half_as_ushort(a[u]), &sa, &ma, &ea); + decompose_fp16(__half_as_ushort(b[u]), &sb, &mb, &eb); + if (ma != 0 && mb != 0) { + int e = ea + eb; + if (e > eta) eta = e; + } + } + if (eta == SEARCH_NEG) continue; // empty no-op group leaves cur unchanged + int unit = eta - SEARCH_W; + + long long sum = 0; + for (int u = g0; u < g1; ++u) { + int sa, sb; + long long ma, mb; + int ea, eb; + decompose_fp16(__half_as_ushort(a[u]), &sa, &ma, &ea); + decompose_fp16(__half_as_ushort(b[u]), &sb, &mb, &eb); + if (ma == 0 || mb == 0) continue; + long long prod = ma * mb; + int sh = (ea + eb) - 20 - unit; + long long aligned = shift_nonneg(prod, sh); + sum += (long long)(sa * sb) * aligned; + } + int csh = culp - unit; + long long acc_aligned = shift_nonneg((long long)cm, csh); + sum += csgn * acc_aligned; + + cur = rz_to_f32(sum, unit); + } + return cur; +} + +// ---- BLAKE3 keyed compression (from fp16_commit / fp16_noise_lines; crate-identical) ---- + +__constant__ unsigned int BLAKE3_IV[8] = { + 0x6A09E667u, 0xBB67AE85u, 0x3C6EF372u, 0xA54FF53Au, + 0x510E527Fu, 0x9B05688Cu, 0x1F83D9ABu, 0x5BE0CD19u}; + +#define B3F_CHUNK_START 1u +#define B3F_CHUNK_END 2u +#define B3F_ROOT 8u +#define B3F_KEYED_HASH 16u + +__device__ __forceinline__ unsigned int rotr32(unsigned int x, unsigned int n) { + return (x >> n) | (x << (32u - n)); +} + +__device__ void blake3_compress(const unsigned int cv[8], const unsigned int m[16], + unsigned int counter_lo, unsigned int counter_hi, + unsigned int flags, unsigned int out[16]) { + unsigned int s[16]; +#pragma unroll + for (int i = 0; i < 8; ++i) s[i] = cv[i]; + s[8] = BLAKE3_IV[0]; + s[9] = BLAKE3_IV[1]; + s[10] = BLAKE3_IV[2]; + s[11] = BLAKE3_IV[3]; + s[12] = counter_lo; + s[13] = counter_hi; + s[14] = 64u; // block_len (always a full 64-byte block here) + s[15] = flags; + + unsigned int v[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = m[i]; + + const int PERM[16] = {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}; + +#define G(a, b, c, d, x, y) \ + s[a] = s[a] + s[b] + (x); \ + s[d] = rotr32(s[d] ^ s[a], 16); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 12); \ + s[a] = s[a] + s[b] + (y); \ + s[d] = rotr32(s[d] ^ s[a], 8); \ + s[c] = s[c] + s[d]; \ + s[b] = rotr32(s[b] ^ s[c], 7); + + for (int round = 0; round < 7; ++round) { + G(0, 4, 8, 12, v[0], v[1]); + G(1, 5, 9, 13, v[2], v[3]); + G(2, 6, 10, 14, v[4], v[5]); + G(3, 7, 11, 15, v[6], v[7]); + G(0, 5, 10, 15, v[8], v[9]); + G(1, 6, 11, 12, v[10], v[11]); + G(2, 7, 8, 13, v[12], v[13]); + G(3, 4, 9, 14, v[14], v[15]); + if (round < 6) { + unsigned int t[16]; +#pragma unroll + for (int i = 0; i < 16; ++i) t[i] = v[PERM[i]]; +#pragma unroll + for (int i = 0; i < 16; ++i) v[i] = t[i]; + } + } +#undef G + +#pragma unroll + for (int i = 0; i < 8; ++i) { + out[i] = s[i] ^ s[i + 8]; + out[i + 8] = s[i + 8] ^ cv[i]; + } +} + +// ---- Lottery fold + ticket + difficulty ---- + +__device__ __forceinline__ unsigned int rotl32(unsigned int x, unsigned int n) { + return (x << n) | (x >> (32u - n)); +} + +// XOR-fold the h x w tile's f32 bit patterns into the 16 u32 message words over +// the committed lane layout, then one ROOT-finalized keyed-BLAKE3 compression of +// that 64-byte message under `key` -> the 32-byte ticket (8 LE u32 words). +__device__ void fold_and_hash(const unsigned int* __restrict__ tile_bits, + const int* __restrict__ lanes, int lane_len, + const unsigned int* __restrict__ key, + unsigned int ticket[8]) { + unsigned int msg[16]; + for (int lane = 0; lane < 16; ++lane) { + const int* idx = lanes + (long)lane * lane_len; + unsigned int acc = 0u; + for (int t = 0; t < lane_len; ++t) { + acc = acc * 0x9E3779B1u; + acc = acc + tile_bits[idx[t]]; + acc = rotl32(acc, 13u); + } + msg[lane] = acc; + } + unsigned int cv[8]; +#pragma unroll + for (int i = 0; i < 8; ++i) cv[i] = key[i]; + unsigned int o[16]; + blake3_compress(cv, msg, 0u, 0u, + B3F_KEYED_HASH | B3F_CHUNK_START | B3F_CHUNK_END | B3F_ROOT, o); +#pragma unroll + for (int i = 0; i < 8; ++i) ticket[i] = o[i]; +} + +// le(ticket) <= le(bound) as 256-bit little-endian unsigned (word 0 least sig). +__device__ __forceinline__ bool le_u256(const unsigned int x[8], const unsigned int b[8]) { +#pragma unroll + for (int i = 7; i >= 0; --i) { + if (x[i] < b[i]) return true; + if (x[i] > b[i]) return false; + } + return true; // equal +} + +// Fill s_tile[0..h*w) with the tile's f32 bit patterns (block-strided). +__device__ void fill_tile(const __half* __restrict__ A, const __half* __restrict__ B, + int k, int h, int w, int tr, int tc, + unsigned int* __restrict__ s_tile) { + int hw = h * w; + for (int c = threadIdx.x; c < hw; c += blockDim.x) { + int r = c / w; + int col = c % w; + const __half* a = A + (long)(tr * h + r) * k; + const __half* b = B + (long)(tc * w + col) * k; + s_tile[c] = __float_as_uint(a100_dot(a, b, k)); + } +} + +// ---- Kernels ---- + +// Scan: one block per tile. Winners atomicMin their flat index into *min_idx +// (sentinel = num_tiles) and raise *found. Optionally dumps every tile's ticket. +__global__ void search_scan_kernel(const __half* __restrict__ A, const __half* __restrict__ B, + int k, int h, int w, int ntc, + const int* __restrict__ lanes, int lane_len, + const unsigned int* __restrict__ key, + const unsigned int* __restrict__ bound, + int* __restrict__ found, int* __restrict__ min_idx, + unsigned int* __restrict__ all_tickets, int collect) { + extern __shared__ unsigned int s_tile[]; + int tile = blockIdx.x; + int tr = tile / ntc; + int tc = tile % ntc; + fill_tile(A, B, k, h, w, tr, tc, s_tile); + __syncthreads(); + if (threadIdx.x == 0) { + unsigned int ticket[8]; + fold_and_hash(s_tile, lanes, lane_len, key, ticket); + if (collect) { +#pragma unroll + for (int i = 0; i < 8; ++i) all_tickets[(long)tile * 8 + i] = ticket[i]; + } + if (le_u256(ticket, bound)) { + atomicMin(min_idx, tile); + atomicMax(found, 1); + } + } +} + +// Latch: recompute the single winning tile and write (tr, tc, ticket[8]) out. +__global__ void search_latch_kernel(const __half* __restrict__ A, const __half* __restrict__ B, + int k, int h, int w, int ntc, int tile, + const int* __restrict__ lanes, int lane_len, + const unsigned int* __restrict__ key, + int* __restrict__ out) { + extern __shared__ unsigned int s_tile[]; + int tr = tile / ntc; + int tc = tile % ntc; + fill_tile(A, B, k, h, w, tr, tc, s_tile); + __syncthreads(); + if (threadIdx.x == 0) { + unsigned int ticket[8]; + fold_and_hash(s_tile, lanes, lane_len, key, ticket); + out[0] = tr; + out[1] = tc; +#pragma unroll + for (int i = 0; i < 8; ++i) out[2 + i] = (int)ticket[i]; + } +} + +// ---- Host launcher ---- +// Returns {found (1,) i32, min_idx (1,) i32, latch (10,) i32 = tr,tc,ticket[8], +// tickets (num_tiles*8 or 0,) i32}. +std::vector fp16_search(torch::Tensor A, torch::Tensor B, + torch::Tensor lanes, torch::Tensor key, + torch::Tensor bound, long h, long w, int collect) { + TORCH_CHECK(A.is_cuda() && B.is_cuda(), "A and B must be CUDA tensors"); + TORCH_CHECK(A.scalar_type() == torch::kFloat16, "A must be float16"); + TORCH_CHECK(B.scalar_type() == torch::kFloat16, "B must be float16"); + TORCH_CHECK(A.dim() == 2 && B.dim() == 2, "A and B must be 2D"); + TORCH_CHECK(A.is_contiguous() && B.is_contiguous(), "A and B must be contiguous"); + TORCH_CHECK(lanes.is_cuda() && lanes.scalar_type() == torch::kInt32 && lanes.is_contiguous(), + "lanes must be a contiguous int32 CUDA tensor"); + TORCH_CHECK(key.is_cuda() && key.scalar_type() == torch::kInt32 && key.numel() == 8, + "key must be an int32 CUDA tensor of 8 words"); + TORCH_CHECK(bound.is_cuda() && bound.scalar_type() == torch::kInt32 && bound.numel() == 8, + "bound must be an int32 CUDA tensor of 8 words"); + long m = A.size(0), k = A.size(1); + long n = B.size(0), kb = B.size(1); + TORCH_CHECK(k == kb, "A and B must share k"); + TORCH_CHECK(k >= 1, "k must be >= 1"); + TORCH_CHECK(h >= 1 && w >= 1, "h and w must be >= 1"); + TORCH_CHECK(m % h == 0, "m must be a multiple of h"); + TORCH_CHECK(n % w == 0, "n must be a multiple of w"); + long hw = h * w; + TORCH_CHECK(hw % 16 == 0, "h*w must be a multiple of 16 (16 lanes)"); + long lane_len = hw / 16; + TORCH_CHECK(lanes.numel() == 16 * lane_len, "lanes must be 16 x (h*w/16)"); + long smem = hw * (long)sizeof(unsigned int); + TORCH_CHECK(smem <= 48 * 1024, "tile too large for 48 KB shared memory (h*w <= 12288)"); + + long ntr = m / h, ntc = n / w; + long num_tiles = ntr * ntc; + + auto i32 = torch::dtype(torch::kInt32).device(A.device()); + auto found = torch::zeros({1}, i32); + auto min_idx = torch::full({1}, (int)num_tiles, i32); + auto latch = torch::zeros({10}, i32); + auto tickets = torch::zeros({collect ? num_tiles * 8 : 0}, i32); + if (num_tiles == 0) return {found, min_idx, latch, tickets}; + + int threads = (int)min(hw, (long)256); + const __half* Ap = (const __half*)A.data_ptr(); + const __half* Bp = (const __half*)B.data_ptr(); + const int* lanes_p = (const int*)lanes.data_ptr(); + const unsigned int* key_p = (const unsigned int*)key.data_ptr(); + const unsigned int* bound_p = (const unsigned int*)bound.data_ptr(); + + search_scan_kernel<<>>( + Ap, Bp, (int)k, (int)h, (int)w, (int)ntc, lanes_p, (int)lane_len, key_p, bound_p, + (int*)found.data_ptr(), (int*)min_idx.data_ptr(), + (unsigned int*)tickets.data_ptr(), collect); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_search scan launch failed"); + + int found_h = found.cpu().item(); + if (found_h) { + int winner = min_idx.cpu().item(); + search_latch_kernel<<<1, threads, smem>>>( + Ap, Bp, (int)k, (int)h, (int)w, (int)ntc, winner, lanes_p, (int)lane_len, key_p, + (int*)latch.data_ptr()); + TORCH_CHECK(cudaGetLastError() == cudaSuccess, "fp16_search latch launch failed"); + } + return {found, min_idx, latch, tickets}; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, mod) { + mod.def("fp16_search", &fp16_search, + "A100 sm_80 full-matrix FP16 lottery search + first-winner latch", + pybind11::arg("A"), pybind11::arg("B"), pybind11::arg("lanes"), + pybind11::arg("key"), pybind11::arg("bound"), pybind11::arg("h"), + pybind11::arg("w"), pybind11::arg("collect")); +} diff --git a/miner/pearl-gemm/src/pearl_gemm/pow/_reset.py b/miner/pearl-gemm/src/pearl_gemm/pow/_reset.py index b7806f725..202a7a89b 100644 --- a/miner/pearl-gemm/src/pearl_gemm/pow/_reset.py +++ b/miner/pearl-gemm/src/pearl_gemm/pow/_reset.py @@ -13,8 +13,10 @@ from .._utils._stream import get_stream from ._hit_signal import HitRecordLayout -# Plain sys/gpu-scope atomics and fences: one source for every family. -_SUPPORTED_ARCHS = (Arch.SM90, Arch.SM100, Arch.SM120) +# Plain sys/gpu-scope atomics and fences (CAS, acquire load, acq_rel/sys +# fence -- all sm_70+), so one source serves every family -- including SM80 +# (A100), the FP16 scheme's target. +_SUPPORTED_ARCHS = (Arch.SM80, Arch.SM90, Arch.SM100, Arch.SM120) _reset_cache: dict[tuple, object] = {} diff --git a/miner/pearl-gemm/src/pearl_gemm/protocol_constants.py b/miner/pearl-gemm/src/pearl_gemm/protocol_constants.py index c4ecffc77..5429d6cb2 100644 --- a/miner/pearl-gemm/src/pearl_gemm/protocol_constants.py +++ b/miner/pearl-gemm/src/pearl_gemm/protocol_constants.py @@ -12,8 +12,21 @@ # enters the kernels only through the per-row alpha/beta scale constants. DELTA_SM90 = 1.0 DELTA_SM100 = 0.5 +# A100 (sm_80) HMMA.16816.F32 commits the Blackwell-strength half-noise: its +# FP32-accumulated FP16 tensor core carries a 24-bit window (W below), like +# Blackwell's 25-bit tcgen05 window and unlike Hopper's 13-bit QGMMA window. +DELTA_SM80 = 0.5 L2_ROUNDED_BITS = 2 # low explicit BF16 mantissa bits cleared from l2 +# A100 (sm_80) HMMA.16816.F32 FP16 accumulation model (the FP16 scheme's verifier +# replays it; see zk-pow/src/api/fp16/accumulate.rs). The k axis is split into +# groups of SM80_FP16_GROUP products; per group the products and the FP32 +# accumulator are truncated toward zero onto a 2^(eta - SM80_FP16_WINDOW) grid, +# summed exactly, then rounded toward zero to FP32. A plain sm_80 FP16 GEMM with +# FP32 accumulation and a pinned ascending-k reduction reproduces this natively. +SM80_FP16_WINDOW = 24 # internal accumulator significand bits (the "W" of the model) +SM80_FP16_GROUP = 8 # FP16 products per hardware accumulation group + # pre_quant BLOCK_SCALE_GROUP = 8 # int8 codes sharing one BF16 block scale along k @@ -27,6 +40,7 @@ # compute-capability majors of the architecture families the kernels target; # ``_utils/_arch.py`` is the gate and each host declares the families it runs on +SM80_CC_MAJOR = 8 # Ampere datacenter (A100/GA100): FP32-accumulated FP16 mma.sync SM90_CC_MAJOR = 9 # Hopper (H100/H200): WGMMA, register accumulators, promoted FP8 SM100_CC_MAJOR = 10 # datacenter Blackwell (B200/B300): tcgen05 UMMA + TMEM SM120_CC_MAJOR = 12 # workstation/consumer Blackwell (RTX PRO 6000, RTX 50): mma.sync tensor cores @@ -48,6 +62,8 @@ def delta_for_capability(device_capability: tuple[int, int]) -> float: major = device_capability[0] if major == SM90_CC_MAJOR: return DELTA_SM90 + if major == SM80_CC_MAJOR: + return DELTA_SM80 if major in (SM100_CC_MAJOR, SM120_CC_MAJOR): return DELTA_SM100 raise ValueError(f"no committed noise fraction for sm{major}{device_capability[1]}") diff --git a/miner/pearl-gemm/tests/helpers/a100_fp16_reference.py b/miner/pearl-gemm/tests/helpers/a100_fp16_reference.py new file mode 100644 index 000000000..ff89838c2 --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/a100_fp16_reference.py @@ -0,0 +1,165 @@ +"""Integer-exact Python port of the A100 (``sm_80``) ``HMMA.16816.F32`` FP16 +accumulation model. + +This mirrors ``zk-pow/src/api/fp16/accumulate.rs`` (``a100_dot`` / +``a100_matmul``) bit-for-bit and is the trusted oracle the on-GPU sm_80 GEMM is +validated against. The k axis is split into groups of ``GROUP = 8`` products; +per group ``eta = max(product stored-exp sums, accumulator stored exp clamped +>= -126)``; every product and the accumulator are truncated toward zero onto the +``2^(eta - W)`` grid (``W = 24``); the integers are summed exactly; the sum is +rounded toward zero to FP32 after every group. A zero result is ``+0``; +``|result| >= 2^128`` overflows. + +All arithmetic is done with Python ``int`` (unbounded), so the model is exact; +the final per-group result is encoded as an IEEE binary32 bit pattern directly, +so no host float rounding ever intervenes. +""" + +from __future__ import annotations + +import struct + +import numpy as np + +W = 24 # internal accumulator significand bits +GROUP = 8 # products per hardware accumulation group +_NEG = (-(2**31)) // 2 # sentinel "no exponent" (i32::MIN / 2 in the Rust model) +_FP32_MIN_EXP = -149 + + +def decompose_fp16(bits: int) -> tuple[int, int, int]: + """``(sign, significand, stored_exp)`` of an FP16 bit pattern. + + Matches ``dtype::decompose_fp16``: zero -> ``(1, 0, 0)``; subnormal -> + ``(sign, man, -14)``; normal -> ``(sign, 1024 | man, exp - 15)``. NaN/inf + (exponent field ``0x1F``) is rejected (never occurs in the scheme). + """ + bits &= 0xFFFF + exp = (bits >> 10) & 0x1F + man = bits & 0x03FF + if exp == 0x1F: + raise ValueError(f"FP16 NaN/inf encoding {bits:#06x} is not allowed") + sign = -1 if (bits & 0x8000) else 1 + if exp == 0 and man == 0: + return (1, 0, 0) + if exp == 0: + return (sign, man, -14) + return (sign, 0x400 | man, exp - 15) + + +def _acc_parts(c_bits: int) -> tuple[int, int, int, int]: + """``(sign, significand, stored_exp, ulp_exp)`` of an FP32 accumulator given + its u32 bit pattern. ``value = sign * significand * 2^ulp``; ``stored_exp`` + is ``_NEG`` for zero (does not participate in the alignment max).""" + c_bits &= 0xFFFFFFFF + sign = -1 if (c_bits >> 31) else 1 + exp_field = (c_bits >> 23) & 0xFF + man = c_bits & 0x7FFFFF + if exp_field == 0 and man == 0: + return (1, 0, _NEG, 0) + if exp_field == 0xFF: + raise ValueError("non-finite FP32 accumulator") + if exp_field > 0: + el = exp_field - 127 + return (sign, 0x800000 | man, el, el - 23) + # subnormal: value = man * 2^-149, stored exponent clamped to -126 + return (sign, man, -126, _FP32_MIN_EXP) + + +def _shift(x: int, s: int) -> int: + """``x`` shifted by ``s`` (left if positive, truncating-toward-zero right if + negative). Python ``>>`` floors, so operate on the magnitude.""" + if s >= 0: + return x << s + if -s >= 127: + return 0 + if x >= 0: + return x >> (-s) + return -((-x) >> (-s)) + + +def _rz_to_f32_bits(s: int, unit: int) -> int: + """Round the integer ``s * 2^unit`` toward zero to an FP32 value, returned as + its u32 bit pattern (24 significant bits; subnormals floored onto the + ``2^-149`` grid). Mirrors the Rust ``rz_to_f32`` exactly: after truncating + the magnitude to 24 significant bits (floored to the ``2^-149`` subnormal + grid), ``sign * truncated * 2^unit`` is an exact IEEE value (<=24 sig bits), + so the f64->f32 cast introduces no rounding.""" + if s == 0: + return 0 + sign = -1.0 if s < 0 else 1.0 + a = abs(s) + nb = a.bit_length() - 1 # floor(log2|s|) + keep = max(nb + unit - 23, _FP32_MIN_EXP) + drop = min(max(keep - unit, 0), 127) + truncated = (a >> drop) << drop + # Exact in f64 (truncated has <=24 significant bits), then exact down-cast. + val = np.float64(sign) * np.float64(truncated) * np.float64(2.0) ** np.float64(unit) + return int(np.float32(val).view(np.uint32)) + + +def a100_dot_bits(a: list[int], b: list[int], c_bits: int) -> int: + """A100 FP16 dot product of operand bit-pattern rows ``a`` and ``b`` with + FP32 carry-in ``c_bits`` (u32); returns the FP32 result as a u32 bit + pattern. Raises on overflow/non-finite (as the verifier aborts).""" + assert len(a) == len(b), "operand length mismatch" + cur = c_bits & 0xFFFFFFFF + k = len(a) + g0 = 0 + while g0 < k: + g1 = min(g0 + GROUP, k) + cs, cm, cel, culp = _acc_parts(cur) + eta = cel + for u in range(g0, g1): + _, ma, ea = decompose_fp16(a[u]) + _, mb, eb = decompose_fp16(b[u]) + if ma != 0 and mb != 0: + eta = max(eta, ea + eb) + if eta == _NEG: + g0 = g1 + continue + unit = eta - W + total = 0 + for u in range(g0, g1): + sa, ma, ea = decompose_fp16(a[u]) + sb, mb, eb = decompose_fp16(b[u]) + if ma == 0 or mb == 0: + continue + prod = ma * mb # < 2^22, exact + sh = (ea + eb) - 20 - unit # product LSB is 2^(ea+eb-20) + aligned = _shift(prod, sh) + total += (sa * sb) * aligned + csh = culp - unit + acc_aligned = _shift(cm, csh) + total += cs * acc_aligned + new_bits = _rz_to_f32_bits(total, unit) + if (new_bits >> 23) & 0xFF == 0xFF: + raise OverflowError("A100 accumulation overflowed to non-finite") + cur = new_bits + g0 = g1 + return cur & 0xFFFFFFFF + + +def a100_dot(a: list[int], b: list[int], c: float) -> float: + """Float wrapper around :func:`a100_dot_bits`.""" + c_bits = struct.unpack(" np.ndarray: + """Device matmul of ``m x k`` operand ``a`` against ``n x k`` operand ``b`` + (row-major FP16 bit patterns, ``uint16``), with optional ``m x n`` FP32 + carry-in (``uint32`` bits). Returns the ``m x n`` FP32 tile as ``uint32`` + bit patterns. ``b`` is the transposed logical operand (row j is column j).""" + a = np.asarray(a, dtype=np.uint16).reshape(m, k) + b = np.asarray(b, dtype=np.uint16).reshape(n, k) + out = np.zeros((m, n), dtype=np.uint32) + for i in range(m): + ai = a[i].tolist() + for j in range(n): + c_bits = int(acc[i, j]) if acc is not None else 0 + out[i, j] = a100_dot_bits(ai, b[j].tolist(), c_bits) + return out diff --git a/miner/pearl-gemm/tests/helpers/fp16_commit_reference.py b/miner/pearl-gemm/tests/helpers/fp16_commit_reference.py new file mode 100644 index 000000000..7e229afd0 --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/fp16_commit_reference.py @@ -0,0 +1,189 @@ +"""Pure-Python oracle for the FP16 operand keyed-BLAKE3 Merkle commitment. + +Faithful port of ``zk-pow/src/api/fp16/commitment.rs::commit_operand`` and the +``pearl_blake3::MerkleTree::with_chunk_len`` tree discipline it builds on: + +* The committed byte image is the FP16 rows as little-endian ``u16`` row-major + (``rows_to_bytes``), zero-padded up to a multiple of ``HashId::chunk_len`` + (``HashId::pad``). +* Leaves are fixed ``chunk_len``-byte chunks. Each leaf's hash is the keyed + BLAKE3 *non-root* chunk chaining value with the BLAKE3 chunk counter equal to + the leaf index (``Blake3Hasher::chunk_cv(chunk, i)``). Because every allowed + ``chunk_len`` (128/256/512/1024) is <= one native BLAKE3 chunk (1024), a leaf + is a single chunk of ``chunk_len/64`` full 64-byte blocks. +* Internal layers pair adjacent CVs with the keyed non-root parent compression + (``merge_subtrees_non_root``); a lone odd node is promoted unchanged. When a + layer has reduced to exactly two nodes the root is their keyed *root*-finalized + parent compression (``merge_subtrees_root``). +* A single-leaf tree (padded image <= chunk_len) is special: its root is the + ROOT-finalized keyed hash of the chunk itself, not a non-root chunk CV. + +This is an independent BLAKE3 implementation (compression written from the spec) +so it cross-checks tree structure against the Rust oracle without sharing code +with the ``blake3`` crate. It is the trusted model for the ``sm_80`` kernel. +""" + +from __future__ import annotations + +# ---- BLAKE3 domain-separation flags (match pearl_blake3::hasher) ---- +CHUNK_START = 1 +CHUNK_END = 2 +PARENT = 4 +ROOT = 8 +KEYED_HASH = 16 + +CHUNK_LEN = 1024 +OUT_LEN = 32 + +IV = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +] + +_MASK = 0xFFFFFFFF +_PERM = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8] + +ALLOWED_CHUNK_LENS = (128, 256, 512, 1024) + + +def _rotr32(x: int, n: int) -> int: + x &= _MASK + return ((x >> n) | (x << (32 - n))) & _MASK + + +def _compress(cv, block, counter, block_len, flags): + """One BLAKE3 compression. Returns the 16-word output state. + + ``cv`` is 8 words, ``block`` is 16 message words, ``counter`` a 64-bit int. + The first 8 output words are the chaining value / 32-byte hash output. + """ + s = [ + cv[0], cv[1], cv[2], cv[3], cv[4], cv[5], cv[6], cv[7], + IV[0], IV[1], IV[2], IV[3], + counter & _MASK, (counter >> 32) & _MASK, block_len & _MASK, flags & _MASK, + ] + v = list(block) + + def g(a, b, c, d, x, y): + s[a] = (s[a] + s[b] + x) & _MASK + s[d] = _rotr32(s[d] ^ s[a], 16) + s[c] = (s[c] + s[d]) & _MASK + s[b] = _rotr32(s[b] ^ s[c], 12) + s[a] = (s[a] + s[b] + y) & _MASK + s[d] = _rotr32(s[d] ^ s[a], 8) + s[c] = (s[c] + s[d]) & _MASK + s[b] = _rotr32(s[b] ^ s[c], 7) + + for rnd in range(7): + g(0, 4, 8, 12, v[0], v[1]) + g(1, 5, 9, 13, v[2], v[3]) + g(2, 6, 10, 14, v[4], v[5]) + g(3, 7, 11, 15, v[6], v[7]) + g(0, 5, 10, 15, v[8], v[9]) + g(1, 6, 11, 12, v[10], v[11]) + g(2, 7, 8, 13, v[12], v[13]) + g(3, 4, 9, 14, v[14], v[15]) + if rnd < 6: + v = [v[_PERM[i]] for i in range(16)] + + out = [0] * 16 + for i in range(8): + out[i] = (s[i] ^ s[i + 8]) & _MASK + out[i + 8] = (s[i + 8] ^ cv[i]) & _MASK + return out + + +def _key_words(key: bytes) -> list[int]: + assert len(key) == 32 + return [int.from_bytes(key[4 * i:4 * i + 4], "little") for i in range(8)] + + +def _blocks_of(data: bytes) -> list[list[int]]: + """Split ``data`` (length a multiple of 64) into 64-byte blocks of 16 LE words.""" + assert len(data) % 64 == 0 + blocks = [] + for off in range(0, len(data), 64): + blk = data[off:off + 64] + blocks.append([int.from_bytes(blk[4 * w:4 * w + 4], "little") for w in range(16)]) + return blocks + + +def _chunk_cv(data: bytes, chunk_index: int, key_words: list[int], root: bool) -> list[int]: + """Keyed BLAKE3 chunk chaining value (``root`` toggles ROOT finalization). + + ``data`` is one leaf's bytes, length a multiple of 64 and <= 1024. + """ + blocks = _blocks_of(data) + cv = list(key_words) + n = len(blocks) + for i, blk in enumerate(blocks): + flags = KEYED_HASH + if i == 0: + flags |= CHUNK_START + if i == n - 1: + flags |= CHUNK_END + if root: + flags |= ROOT + out = _compress(cv, blk, chunk_index, 64, flags) + cv = out[:8] + return cv + + +def _parent(left: list[int], right: list[int], key_words: list[int], root: bool) -> list[int]: + msg = list(left) + list(right) + flags = KEYED_HASH | PARENT | (ROOT if root else 0) + out = _compress(key_words, msg, 0, 64, flags) + return out[:8] + + +def _words_to_bytes(words: list[int]) -> bytes: + return b"".join(int(w & _MASK).to_bytes(4, "little") for w in words[:8]) + + +def rows_to_bytes(rows) -> bytes: + """Little-endian ``u16`` row-major byte image of the FP16 operand.""" + import numpy as np + + arr = np.asarray(rows, dtype=np.uint16).reshape(-1) + return arr.astype(" bytes: + rem = len(data) % chunk_len + if rem: + data = data + b"\x00" * (chunk_len - rem) + return data + + +def commit_operand_root(rows, num_rows: int, k: int, key: bytes, chunk_len: int = 1024) -> bytes: + """Return the 32-byte keyed-BLAKE3 Merkle root of the FP16 operand. + + Mirrors ``commit_operand(rows, num_rows, k, HashId::from(chunk_len), key)``. + """ + assert chunk_len in ALLOWED_CHUNK_LENS, chunk_len + kw = _key_words(key) + data = pad(rows_to_bytes(rows), chunk_len) + + if len(data) == 0: + return b"\x00" * 32 + if len(data) <= chunk_len: + # Single-leaf tree: ROOT-finalized keyed hash of the (one) chunk. + return _words_to_bytes(_chunk_cv(data, 0, kw, root=True)) + + # Leaf layer: one non-root chunk CV per chunk_len-byte leaf. + num_leaves = len(data) // chunk_len + layer = [ + _chunk_cv(data[i * chunk_len:(i + 1) * chunk_len], i, kw, root=False) + for i in range(num_leaves) + ] + # Reduce pairwise (promote lone odd node) until exactly two remain. + while len(layer) > 2: + nxt = [] + for i in range(0, len(layer), 2): + if i + 1 < len(layer): + nxt.append(_parent(layer[i], layer[i + 1], kw, root=False)) + else: + nxt.append(layer[i]) + layer = nxt + # Final combine is ROOT-finalized. + return _words_to_bytes(_parent(layer[0], layer[1], kw, root=True)) diff --git a/miner/pearl-gemm/tests/helpers/fp16_noise_lines_reference.py b/miner/pearl-gemm/tests/helpers/fp16_noise_lines_reference.py new file mode 100644 index 000000000..b97a58fd7 --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/fp16_noise_lines_reference.py @@ -0,0 +1,87 @@ +"""Integer/float-exact Python port of the FP16 scheme's deterministic noise-line +generation (``zk-pow/src/api/fp16/noise.rs``: ``sample_line`` / ``sample_noise``). + +The trusted oracle the on-GPU ``sm_80`` ``fp16_noise_lines`` kernel is validated +against. The keyed-BLAKE3 XOF uses the same ``blake3`` crate the reference +hashes with; every BF16/FP16 rounding matches the Rust helpers +(``crate::api::fp8::{compute,dtype}``, ``fp16::dtype``) bit-for-bit, and the L2 +normalization uses the exact integer ``isqrt`` + one-BF16-division recipe. +""" + +from __future__ import annotations + +import math + +import blake3 +import numpy as np + +from .fp16_noisy_quant_reference import ( + bf16_div, + bf16_mul, + bf16_to_f32, + f32_to_bf16, + f32_to_fp16, +) + +LABEL_NOISE_LINE = b"pearl/v4/FP16/noise-line" +INT_SQRT_PREC = 32 +NOISE_TARGET_NORM = 256.0 + +SIDE_A, SIDE_B = 0, 1 +FACTOR_E, FACTOR_F = 0, 1 + + +def line_key(seed: bytes) -> bytes: + """``subkey(LABEL_NOISE_LINE, seed)`` = keyed BLAKE3 of the label under seed.""" + assert len(seed) == 32 + return blake3.blake3(LABEL_NOISE_LINE, key=seed).digest(length=32) + + +def xof_bytes(seed: bytes, side: int, factor: int, line: int, r: int) -> bytes: + """The raw keyed-BLAKE3-XOF bytes of one line (``sample_line_xof_bytes``).""" + material = bytes([side & 0xFF, factor & 0xFF]) + int(line).to_bytes(4, "little") + assert len(material) <= 64 + material = material.ljust(64, b"\x00") + return blake3.blake3(material, key=line_key(seed)).digest(length=r) + + +def normalize_line(byts: bytes) -> np.ndarray: + """Decode + L2-normalize XOF bytes to FP16 ``u16`` (``normalize_line``).""" + xs = [] + sumsq = 0 + for b in byts: + sign = 1 - 2 * (b >> 7) + mag = (b & 0x7F) + 1 + xs.append(sign * mag) + sumsq += mag * mag + norm_scaled = math.isqrt(sumsq * (INT_SQRT_PREC * INT_SQRT_PREC)) # exact floor isqrt + numer = f32_to_bf16(np.float32(NOISE_TARGET_NORM * INT_SQRT_PREC)) # 8192, exact bf16 + denom = f32_to_bf16(np.float32(float(norm_scaled))) + scale = bf16_div(numer, denom) + out = np.empty(len(byts), dtype=np.uint16) + for i, xi in enumerate(xs): + xb = f32_to_bf16(np.float32(float(xi))) + entry = bf16_mul(xb, scale) + out[i] = f32_to_fp16(bf16_to_f32(entry)) + return out + + +def sample_line(seed: bytes, side: int, factor: int, line: int, r: int) -> np.ndarray: + return normalize_line(xof_bytes(seed, side, factor, line, r)) + + +def noise_lines(seed: bytes, side: int, factor: int, indices, r: int) -> np.ndarray: + """``(len(indices), r)`` ``u16`` FP16 lines, row ``i`` = ``sample_line(... indices[i])``.""" + rows = [sample_line(seed, side, factor, int(idx), r) for idx in indices] + if not rows: + return np.empty((0, r), dtype=np.uint16) + return np.stack(rows) + + +def sample_noise(seed_a: bytes, seed_b: bytes, k: int, r: int, a_rows, b_cols): + """``(e_a, f_a, e_b, f_b)`` matching the reference ``sample_noise`` layout.""" + e_a = noise_lines(seed_a, SIDE_A, FACTOR_E, a_rows, r) + e_b = noise_lines(seed_b, SIDE_B, FACTOR_E, b_cols, r) + f_a = noise_lines(seed_b, SIDE_A, FACTOR_F, range(k), r) + f_b = noise_lines(seed_b, SIDE_B, FACTOR_F, range(k), r) + return e_a, f_a, e_b, f_b diff --git a/miner/pearl-gemm/tests/helpers/fp16_noisy_quant_reference.py b/miner/pearl-gemm/tests/helpers/fp16_noisy_quant_reference.py new file mode 100644 index 000000000..4d91743fc --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/fp16_noisy_quant_reference.py @@ -0,0 +1,175 @@ +"""Integer/float-exact Python port of the FP16 scheme's fused noisy quantize +(``zk-pow/src/api/fp16/quantization.rs``). + +The trusted oracle the on-GPU sm_80 ``fp16_noisy_quant`` kernels are validated +against. Every BF16/FP16 rounding matches the Rust helpers +(``crate::api::fp8::{compute,dtype}``, ``fp16::dtype``, ``prequant``) bit-for-bit; +the ``E@F^T`` noise reuses :func:`a100_matmul_bits` (the committed A100 datapath). +""" + +from __future__ import annotations + +import math +from fractions import Fraction + +import numpy as np + +from .a100_fp16_reference import a100_matmul_bits + +MAX_FP16 = 65504.0 +DELTA = 0.5 +NORM_FLOOR = 1.0 / 4294967296.0 # 2^-32 +NOISE_TARGET_NORM = 256.0 + + +# ---- dtype conversions ---- + +def fp16_to_f32(bits: int) -> np.float32: + return np.float32(np.uint16(bits).view(np.float16)) + + +def f32_to_fp16(x: np.float32) -> int: + """RNE f32 -> FP16 (input assumed finite and in range).""" + return int(np.float32(x).astype(np.float16).view(np.uint16)) + + +def bf16_to_f32(bits: int) -> np.float32: + return np.uint32(np.uint32(bits) << np.uint32(16)).view(np.float32) + + +def f32_to_bf16(x: np.float32) -> int: + """RNE f32 -> BF16, matching ``dtype::f32_to_bf16``.""" + bits = int(np.float32(x).view(np.uint32)) + round_bit = (bits >> 16) & 1 + return ((bits + 0x7FFF + round_bit) >> 16) & 0xFFFF + + +# ---- BF16 element-wise ops (compute.rs) ---- + +def bf16_mul(a: int, b: int) -> int: + return f32_to_bf16(np.float32(bf16_to_f32(a) * bf16_to_f32(b))) + + +def bf16_div(a: int, b: int) -> int: + return f32_to_bf16(np.float32(bf16_to_f32(a) / bf16_to_f32(b))) + + +def bf16_max(a: int, b: int) -> int: + return a if bf16_to_f32(a) >= bf16_to_f32(b) else b + + +def _round_to_odd_f32(s: float, residual: float) -> np.float32: + """Correctly-rounded f32 of the exact real ``s + residual`` via round-to-odd + (``s`` already the f64 RNE approximation; ``residual`` the exact f64 tail).""" + s32 = np.float32(s) + err = (s - float(s32)) + residual # sign(x - s32); nonzero iff x != s32 + if err != 0.0 and (int(s32.view(np.uint32)) & 1) == 0 and np.isfinite(s32): + direction = np.float32(np.inf) if err > 0.0 else np.float32(-np.inf) + return np.nextafter(s32, direction) + return s32 + + +def bf16_fma(a: int, b: int, c: int) -> int: + """Single-rounding ``a*b + c`` in BF16 (``compute::bf16_fma``).""" + a64 = float(bf16_to_f32(a)) + b64 = float(bf16_to_f32(b)) + c64 = float(bf16_to_f32(c)) + p = a64 * b64 # exact (two 8-bit significands) + s = p + c64 + t = s - c64 + r = (p - t) + (c64 - (s - t)) # TwoSum residual, exact + return f32_to_bf16(_round_to_odd_f32(s, r)) + + +def round_l2_to_grid(l2: int) -> int: + """``prequant::round_l2_to_grid``: round to nearest multiple of 4 ulps, ties up.""" + return (l2 + 2) & ~3 & 0xFFFF + + +# ---- per-row norms + scales ---- + +def row_norms(row: np.ndarray) -> tuple[int, int]: + """``(l2, linf)`` BF16 bits for an FP16 row (uint16), matching ``row_norms``.""" + k = len(row) + sumsq = np.float32(0.0) + absmax = np.float32(0.0) + for bits in row: + v = fp16_to_f32(int(bits)) + sumsq = np.float32(sumsq + np.float32(v * v)) # sequential f32 fold + absmax = np.float32(max(absmax, abs(v))) + l2 = round_l2_to_grid(f32_to_bf16(np.float32(np.sqrt(np.float32(sumsq / np.float32(k)))))) + linf = f32_to_bf16(absmax) + return l2, linf + + +def derive_row_scales(l2: int, linf: int, r: int) -> tuple[int, int]: + max_fp16 = f32_to_bf16(np.float32(MAX_FP16)) + delta_r = f32_to_bf16(np.float32(DELTA * math.sqrt(r))) + delta_over_std = f32_to_bf16( + np.float32(DELTA * math.sqrt(r) / (NOISE_TARGET_NORM * NOISE_TARGET_NORM)) + ) + noised_bound = bf16_fma(delta_r, l2, linf) + alpha = bf16_div(max_fp16, noised_bound) + beta = bf16_mul(bf16_mul(alpha, l2), delta_over_std) + return alpha, beta + + +def _rne_f32(fr: Fraction) -> np.float32: + """Correctly-rounded (RNE, ties-to-even) f32 of an exact rational, checking + the +-1 ULP neighbours of the f64 approximation (the true nearest is always + among them).""" + c0 = np.float32(float(fr)) + best, best_key = None, None + for c in (np.nextafter(c0, np.float32(-np.inf)), c0, np.nextafter(c0, np.float32(np.inf))): + dist = abs(Fraction(float(c)) - fr) + key = (dist, int(np.float32(c).view(np.uint32)) & 1) # tie -> even last bit + if best_key is None or key < best_key: + best, best_key = c, key + return best + + +def _fma_f32(af: np.float32, x: np.float32, bn: np.float32) -> np.float32: + """Correctly-rounded (RNE) f32 ``af*x + bn`` -- Rust ``f32::mul_add``. + + A true f32 FMA, so the caller's subsequent RNE to FP16 double-rounds exactly + as Rust (``mul_add`` then ``f32 -> f16``) and the GPU (``fmaf`` then + ``__float2half_rn``) do; round-to-odd here would diverge in ties. + """ + exact = Fraction(float(af)) * Fraction(float(x)) + Fraction(float(bn)) + return _rne_f32(exact) + + +def noisy_quantize( + rows: np.ndarray, e: np.ndarray, f: np.ndarray, norms: list[tuple[int, int]], r: int +) -> dict: + """Returns ``{noised, alpha, beta, l2}`` (all uint16 arrays).""" + num_rows = len(norms) + k = rows.shape[1] + rows_bits = np.ascontiguousarray(rows).view(np.uint16).reshape(num_rows, k) + floor = f32_to_bf16(np.float32(NORM_FLOOR)) + # N = E @ F^T on the committed A100 FP16 datapath (f32 bits -> f32). + noise_bits = a100_matmul_bits( + e.reshape(-1).view(np.uint16), f.reshape(-1).view(np.uint16), num_rows, k, r + ) + noise = noise_bits.view(np.float32).reshape(num_rows, k) + + noised = np.zeros((num_rows, k), dtype=np.uint16) + alphas = np.zeros(num_rows, dtype=np.uint16) + betas = np.zeros(num_rows, dtype=np.uint16) + l2s = np.zeros(num_rows, dtype=np.uint16) + for i in range(num_rows): + l2 = bf16_max(norms[i][0], floor) + linf = bf16_max(norms[i][1], floor) + alpha, beta = derive_row_scales(l2, linf, r) + af = bf16_to_f32(alpha) + bf = bf16_to_f32(beta) + for j in range(k): + x = fp16_to_f32(int(rows_bits[i, j])) + bn = np.float32(bf * np.float32(noise[i, j])) + val = float(_fma_f32(af, x, bn)) + clamped = min(max(val, -MAX_FP16), MAX_FP16) + noised[i, j] = f32_to_fp16(np.float32(clamped)) + alphas[i] = alpha + betas[i] = beta + l2s[i] = l2 + return {"noised": noised, "alpha": alphas, "beta": betas, "l2": l2s} diff --git a/miner/pearl-gemm/tests/helpers/fp16_pipeline_reference.py b/miner/pearl-gemm/tests/helpers/fp16_pipeline_reference.py new file mode 100644 index 000000000..094384afc --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/fp16_pipeline_reference.py @@ -0,0 +1,223 @@ +"""Independent Python port of the FP16 scheme's end-to-end tile verification +(``zk-pow/src/api/fp16/verify.rs::verify_tile`` / ``verify_tile_proof``). + +The trusted oracle the on-GPU sm_80 :mod:`pearl_gemm.fp16_pipeline` driver is +validated against. The numeric datapath reuses the sibling reference oracles +(:mod:`fp16_noisy_quant_reference`, :mod:`fp16_policy_reference`, whose matmuls +are the committed A100 datapath); the scheme-neutral lottery extractor (mixed- +radix lane assignment, XOR-fold message, keyed-BLAKE3 jackpot ticket, difficulty +check) is reimplemented here from scratch -- deliberately not importing the +driver's ``_layout``, so the two agree only if both match the Rust verifier. +""" + +from __future__ import annotations + +import struct +from dataclasses import dataclass +from fractions import Fraction + +import blake3 +import numpy as np + +from .a100_fp16_reference import a100_matmul_bits +from .fp16_noisy_quant_reference import ( + MAX_FP16, + NORM_FLOOR, + bf16_max, + bf16_to_f32, + derive_row_scales, + f32_to_bf16, + f32_to_fp16, + fp16_to_f32, +) +from .fp16_noisy_quant_reference import row_norms as ref_row_norms +from .fp16_policy_reference import PolicyReport +from .fp16_policy_reference import replay_and_evaluate as ref_replay_and_evaluate + +# DimType discriminants and the FP8/v4 jackpot label (shared transcript). +NULL, FOLD, BLAKE = 0, 1, 2 +LABEL_JACKPOT = b"pearl/v4/FP8/jackpot" +JACKPOT_ENTRIES = 16 +_U32 = 0xFFFFFFFF + + +@dataclass(frozen=True) +class AxisPattern: + """Canonical mixed-radix axis pattern (``crate::api::layout::AxisPattern``).""" + + dims: tuple[tuple[int, int], ...] + + @staticmethod + def new(dims) -> "AxisPattern": + canon: list[list[int]] = [] + for length, t in dims: + if length == 1: + continue + if canon and canon[-1][1] == t: + canon[-1][0] *= length + else: + canon.append([length, t]) + return AxisPattern(tuple((l, t) for l, t in canon)) + + def _offsets(self, keep) -> list[int]: + offs, stride = [0], 1 + for length, t in self.dims: + if keep(t): + base = len(offs) + for d in range(1, length): + offs.extend(offs[i] + d * stride for i in range(base)) + stride *= length + return offs + + def fold_offsets(self): + return self._offsets(lambda t: t == FOLD) + + def blake_offsets(self): + return self._offsets(lambda t: t == BLAKE) + + def tile_offsets(self): + return self._offsets(lambda t: t != NULL) + + def tile_size(self) -> int: + n = 1 + for length, t in self.dims: + if t != NULL: + n *= length + return n + + +def lane_assignment(rows: AxisPattern, cols: AxisPattern) -> list[list[int]]: + def subtile_positions(axis: AxisPattern): + tile = axis.tile_offsets() + fold = axis.fold_offsets() + pos = {o: i for i, o in enumerate(tile)} + return [[pos[a + b] for a in fold] for b in axis.blake_offsets()] + + rsub = subtile_positions(rows) + csub = subtile_positions(cols) + n_cols = cols.tile_size() + return [[r * n_cols + c for r in rs for c in cs] for rs in rsub for cs in csub] + + +def xor_fold_extract(tile_bits, lanes: list[list[int]]) -> bytes: + out = bytearray(4 * JACKPOT_ENTRIES) + for li, idxs in enumerate(lanes): + acc = 0 + for i in idxs: + acc = (acc * 0x9E3779B1) & _U32 + acc = (acc + (int(tile_bits[i]) & _U32)) & _U32 + acc = ((acc << 13) | (acc >> 19)) & _U32 + out[li * 4 : li * 4 + 4] = struct.pack(" bytes: + subkey = blake3.blake3(LABEL_JACKPOT, key=seed_a).digest(length=32) + return blake3.blake3(message, key=subkey).digest(length=32) + + +def nbits_to_difficulty(nbits: int) -> int: + exp, mant = nbits >> 24, nbits & 0x00FFFFFF + if mant == 0 or exp == 0 or (mant & 0x00800000): + return 0 + return mant >> (8 * (3 - exp)) if exp <= 3 else (mant << (8 * (exp - 3))) & ((1 << 256) - 1) + + +def check_jackpot_difficulty(jackpot: bytes, nbits: int, h: int, w: int, k: int) -> bool: + umax = (1 << 256) - 1 + target = nbits_to_difficulty(nbits) + adj = min(h * w * k, 0xFFFFFFFF) + bound = umax if adj != 0 and target > umax // adj else target * adj + return int.from_bytes(jackpot, "little") <= bound + + +def _rne_f32(fr: Fraction) -> np.float32: + """Correctly-rounded (RNE, ties-to-even) f32 of an exact rational, checking + the +-1 ULP neighbours of the f64 approximation (double-rounding error is at + most one f32 ULP, so the true nearest is always among them).""" + c0 = np.float32(float(fr)) + up = np.nextafter(c0, np.float32(np.inf)) + dn = np.nextafter(c0, np.float32(-np.inf)) + best, best_key = None, None + for c in (dn, c0, up): + dist = abs(Fraction(float(c)) - fr) + key = (dist, int(np.float32(c).view(np.uint32)) & 1) # tie -> even last bit + if best_key is None or key < best_key: + best, best_key = c, key + return best + + +def _noised_operand(rows16: np.ndarray, e16: np.ndarray, f16: np.ndarray, r: int) -> np.ndarray: + """Rebuild one noised FP16 operand with Rust's exact two-step rounding: + ``code = RNE_f16(clamp(RNE_f32(alpha*x + RNE_f32(beta*N))))`` -- a single + f32 FMA (RNE) followed by an independent RNE to FP16 (so double-rounding + ties resolve exactly as ``f32::mul_add`` then ``f32 -> f16`` do).""" + num_rows, k = rows16.shape + floor = f32_to_bf16(np.float32(NORM_FLOOR)) + noise = ( + a100_matmul_bits(e16.reshape(-1), f16.reshape(-1), num_rows, k, r) + .view(np.float32) + .reshape(num_rows, k) + ) + out = np.zeros((num_rows, k), dtype=np.uint16) + for i in range(num_rows): + l2 = bf16_max(int(ref_row_norms(rows16[i])[0]), floor) + linf = bf16_max(int(ref_row_norms(rows16[i])[1]), floor) + alpha, beta = derive_row_scales(l2, linf, r) + af = np.float32(bf16_to_f32(alpha)) + bf = np.float32(bf16_to_f32(beta)) + for j in range(k): + x = np.float16(np.uint16(rows16[i, j]).view(np.float16)) + bn = np.float32(bf * np.float32(noise[i, j])) # f32 product, RNE + exact = Fraction(float(af)) * Fraction(float(x)) + Fraction(float(bn)) + val = float(_rne_f32(exact)) # single RNE to f32 == mul_add + clamped = min(max(val, -MAX_FP16), MAX_FP16) + out[i, j] = f32_to_fp16(np.float32(clamped)) # independent RNE to f16 + return out + + +@dataclass +class TileVerify: + tile_bits: np.ndarray # (h, w) uint32 f32 bit patterns + report: PolicyReport + message: bytes + ticket: bytes + built_a: np.ndarray # (h, k) uint16 + built_b: np.ndarray # (w, k) uint16 + + +def verify_tile( + a_rows: np.ndarray, + b_rows: np.ndarray, + e_a: np.ndarray, + f_a: np.ndarray, + e_b: np.ndarray, + f_b: np.ndarray, + rows_pattern: AxisPattern, + cols_pattern: AxisPattern, + seed_a: bytes, + r: int, +) -> TileVerify: + """Reproduces ``verify_tile``: rebuild both noised operands, replay+score the + tile, then fold the lottery ticket. ``a_rows`` ``(h, k)`` and ``b_rows`` + ``(w, k)`` are FP16 arrays (float16 or uint16 bit patterns); ``e_*``/``f_*`` + are the FP16 noise factors. Does *not* raise on a rejecting tile.""" + a16 = np.asarray(a_rows).view(np.uint16) if a_rows.dtype == np.float16 else np.asarray(a_rows, np.uint16) + b16 = np.asarray(b_rows).view(np.uint16) if b_rows.dtype == np.float16 else np.asarray(b_rows, np.uint16) + h, k = a16.shape + w, _ = b16.shape + + e_a16 = np.asarray(e_a).view(np.uint16) if np.asarray(e_a).dtype == np.float16 else np.asarray(e_a, np.uint16) + f_a16 = np.asarray(f_a).view(np.uint16) if np.asarray(f_a).dtype == np.float16 else np.asarray(f_a, np.uint16) + e_b16 = np.asarray(e_b).view(np.uint16) if np.asarray(e_b).dtype == np.float16 else np.asarray(e_b, np.uint16) + f_b16 = np.asarray(f_b).view(np.uint16) if np.asarray(f_b).dtype == np.float16 else np.asarray(f_b, np.uint16) + na = _noised_operand(a16, e_a16.reshape(h, r), f_a16.reshape(k, r), r) + nb = _noised_operand(b16, e_b16.reshape(w, r), f_b16.reshape(k, r), r) + + tile_bits, _percell, report = ref_replay_and_evaluate(na, nb, h, w, k) + + lanes = lane_assignment(rows_pattern, cols_pattern) + message = xor_fold_extract(tile_bits.reshape(-1), lanes) + ticket = compute_jackpot_ticket(seed_a, message) + return TileVerify(tile_bits=tile_bits, report=report, message=message, ticket=ticket, + built_a=na, built_b=nb) diff --git a/miner/pearl-gemm/tests/helpers/fp16_policy_reference.py b/miner/pearl-gemm/tests/helpers/fp16_policy_reference.py new file mode 100644 index 000000000..577dfd42e --- /dev/null +++ b/miner/pearl-gemm/tests/helpers/fp16_policy_reference.py @@ -0,0 +1,167 @@ +"""Integer-exact Python port of the FP16 "unpredictable accumulation steps" +jackpot policy (``zk-pow/src/api/fp16/policy.rs``). + +Extends the trusted A100 accumulation oracle (:mod:`tests.helpers.a100_fp16_reference`) +with the per-group census ``a100_dot`` records when ``census = Some`` and the +``evaluate`` reduction over a tile. It is the oracle the on-GPU sm_80 +``fp16_policy`` kernel is validated against. + +Per group of ``GROUP = 8`` products the census records a ``PolicyStep``: + +* ``breakpoint`` -- the accumulator alignment OR the final FP32 round-toward-zero + discarded a nonzero bit (``acc_truncated || rz_dropped``); +* ``products_truncated`` -- how many of the group's products lost nonzero bits in + their right-shift alignment. + +Empty no-op groups push a default step (``breakpoint = False``, +``products_truncated = 0``). ``evaluate`` then, per cell, counts breakpoint steps +(``n_bp``), maximal runs of non-breakpoint steps (``n_runs``; empty no-ops extend +the surrounding run), and sums ``products_truncated`` over non-breakpoint steps +(``n_pt``), and aggregates ``f_bp`` and ``rho`` in f64. +""" + +from __future__ import annotations + +import struct +from dataclasses import dataclass + +import numpy as np + +from tests.helpers.a100_fp16_reference import ( + GROUP, + W, + _NEG, + _acc_parts, + _rz_to_f32_bits, + _shift, + decompose_fp16, +) + +NOISE_RANK = 32 +MIN_FBP = 0.30 +MIN_RHO = 1.2 + + +@dataclass +class PolicyStep: + breakpoint: bool + products_truncated: int + + +@dataclass +class PolicyReport: + f_bp: float + rho: float + accept: bool + breakpoints: int + numerator: int + + +def a100_dot_census(a: list[int], b: list[int], c_bits: int = 0) -> tuple[int, list[PolicyStep]]: + """A100 FP16 dot product with per-group census. + + Returns ``(d_bits, steps)``: the FP32 result u32 bit pattern and one + :class:`PolicyStep` per group of 8 (empty groups included). Mirrors + ``accumulate::a100_dot`` with ``census = Some`` exactly. + """ + assert len(a) == len(b), "operand length mismatch" + cur = c_bits & 0xFFFFFFFF + k = len(a) + steps: list[PolicyStep] = [] + g0 = 0 + while g0 < k: + g1 = min(g0 + GROUP, k) + cs, cm, cel, culp = _acc_parts(cur) + eta = cel + for u in range(g0, g1): + _, ma, ea = decompose_fp16(a[u]) + _, mb, eb = decompose_fp16(b[u]) + if ma != 0 and mb != 0: + eta = max(eta, ea + eb) + if eta == _NEG: + steps.append(PolicyStep(breakpoint=False, products_truncated=0)) + g0 = g1 + continue + unit = eta - W + total = 0 + products_truncated = 0 + for u in range(g0, g1): + sa, ma, ea = decompose_fp16(a[u]) + sb, mb, eb = decompose_fp16(b[u]) + if ma == 0 or mb == 0: + continue + prod = ma * mb + sh = (ea + eb) - 20 - unit + aligned = _shift(prod, sh) + if sh < 0 and (prod & ((1 << min(-sh, 126)) - 1)) != 0: + products_truncated += 1 + total += (sa * sb) * aligned + csh = culp - unit + acc_aligned = _shift(cm, csh) + acc_truncated = csh < 0 and cm != 0 and (cm & ((1 << min(-csh, 126)) - 1)) != 0 + total += cs * acc_aligned + new_bits = _rz_to_f32_bits(total, unit) + # rz dropped a nonzero bit iff the result differs from the exact sum. + new_val = struct.unpack(" tuple[int, int, int]: + """``(n_bp, n_runs, n_pt)`` for one cell, mirroring ``evaluate``'s inner loop.""" + n_bp = n_pt = n_runs = 0 + in_run = False + for s in steps: + if s.breakpoint: + n_bp += 1 + in_run = False + else: + n_pt += s.products_truncated + if not in_run: + n_runs += 1 + in_run = True + return n_bp, n_runs, n_pt + + +def evaluate(percell: list[tuple[int, int, int]], cells: int, k: int) -> PolicyReport: + """Fold per-cell ``(n_bp, n_runs, n_pt)`` into the tile report (``evaluate``).""" + assert cells > 0 and k > 0, "empty tile" + steps_per_cell = -(-k // GROUP) # ceil + breakpoints = sum(nb for nb, _, _ in percell) + numerator = sum(GROUP * nb + NOISE_RANK * nr + npt for nb, nr, npt in percell) + f_bp = breakpoints / float(cells * steps_per_cell) + rho = numerator / float(cells * k) + return PolicyReport( + f_bp=f_bp, + rho=rho, + accept=f_bp >= MIN_FBP and rho >= MIN_RHO, + breakpoints=breakpoints, + numerator=numerator, + ) + + +def replay_and_evaluate( + a: np.ndarray, b: np.ndarray, m: int, n: int, k: int +) -> tuple[np.ndarray, np.ndarray, PolicyReport]: + """Device-order replay + policy evaluation of the ``m x n`` tile ``a @ b.T``. + + ``a`` is ``(m, k)`` and ``b`` is ``(n, k)`` FP16 bit patterns (``uint16``). + Returns ``(tile_bits, percell, report)``: the ``(m, n)`` u32 tile bits, the + ``(m*n, 3)`` int per-cell ``(n_bp, n_runs, n_pt)`` census, and the report. + """ + a = np.asarray(a, dtype=np.uint16).reshape(m, k) + b = np.asarray(b, dtype=np.uint16).reshape(n, k) + tile = np.zeros((m, n), dtype=np.uint32) + percell: list[tuple[int, int, int]] = [] + for i in range(m): + ai = a[i].tolist() + for j in range(n): + d_bits, steps = a100_dot_census(ai, b[j].tolist(), 0) + tile[i, j] = d_bits + percell.append(cell_counts(steps)) + report = evaluate(percell, m * n, k) + return tile, np.asarray(percell, dtype=np.int64), report diff --git a/miner/pearl-gemm/tests/test_arch.py b/miner/pearl-gemm/tests/test_arch.py index e7f869337..754c5e7c2 100644 --- a/miner/pearl-gemm/tests/test_arch.py +++ b/miner/pearl-gemm/tests/test_arch.py @@ -4,12 +4,18 @@ import torch from pearl_gemm._utils._arch import Arch, arch_of, require_arch -from pearl_gemm.protocol_constants import SM90_CC_MAJOR, SM100_CC_MAJOR, SM120_CC_MAJOR +from pearl_gemm.protocol_constants import ( + SM80_CC_MAJOR, + SM90_CC_MAJOR, + SM100_CC_MAJOR, + SM120_CC_MAJOR, +) @pytest.mark.parametrize( ("capability", "arch"), [ + ((8, 0), Arch.SM80), ((9, 0), Arch.SM90), ((10, 0), Arch.SM100), ((10, 3), Arch.SM100), @@ -19,7 +25,7 @@ ) def test_known_majors_map_to_their_family(capability, arch): assert arch_of(capability) is arch - assert arch.value in (SM90_CC_MAJOR, SM100_CC_MAJOR, SM120_CC_MAJOR) + assert arch.value in (SM80_CC_MAJOR, SM90_CC_MAJOR, SM100_CC_MAJOR, SM120_CC_MAJOR) def test_smem_capacity_is_the_lead_target_opt_in_maximum(): @@ -28,7 +34,7 @@ def test_smem_capacity_is_the_lead_target_opt_in_maximum(): assert Arch.SM120.smem_capacity_bytes == 101376 -@pytest.mark.parametrize("capability", [(8, 9), (11, 0), (13, 0)]) +@pytest.mark.parametrize("capability", [(7, 5), (11, 0), (13, 0)]) def test_unknown_majors_fail_closed(capability): with pytest.raises(ValueError, match=f"sm{capability[0]}{capability[1]}"): arch_of(capability) diff --git a/miner/pearl-gemm/tests/test_fp16_commit_sm80.py b/miner/pearl-gemm/tests/test_fp16_commit_sm80.py new file mode 100644 index 000000000..80dbe13b7 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_commit_sm80.py @@ -0,0 +1,72 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) FP16 operand commitment. + +Runs the hand-written keyed-BLAKE3 Merkle kernel on the local GA100 and asserts +the 32-byte root matches, bit-for-bit, the pure-Python port of the verifier's +``commit_operand`` / ``pearl_blake3::MerkleTree::with_chunk_len`` +(``tests/helpers/fp16_commit_reference.py``), itself cross-checked against the +Rust oracle dump (``api::fp16::commitment::dump_commit_oracle``). Gated to +``sm_80`` hardware. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 operand-commitment kernel targets sm_80 (GA100) hardware", +) + + +def _gen_rows(n, seed): + # Arbitrary raw u16 bit patterns; commit_operand does not validate finiteness. + return np.array([(i * 40503 + seed) & 0xFFFF for i in range(n)], dtype=np.uint16) + + +# (num_rows, k, chunk_len, key_byte, seed): single-leaf, multi-leaf, every +# allowed chunk_len, odd leaf counts, and row-spanning leaves. +_CASES = [ + (1, 1, 1024, 0x11, 0), + (2, 64, 1024, 0x22, 7), + (8, 256, 1024, 0x07, 123), + (8, 256, 128, 0x5A, 55), + (8, 256, 256, 0xA5, 99), + (8, 256, 512, 0x33, 12), + (5, 100, 512, 0x44, 321), + (7, 333, 128, 0x99, 1000), + (13, 777, 1024, 0xFE, 2024), + (3, 1500, 256, 0x80, 65535), + (1, 600, 1024, 0x01, 44), # single leaf, multi-block chunk + (16, 512, 256, 0xC3, 7777), +] + + +@pytest.mark.parametrize(("num_rows", "k", "chunk_len", "key_byte", "seed"), _CASES) +def test_commit_root_is_bit_exact_vs_verifier(num_rows, k, chunk_len, key_byte, seed): + from pearl_gemm.fp16_commit import commit_operand + + from tests.helpers.fp16_commit_reference import commit_operand_root as ref_root + + rows = _gen_rows(num_rows * k, seed) + key = bytes([key_byte]) * 32 + + expected = ref_root(rows, num_rows, k, key, chunk_len) + got = commit_operand(torch.from_numpy(rows.view(np.int16)), num_rows, k, key, chunk_len) + + assert got == expected, ( + f"root mismatch (nr={num_rows}, k={k}, chunk_len={chunk_len}): " + f"{got.hex()} != {expected.hex()}" + ) + + +def test_commit_root_determinism(): + from pearl_gemm.fp16_commit import commit_operand + + rows = _gen_rows(8 * 256, 1) + key = bytes(range(32)) + first = commit_operand(torch.from_numpy(rows.view(np.int16)), 8, 256, key, 1024) + for _ in range(8): + again = commit_operand(torch.from_numpy(rows.view(np.int16)), 8, 256, key, 1024) + assert again == first, "commitment kernel is not deterministic" diff --git a/miner/pearl-gemm/tests/test_fp16_gemm_sm80.py b/miner/pearl-gemm/tests/test_fp16_gemm_sm80.py new file mode 100644 index 000000000..4004cbb8c --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_gemm_sm80.py @@ -0,0 +1,101 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) FP16 GEMM tile. + +Runs the hand-written ``mma.sync.m16n8k16.f32.f16`` kernel on the local GA100 and +asserts every FP32 output bit matches the Python port of the verifier's A100 +accumulation model (``tests/helpers/a100_fp16_reference.py``, itself validated +bit-exact against ``zk-pow/.../a100_dot_vectors.txt``). Also checks repeat-launch +determinism. Gated to ``sm_80`` hardware; a dead end on any other family. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 GEMM kernel targets sm_80 (GA100) hardware", +) + +# Shapes: (m, n, k) with m%16==0, n%8==0, k%16==0, spanning one-tile and +# many-tile grids and a range of k depths (one group, several groups, long). +_SHAPES = [ + (16, 8, 16), + (16, 8, 256), + (32, 16, 32), + (48, 24, 64), + (64, 40, 128), + (128, 64, 48), +] + + +def _rand_fp16(shape, rng, scale): + """Random finite FP16 operands at a given magnitude scale, with some zeros.""" + v = (rng.standard_normal(shape) * scale).astype(np.float16) + mask = rng.random(shape) < 0.1 + v[mask] = np.float16(0.0) + return v + + +def _reference_bits(a_np, b_np, m, n, k, acc_bits=None): + from tests.helpers.a100_fp16_reference import a100_matmul_bits + + return a100_matmul_bits(a_np.view(np.uint16), b_np.view(np.uint16), m, n, k, acc_bits) + + +@pytest.mark.parametrize(("m", "n", "k"), _SHAPES) +@pytest.mark.parametrize("scale", [0.25, 2.0, 32.0]) +def test_tile_is_bit_exact_vs_verifier(m, n, k, scale): + from pearl_gemm.fp16_gemm import fp16_gemm_a100 + + rng = np.random.default_rng(1234 + m * 131 + n * 17 + k + int(scale * 7)) + a_np = _rand_fp16((m, k), rng, scale) + b_np = _rand_fp16((n, k), rng, scale) + + ref = _reference_bits(a_np, b_np, m, n, k) + d = fp16_gemm_a100(torch.from_numpy(a_np).cuda(), torch.from_numpy(b_np).cuda()) + got = d.cpu().numpy().view(np.uint32) + + mism = int((got != ref).sum()) + assert mism == 0, f"{mism}/{got.size} elements differ from the A100 verifier model" + + +@pytest.mark.parametrize(("m", "n", "k"), [(32, 16, 64), (48, 24, 32)]) +def test_accumulator_carry_in_is_bit_exact(m, n, k): + from pearl_gemm.fp16_gemm import fp16_gemm_a100 + + rng = np.random.default_rng(99 + m + n + k) + a_np = _rand_fp16((m, k), rng, 2.0) + b_np = _rand_fp16((n, k), rng, 2.0) + acc = (rng.standard_normal((m, n)) * 4.0).astype(np.float32) + + ref = _reference_bits(a_np, b_np, m, n, k, acc.view(np.uint32)) + d = fp16_gemm_a100( + torch.from_numpy(a_np).cuda(), + torch.from_numpy(b_np).cuda(), + acc=torch.from_numpy(acc).cuda(), + ) + got = d.cpu().numpy().view(np.uint32) + assert int((got != ref).sum()) == 0 + + +def test_repeat_launch_determinism(): + from pearl_gemm.fp16_gemm import fp16_gemm_a100 + + rng = np.random.default_rng(7) + a = torch.from_numpy(_rand_fp16((64, 128), rng, 2.0)).cuda() + b = torch.from_numpy(_rand_fp16((40, 128), rng, 2.0)).cuda() + first = fp16_gemm_a100(a, b).cpu().numpy().view(np.uint32) + for _ in range(8): + again = fp16_gemm_a100(a, b).cpu().numpy().view(np.uint32) + assert np.array_equal(first, again), "kernel is not deterministic across launches" + + +def test_shape_constraints_rejected(): + from pearl_gemm.fp16_gemm import fp16_gemm_a100 + + a = torch.zeros((16, 24), dtype=torch.float16, device="cuda") # k=24 not %16 + b = torch.zeros((8, 24), dtype=torch.float16, device="cuda") + with pytest.raises(RuntimeError, match="multiple of 16"): + fp16_gemm_a100(a, b) diff --git a/miner/pearl-gemm/tests/test_fp16_miner_sm80.py b/miner/pearl-gemm/tests/test_fp16_miner_sm80.py new file mode 100644 index 000000000..49b5be637 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_miner_sm80.py @@ -0,0 +1,199 @@ +"""On-GPU end-to-end validation of the FP16 (A100 / ``sm_80``) miner driver. + +Drives :func:`pearl_gemm.fp16_miner.search_block` on the local GA100: from a job +header + full plaintext FP16 operands it derives the bit-exact seed chain, commits +both operands, rebuilds ``A'``/``B'``, runs the full-matrix lottery search, and +decodes the latched hit into an opened tile. The decoded witness (opened rows + +sliced noise + ``seed_a``) is then fed to the Rust-anchored numpy oracle +(``tests/helpers/fp16_pipeline_reference.verify_tile``), which must: + + * ACCEPT the tile (policy-admissible), + * reproduce the search's latched 32-byte jackpot ticket bit-for-bit, and + * clear the EASY difficulty target. + +A HARD (impossible) ``nbits`` must produce no winner. A separate test asserts the +host seed-chain reproduction (:mod:`pearl_gemm.fp16_miner._seed_chain`) is +internally consistent and matches the committed Rust cargo-dump vector +bit-for-bit (keys / p-encodings / seeds / ``pow_key`` / pattern encodings). + +Gated to ``sm_80`` hardware; the full suite is CI. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the FP16 miner driver targets sm_80 (GA100) hardware", +) + +_BLAKE, _FOLD = 2, 1 + + +class _Gen: + """Deterministic xorshift FP16 stream with spread magnitudes (the honest, + policy-admissible regime), reused from the pipeline/search tests.""" + + def __init__(self, seed): + self.s = seed & 0xFFFFFFFFFFFFFFFF + + def _n(self): + self.s ^= (self.s << 13) & 0xFFFFFFFFFFFFFFFF + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & 0xFFFFFFFFFFFFFFFF + return self.s + + def operand(self, n): + out = np.empty(n, np.float16) + for i in range(n): + r = self._n() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = int((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(sign * mant * (2.0 ** exp)) + return out + + +# (h, w, k, rp_dims, cp_dims, m, n): h/w == pattern tile_size, 16 blake lanes, +# whole lottery tiles in m and n. +_SHAPES = [ + (4, 64, 256, [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)], 16, 256), + (16, 64, 128, [(4, _BLAKE), (4, _FOLD)], [(4, _BLAKE), (16, _FOLD)], 32, 128), +] + + +@pytest.mark.parametrize(("h", "w", "k", "rp", "cp", "m", "n"), _SHAPES) +def test_search_block_winner_verifies_against_rust_oracle(h, w, k, rp, cp, m, n): + from pearl_gemm.fp16_miner import ( + Fp16JobParams, + Fp16OperandParams, + jackpot_pow_key, + noise_seeds, + search_block, + ) + from pearl_gemm.fp16_pipeline import AxisPattern + + from tests.helpers import fp16_pipeline_reference as ref + + r = 32 + header = bytes((i * 7 + 11) & 0xFF for i in range(76)) + + g = _Gen(0xBEEF_1234_5678_9ABC ^ (h * 131 + w * 17 + k + m * 7 + n * 3)) + a = g.operand(m * k).reshape(m, k) + b = g.operand(n * k).reshape(n, k) + a_dev = torch.from_numpy(np.ascontiguousarray(a)).cuda() + b_dev = torch.from_numpy(np.ascontiguousarray(b)).cuda() + + rp_a = AxisPattern.new(rp) + cp_a = AxisPattern.new(cp) + op_a = Fp16OperandParams(num_rows=m, pattern=rp_a, chunk_len=1024) + op_b = Fp16OperandParams(num_rows=n, pattern=cp_a, chunk_len=1024) + + ref_rp = ref.AxisPattern.new(rp) + ref_cp = ref.AxisPattern.new(cp) + + # EASY nbits: every tile clears difficulty, so the first flat tile latches. + easy = 0x207F_FFFF + wt = search_block(header, a_dev, b_dev, Fp16JobParams(k=k, a=op_a, b=op_b, nbits=easy)) + assert wt.found, "EASY nbits must latch a winner" + assert (wt.tile_row, wt.tile_col) == (0, 0), "EASY first winner must be tile (0, 0)" + + # Feed the decoded witness to the Rust-anchored numpy oracle. + rv = ref.verify_tile( + wt.opened_a_rows.cpu().numpy(), + wt.opened_b_rows.cpu().numpy(), + wt.e_a.cpu().numpy(), + wt.f_a.cpu().numpy(), + wt.e_b.cpu().numpy(), + wt.f_b.cpu().numpy(), + ref_rp, + ref_cp, + wt.seed_a, + r, + ) + assert rv.ticket == wt.ticket, ( + f"oracle ticket {rv.ticket.hex()} != search latched ticket {wt.ticket.hex()}" + ) + assert rv.report.accept, "oracle must ACCEPT the honest winning tile" + assert bool(wt.report.accept) == bool(rv.report.accept), "GA100 and oracle policy disagree" + assert ref.check_jackpot_difficulty(rv.ticket, easy, h, w, k), "winner must clear EASY difficulty" + + # HARD (impossible) nbits: no tile can win. + wt_hard = search_block(header, a_dev, b_dev, Fp16JobParams(k=k, a=op_a, b=op_b, nbits=0)) + assert not wt_hard.found + assert (wt_hard.tile_row, wt_hard.tile_col) == (-1, -1) + assert wt_hard.report is None + + # The host seed chain is internally consistent. + sc = wt.seeds + assert sc.pow_key == jackpot_pow_key(sc.seed_a) + sa, sb = noise_seeds(sc.key_a, sc.key_b, sc.root_a, sc.root_b, sc.p_a, sc.p_b) + assert (sa, sb) == (sc.seed_a, sc.seed_b) + + +def test_seed_chain_matches_rust_cargo_dump(): + """The host seed-chain reproduction is bit-for-bit with the ``zk-pow`` cargo + dump (``api::fp16::plain_proof::seed_chain_dump::dump_seed_chain``). + + The fixed vector below is the committed output of that ``#[ignore]`` test for + ``(header=new_for_test(0x207fffff), fill(0x1111)/fill(0x2222) operands, M=8 + N=128 K=256 R=32, P_A=[(4,Blake)], P_B=[(4,Blake),(16,Fold)], chunk 1024)``. + Regenerate with:: + + PEARL_FP16_SEEDCHAIN_OUT=/tmp/sc.txt cargo test -p zk-pow --lib -- \\ + api::fp16::plain_proof::seed_chain_dump::dump_seed_chain --ignored --exact + """ + from pearl_gemm.fp16_miner import ( + commitment_keys, + encode_p_a, + encode_p_b, + encode_pattern, + jackpot_pow_key, + noise_seeds, + ) + from pearl_gemm.fp16_pipeline import AxisPattern + + expected = { + "key_a": "69085d9fe0824504f23261420abc30fe9265ec0c3ce4381f5064bdad9311fd01", + "key_b": "bb7c90187928bb63994c0b1a0f1aeb9d75d014cdaac2276255451033c0989c8b", + "root_a": "3d9c9b3fb3eaeff3ca6bc0169c9ceeedcb35a9910da2fac33bc147bb17f6cdba", + "root_b": "aae6744237799891831b778b5a673db028878cec732f171b9e3229919b6c3e84", + "p_a": "00010000200000000008000000030e0303030303", + "p_b": ( + "000000000101010101010101010101010101010101010101010101010101010101010101" + "020202020202020202020202020202020202020202020202020202020202020266666666" + "ffff7f2000010000200000000080000000030e3d03030303" + ), + "seed_a": "f32e5853b457b58cbe90bfc387186a05553757e59512bf92b0ce284ce14edbdf", + "seed_b": "762bd866355529f85aa7ba16d5b973821601ac9099e0c672b377fd29faa44ebd", + "pow_key": "31a758e15808744125c4747eed7fc20e9245abc77109d31812ab0278f0efc8a3", + "pattern_a": "0e0303030303", + "pattern_b": "0e3d03030303", + } + header = bytes.fromhex( + "000000000101010101010101010101010101010101010101010101010101010101010101" + "020202020202020202020202020202020202020202020202020202020202020266666666ffff7f20" + ) + ancestor = header # depth-0 coincidence + k, r, m, n, hash_id = 256, 32, 8, 128, 3 + rp = AxisPattern.new([(4, 2)]) + cp = AxisPattern.new([(4, 2), (16, 1)]) + + ka, kb = commitment_keys(header, ancestor) + assert ka.hex() == expected["key_a"] + assert kb.hex() == expected["key_b"] + assert encode_pattern(rp).hex() == expected["pattern_a"] + assert encode_pattern(cp).hex() == expected["pattern_b"] + p_a = encode_p_a(k, r, 0, m, hash_id, rp) + p_b = encode_p_b(ancestor, k, r, 0, n, hash_id, cp) + assert p_a.hex() == expected["p_a"] + assert p_b.hex() == expected["p_b"] + seed_a, seed_b = noise_seeds( + ka, kb, bytes.fromhex(expected["root_a"]), bytes.fromhex(expected["root_b"]), p_a, p_b + ) + assert seed_a.hex() == expected["seed_a"] + assert seed_b.hex() == expected["seed_b"] + assert jackpot_pow_key(seed_a).hex() == expected["pow_key"] diff --git a/miner/pearl-gemm/tests/test_fp16_noise_lines_sm80.py b/miner/pearl-gemm/tests/test_fp16_noise_lines_sm80.py new file mode 100644 index 000000000..1d1deaf05 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_noise_lines_sm80.py @@ -0,0 +1,74 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) FP16 noise-line generation. + +Runs the hand-written keyed-BLAKE3 + normalize kernel on the local GA100 and +asserts every ``u16`` of the ``E``/``F`` noise factors matches the Python port of +the verifier's ``sample_line`` / ``sample_noise`` +(``tests/helpers/fp16_noise_lines_reference.py``, whose keyed-BLAKE3 XOF uses the +same ``blake3`` crate the reference hashes with). Gated to ``sm_80`` hardware. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 noise-line kernel targets sm_80 (GA100) hardware", +) + +# (seed_a, seed_b, k, r, a_rows, b_cols). r = NOISE_RANK = 32 is the protocol +# rank; the extra ranks exercise XOF beyond one 32/64-byte output block. +_CASES = [ + (b"\x22" * 32, b"\x11" * 32, 128, 32, [0, 8, 64], [1, 2]), + (b"\x01" * 32, b"\xfe" * 32, 64, 32, [0, 1, 2, 255], [7, 300, 1000]), + (b"\xa5" * 32, b"\x5a" * 32, 256, 32, [0], [0]), + (b"\x33" * 32, b"\x44" * 32, 40, 16, [3, 9], [4]), + (b"\x7f" * 32, b"\x80" * 32, 48, 48, [0, 17], [1, 2, 65535]), + (b"\x00" * 32, b"\xff" * 32, 24, 72, [5], [6]), +] + + +@pytest.mark.parametrize(("seed_a", "seed_b", "k", "r", "a_rows", "b_cols"), _CASES) +def test_noise_lines_are_bit_exact_vs_verifier(seed_a, seed_b, k, r, a_rows, b_cols): + from pearl_gemm.fp16_noise_lines import sample_noise + + from tests.helpers.fp16_noise_lines_reference import sample_noise as ref_sample_noise + + ref_e_a, ref_f_a, ref_e_b, ref_f_b = ref_sample_noise(seed_a, seed_b, k, r, a_rows, b_cols) + + got = sample_noise(seed_a, seed_b, k, r, a_rows, b_cols) + + def u16(t): + return t.cpu().numpy().view(np.uint16).reshape(-1) + + for name, g, ref in ( + ("e_a", got.e_a, ref_e_a), + ("f_a", got.f_a, ref_f_a), + ("e_b", got.e_b, ref_e_b), + ("f_b", got.f_b, ref_f_b), + ): + g = u16(g) + ref = ref.reshape(-1) + mism = int((g != ref).sum()) + assert mism == 0, f"{name}: {mism}/{ref.size} u16 differ from the verifier model" + + +def test_line_key_matches_reference(): + from pearl_gemm.fp16_noise_lines import line_key + + from tests.helpers.fp16_noise_lines_reference import line_key as ref_line_key + + for seed in (b"\x22" * 32, b"\x01" * 32, bytes(range(32))): + assert line_key(seed) == ref_line_key(seed) + + +def test_repeat_launch_determinism(): + from pearl_gemm.fp16_noise_lines import noise_lines + + seed = bytes(range(32)) + first = noise_lines(seed, 0, 0, list(range(64)), 32).cpu().numpy().copy() + for _ in range(8): + again = noise_lines(seed, 0, 0, list(range(64)), 32).cpu().numpy() + assert np.array_equal(first, again), "noise-line kernel is not deterministic" diff --git a/miner/pearl-gemm/tests/test_fp16_noisy_quant_sm80.py b/miner/pearl-gemm/tests/test_fp16_noisy_quant_sm80.py new file mode 100644 index 000000000..56a062989 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_noisy_quant_sm80.py @@ -0,0 +1,92 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) FP16 fused noisy quantize. + +Runs the hand-written norms+scales and fused-elementwise kernels on the local +GA100 and asserts every output bit (per-row ``alpha``/``beta``/``l2`` BF16 scales +and the final FP16 codes) matches the Python port of the verifier's +``noisy_quantize`` (``tests/helpers/fp16_noisy_quant_reference.py``, whose +``E@F^T`` noise reuses the bit-exact A100 datapath oracle). Gated to ``sm_80``. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 noisy-quantize kernels target sm_80 (GA100) hardware", +) + +# (num_rows, k, r): num_rows%16==0, k%8==0, r%16==0 (fp16_gemm_a100 tile grid). +_SHAPES = [ + (16, 8, 16), + (16, 16, 16), + (32, 8, 32), + (16, 64, 16), + (32, 24, 48), + (48, 40, 16), +] + + +def _rand_fp16(shape, rng, scale): + v = (rng.standard_normal(shape) * scale).astype(np.float16) + v[rng.random(shape) < 0.1] = np.float16(0.0) + return v + + +@pytest.mark.parametrize(("num_rows", "k", "r"), _SHAPES) +@pytest.mark.parametrize("scale", [0.25, 2.0, 16.0]) +def test_noisy_quantize_is_bit_exact_vs_verifier(num_rows, k, r, scale): + from pearl_gemm.fp16_noisy_quant import noisy_quantize + + from tests.helpers.fp16_noisy_quant_reference import noisy_quantize as ref_nq + from tests.helpers.fp16_noisy_quant_reference import row_norms as ref_row_norms + + rng = np.random.default_rng(2024 + num_rows * 131 + k * 17 + r + int(scale * 7)) + rows_np = _rand_fp16((num_rows, k), rng, scale) + e_np = _rand_fp16((num_rows, r), rng, scale) + f_np = _rand_fp16((k, r), rng, scale) + + norms = [ref_row_norms(rows_np[i].view(np.uint16)) for i in range(num_rows)] + ref = ref_nq(rows_np, e_np, f_np, norms, r) + + built = noisy_quantize( + torch.from_numpy(rows_np).cuda(), + torch.from_numpy(e_np).cuda(), + torch.from_numpy(f_np).cuda(), + r, + ) + a_got = built.alpha.cpu().numpy().view(np.uint16) + b_got = built.beta.cpu().numpy().view(np.uint16) + l2_got = built.l2.cpu().numpy().view(np.uint16) + n_got = built.noised_part.cpu().numpy().view(np.uint16) + + assert int((a_got != ref["alpha"]).sum()) == 0, "alpha scales differ" + assert int((b_got != ref["beta"]).sum()) == 0, "beta scales differ" + assert int((l2_got != ref["l2"]).sum()) == 0, "l2 differs" + mism = int((n_got != ref["noised"]).sum()) + assert mism == 0, f"{mism}/{n_got.size} FP16 codes differ from the verifier" + + +def test_repeat_launch_determinism(): + from pearl_gemm.fp16_noisy_quant import noisy_quantize + + rng = np.random.default_rng(7) + rows = torch.from_numpy(_rand_fp16((32, 64), rng, 2.0)).cuda() + e = torch.from_numpy(_rand_fp16((32, 32), rng, 2.0)).cuda() + f = torch.from_numpy(_rand_fp16((64, 32), rng, 2.0)).cuda() + first = noisy_quantize(rows, e, f, 32).noised_part.cpu().numpy().view(np.uint16) + for _ in range(8): + again = noisy_quantize(rows, e, f, 32).noised_part.cpu().numpy().view(np.uint16) + assert np.array_equal(first, again), "kernel is not deterministic across launches" + + +def test_shape_mismatch_rejected(): + from pearl_gemm.fp16_noisy_quant import noisy_quantize + + rows = torch.zeros((16, 16), dtype=torch.float16, device="cuda") + e = torch.zeros((16, 16), dtype=torch.float16, device="cuda") + f = torch.zeros((8, 16), dtype=torch.float16, device="cuda") # k must be 16 + with pytest.raises(ValueError, match="f must be"): + noisy_quantize(rows, e, f, 16) diff --git a/miner/pearl-gemm/tests/test_fp16_pipeline_sm80.py b/miner/pearl-gemm/tests/test_fp16_pipeline_sm80.py new file mode 100644 index 000000000..ab4a0ff78 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_pipeline_sm80.py @@ -0,0 +1,180 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) end-to-end FP16 tile pipeline. + +Chains the GA100 FP16 kernels on the local hardware exactly as +``zk-pow/src/api/fp16/verify.rs::verify_tile`` does -- rebuild the noised +operands, replay + score the tile, fold the jackpot ticket -- and asserts every +stage boundary is bit-exact to the independent Python port of the verifier +(``tests/helpers/fp16_pipeline_reference.py``): the rebuilt FP16 operands, the +``(h, w)`` f32 tile bits, the ``f_bp``/``rho``/``accept`` report, the 64-byte +XOR-fold message, the 32-byte jackpot ticket, and the difficulty verdict. Gated +to ``sm_80``. The reference reproduces Rust's two-step rounding (``mul_add`` -> +f32, then RNE -> f16), which the GA100 kernels (``fmaf`` + ``__float2half_rn``) +match bit-for-bit. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 pipeline kernels target sm_80 (GA100) hardware", +) + +# DimType discriminants (crate::api::layout::DimType). +_BLAKE, _FOLD = 2, 1 + + +class _Gen: + """Deterministic xorshift FP16 stream with spread magnitudes, so the tile has + dense breakpoints (the honest/realistic regime that clears the policy gate).""" + + def __init__(self, seed): + self.s = seed & 0xFFFFFFFFFFFFFFFF + + def _n(self): + self.s ^= (self.s << 13) & 0xFFFFFFFFFFFFFFFF + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & 0xFFFFFFFFFFFFFFFF + return self.s + + def operand(self, n): + out = np.empty(n, np.float16) + for i in range(n): + r = self._n() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = int((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(sign * mant * (2.0 ** exp)) + return out + + def noise(self, n, r_rank): + scale = 256.0 / (r_rank ** 0.5) + out = np.empty(n, np.float16) + for i in range(n): + out[i] = np.float16(scale if (self._n() & 1) == 0 else -scale) + return out + + +def _cuda_f16(arr): + return torch.from_numpy(np.ascontiguousarray(arr)).cuda() + + +def _assert_matches_reference(a, b, ea, fa, eb, fb, rp_dims, cp_dims, seed, r): + from pearl_gemm.fp16_pipeline import AxisPattern, pipeline + + from tests.helpers.fp16_pipeline_reference import AxisPattern as RefAxis + from tests.helpers.fp16_pipeline_reference import verify_tile as ref_verify_tile + + h, k = a.shape + w = b.shape[0] + ref = ref_verify_tile(a, b, ea, fa, eb, fb, RefAxis.new(rp_dims), RefAxis.new(cp_dims), seed, r) + v = pipeline( + _cuda_f16(a), _cuda_f16(b), _cuda_f16(ea), _cuda_f16(fa), _cuda_f16(eb), _cuda_f16(fb), + AxisPattern.new(rp_dims), AxisPattern.new(cp_dims), seed, r, + ) + + ba = v.built_a.noised_part.cpu().numpy().view(np.uint16) + bb = v.built_b.noised_part.cpu().numpy().view(np.uint16) + assert int((ba != ref.built_a).sum()) == 0, "rebuilt A operand differs" + assert int((bb != ref.built_b).sum()) == 0, "rebuilt B operand differs" + tile_bits = v.tile.view(torch.int32).reshape(-1).cpu().numpy().view(np.uint32) + assert int((tile_bits != ref.tile_bits.reshape(-1)).sum()) == 0, "tile f32 bits differ" + assert np.float64(v.report.f_bp).view(np.uint64) == np.float64(ref.report.f_bp).view(np.uint64) + assert np.float64(v.report.rho).view(np.uint64) == np.float64(ref.report.rho).view(np.uint64) + assert v.report.accept == ref.report.accept + assert v.message == ref.message, "XOR-fold message differs" + assert v.ticket == ref.ticket, "jackpot ticket differs" + return v, ref + + +# (h, w, k, r, rp_dims, cp_dims): h/w == pattern tile_size, 16 blake lanes. +_SHAPES = [ + (4, 64, 128, 32, [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)]), + (4, 64, 256, 32, [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)]), + (16, 64, 128, 32, [(4, _BLAKE), (4, _FOLD)], [(4, _BLAKE), (16, _FOLD)]), +] + + +@pytest.mark.parametrize(("h", "w", "k", "r", "rp", "cp"), _SHAPES) +def test_pipeline_is_bit_exact_vs_verifier(h, w, k, r, rp, cp): + g = _Gen(0x1234_5678_9ABC_DEF1 ^ (h * 131 + w * 17 + k + r)) + a = g.operand(h * k).reshape(h, k) + b = g.operand(w * k).reshape(w, k) + ea = g.noise(h * r, r).reshape(h, r) + fa = g.noise(k * r, r).reshape(k, r) + eb = g.noise(w * r, r).reshape(w, r) + fb = g.noise(k * r, r).reshape(k, r) + v, ref = _assert_matches_reference(a, b, ea, fa, eb, fb, rp, cp, b"\x07" * 32, r) + # Spread-magnitude operands clear the policy gate. + assert v.report.accept and v.report.f_bp >= 0.30 and v.report.rho >= 1.2 + + +def test_verify_tile_accepts_and_proof_checks_difficulty(): + from pearl_gemm.fp16_pipeline import AxisPattern, verify_tile, verify_tile_proof + + h, w, k, r = 4, 64, 256, 32 + rp, cp = [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)] + g = _Gen(0xFEED_FACE_CAFE_B0BA) + a = _cuda_f16(g.operand(h * k).reshape(h, k)) + b = _cuda_f16(g.operand(w * k).reshape(w, k)) + ea = _cuda_f16(g.noise(h * r, r).reshape(h, r)) + fa = _cuda_f16(g.noise(k * r, r).reshape(k, r)) + eb = _cuda_f16(g.noise(w * r, r).reshape(w, r)) + fb = _cuda_f16(g.noise(k * r, r).reshape(k, r)) + seed = b"\x5a" * 32 + rpa, cpa = AxisPattern.new(rp), AxisPattern.new(cp) + + v = verify_tile(a, b, ea, fa, eb, fb, rpa, cpa, seed, r) + assert v.report.accept + # Easy target accepts; an impossible (zero) target raises. + verify_tile_proof(a, b, ea, fa, eb, fb, rpa, cpa, seed, r, 0x207F_FFFF) + with pytest.raises(ValueError, match="difficulty"): + verify_tile_proof(a, b, ea, fa, eb, fb, rpa, cpa, seed, r, 0) + + +def test_verify_tile_rejects_flat_tile(): + from pearl_gemm.fp16_pipeline import AxisPattern, verify_tile + + h, w, k, r = 4, 64, 256, 32 + one = np.ones((h, k), np.float16) + a = _cuda_f16(one) + b = _cuda_f16(np.ones((w, k), np.float16)) + ea = _cuda_f16(np.zeros((h, r), np.float16)) + fa = _cuda_f16(np.zeros((k, r), np.float16)) + eb = _cuda_f16(np.zeros((w, r), np.float16)) + fb = _cuda_f16(np.zeros((k, r), np.float16)) + rp, cp = AxisPattern.new([(4, _BLAKE)]), AxisPattern.new([(4, _BLAKE), (16, _FOLD)]) + with pytest.raises(ValueError, match="not admissible"): + verify_tile(a, b, ea, fa, eb, fb, rp, cp, b"\x00" * 32, r) + + +def test_pipeline_with_noise_sampled_from_seeds(): + """Close the loop with the deterministic noise module: draw E/F from seeds via + ``fp16_noise_lines`` and feed the driver, asserting it still matches the + reference built from the same sampled factors.""" + from pearl_gemm.fp16_noise_lines import sample_noise + + from tests.helpers.fp16_noise_lines_reference import sample_noise as ref_sample + + h, w, k, r = 4, 64, 128, 32 + rp, cp = [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)] + g = _Gen(0x0BAD_F00D_1337_D00D) + a = g.operand(h * k).reshape(h, k) + b = g.operand(w * k).reshape(w, k) + seed_a, seed_b = b"\x11" * 32, b"\x22" * 32 + a_rows, b_cols = list(range(h)), list(range(w)) + + # Device-sampled noise (int16 FP16 bits) and the reference's. + nz = sample_noise(seed_a, seed_b, k, r, a_rows, b_cols) + ea = nz.e_a.cpu().numpy().view(np.uint16).view(np.float16) + fa = nz.f_a.cpu().numpy().view(np.uint16).view(np.float16) + eb = nz.e_b.cpu().numpy().view(np.uint16).view(np.float16) + fb = nz.f_b.cpu().numpy().view(np.uint16).view(np.float16) + ref_ea, ref_fa, ref_eb, ref_fb = ref_sample(seed_a, seed_b, k, r, a_rows, b_cols) + assert np.array_equal(ea.view(np.uint16), ref_ea), "sampled E_a differs from reference" + assert np.array_equal(fb.view(np.uint16), ref_fb), "sampled F_b differs from reference" + + _assert_matches_reference(a, b, ea, fa, eb, fb, rp, cp, seed_a, r) diff --git a/miner/pearl-gemm/tests/test_fp16_policy_sm80.py b/miner/pearl-gemm/tests/test_fp16_policy_sm80.py new file mode 100644 index 000000000..f1b45e408 --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_policy_sm80.py @@ -0,0 +1,130 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) FP16 accumulation policy census. + +Runs the hand-written software-accumulation + fused policy-reduction kernel on +the local GA100 and asserts, against the Python port of the verifier's +``policy.rs`` (``tests/helpers/fp16_policy_reference.py``, built on the trusted +A100 accumulation oracle): every recomputed tile u32 bit matches, every per-cell +integer census quantity (``n_bp``, ``n_runs``, ``n_pt``) matches, and the folded +``f_bp`` / ``rho`` bit patterns and ``accept`` agree. Gated to ``sm_80``. +""" + +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 policy census kernel targets sm_80 (GA100) hardware", +) + +# (m, n, k): k includes non-multiples of 8 and k < 8; shapes mirror the Rust +# oracle dump. No tile-granularity constraint (software accumulation path). +_SHAPES = [ + (1, 1, 7), + (2, 3, 8), + (3, 2, 9), + (4, 4, 16), + (2, 2, 31), + (5, 3, 33), + (4, 6, 64), + (3, 3, 100), + (6, 5, 127), + (2, 4, 256), + (8, 8, 40), + (7, 7, 48), + (1, 16, 72), + (16, 1, 72), +] + + +def _rand_fp16_bits(shape, rng, exp_lo, exp_hi): + """Random finite FP16 bit patterns with a bounded exponent window (wide => + breakpoints/truncations, narrow => near-flat), ~12% exact zeros.""" + size = int(np.prod(shape)) + sign = (rng.integers(0, 2, size).astype(np.uint16)) << 15 + exp = rng.integers(exp_lo, exp_hi + 1, size).astype(np.uint16) << 10 + man = rng.integers(0, 0x400, size).astype(np.uint16) + bits = (sign | exp | man).astype(np.uint16) + zero = rng.random(size) < 0.12 + bits[zero] = (sign[zero]) # +/-0 + return bits.reshape(shape) + + +@pytest.mark.parametrize(("m", "n", "k"), _SHAPES) +@pytest.mark.parametrize(("exp_lo", "exp_hi"), [(1, 28), (10, 12), (1, 29)]) +def test_policy_census_is_bit_exact_vs_verifier(m, n, k, exp_lo, exp_hi): + from pearl_gemm.fp16_policy import evaluate, policy_census + + from tests.helpers.fp16_policy_reference import replay_and_evaluate as ref_replay + + rng = np.random.default_rng(99 + m * 131 + n * 17 + k * 7 + exp_lo * 3 + exp_hi) + a_bits = _rand_fp16_bits((m, k), rng, exp_lo, exp_hi) + b_bits = _rand_fp16_bits((n, k), rng, exp_lo, exp_hi) + + ref_tile, ref_percell, ref_report = ref_replay(a_bits, b_bits, m, n, k) + + a = torch.from_numpy(a_bits.view(np.float16)).cuda() + b = torch.from_numpy(b_bits.view(np.float16)).cuda() + tile, n_bp, n_runs, n_pt = policy_census(a, b) + + tile_bits = tile.cpu().numpy().view(np.uint32) + assert int((tile_bits != ref_tile).sum()) == 0, "recomputed tile bits differ" + + got_percell = np.stack( + [ + n_bp.cpu().numpy().reshape(-1), + n_runs.cpu().numpy().reshape(-1), + n_pt.cpu().numpy().reshape(-1), + ], + axis=1, + ).astype(np.int64) + assert int((got_percell != ref_percell).sum()) == 0, "per-cell census differs" + + report = evaluate(n_bp, n_runs, n_pt, k) + assert report.breakpoints == ref_report.breakpoints + assert report.numerator == ref_report.numerator + # f_bp / rho are f64: compare exact bit patterns. + assert np.float64(report.f_bp).view(np.uint64) == np.float64(ref_report.f_bp).view(np.uint64) + assert np.float64(report.rho).view(np.uint64) == np.float64(ref_report.rho).view(np.uint64) + assert report.accept == ref_report.accept + + +def test_tile_matches_fp16_gemm(): + """The census kernel's recomputed tile matches the committed fp16_gemm + datapath exactly (k a multiple of 16 so the HMMA kernel applies).""" + from pearl_gemm.fp16_gemm import fp16_gemm_a100 + from pearl_gemm.fp16_policy import policy_census + + rng = np.random.default_rng(5) + a_bits = _rand_fp16_bits((16, 64), rng, 1, 28) + b_bits = _rand_fp16_bits((8, 64), rng, 1, 28) + a = torch.from_numpy(a_bits.view(np.float16)).cuda() + b = torch.from_numpy(b_bits.view(np.float16)).cuda() + + gemm_tile = fp16_gemm_a100(a, b).cpu().numpy().view(np.uint32) + policy_tile = policy_census(a, b)[0].cpu().numpy().view(np.uint32) + assert int((gemm_tile != policy_tile).sum()) == 0, "policy tile != fp16_gemm tile" + + +def test_repeat_launch_determinism(): + from pearl_gemm.fp16_policy import policy_census + + rng = np.random.default_rng(11) + a = torch.from_numpy(_rand_fp16_bits((8, 48), rng, 1, 28).view(np.float16)).cuda() + b = torch.from_numpy(_rand_fp16_bits((8, 48), rng, 1, 28).view(np.float16)).cuda() + first = [t.cpu().numpy().copy() for t in policy_census(a, b)] + for _ in range(8): + again = [t.cpu().numpy() for t in policy_census(a, b)] + for x, y in zip(first, again): + assert np.array_equal(x, y), "kernel is not deterministic across launches" + + +def test_shape_mismatch_rejected(): + from pearl_gemm.fp16_policy import policy_census + + a = torch.zeros((4, 16), dtype=torch.float16, device="cuda") + b = torch.zeros((4, 8), dtype=torch.float16, device="cuda") # k must match + with pytest.raises(ValueError, match="b must have k="): + policy_census(a, b) diff --git a/miner/pearl-gemm/tests/test_fp16_search_sm80.py b/miner/pearl-gemm/tests/test_fp16_search_sm80.py new file mode 100644 index 000000000..2d9d2f6ce --- /dev/null +++ b/miner/pearl-gemm/tests/test_fp16_search_sm80.py @@ -0,0 +1,193 @@ +"""On-GPU bit-exactness of the A100 (``sm_80``) full-matrix FP16 lottery search. + +Runs the hand-written search + first-winner latch kernel on the local GA100 and +asserts, for the SAME noised operands ``A'``/``B'``: + + * every committed tile's 32-byte jackpot ticket matches, bit-for-bit, an + independent Python scan that computes each tile via the verifier reference + (``tests/helpers/fp16_policy_reference.replay_and_evaluate`` for the + bit-exact A100 accumulation, then ``fp16_pipeline_reference``'s XOR-fold + + keyed-BLAKE3 ticket), and + * the latched first-winner ``(tile_row, tile_col, ticket)`` equals the Python + scan's first winner (lowest flat tile index ``tr*ntc + tc``), both for an + EASY ``nbits`` (winners exist) and a HARD ``nbits`` (no winner -> empty + latch). + +Policy is deliberately NOT evaluated in the search kernel (it latches purely on +the jackpot difficulty threshold, mirroring fp8); the host driver scores +``fp16_policy`` on the latched tile later. Gated to ``sm_80`` hardware. +""" + +import blake3 +import numpy as np +import pytest +import torch + +from pearl_gemm._utils._arch import Arch, arch_of + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the A100 FP16 lottery-search kernel targets sm_80 (GA100) hardware", +) + +# DimType discriminants (crate::api::layout::DimType). +_BLAKE, _FOLD = 2, 1 +_LABEL_JACKPOT = b"pearl/v4/FP8/jackpot" + + +class _Gen: + """Deterministic xorshift FP16 stream with spread magnitudes (dense + breakpoints, the honest regime), reused from the pipeline test.""" + + def __init__(self, seed): + self.s = seed & 0xFFFFFFFFFFFFFFFF + + def _n(self): + self.s ^= (self.s << 13) & 0xFFFFFFFFFFFFFFFF + self.s ^= self.s >> 7 + self.s ^= (self.s << 17) & 0xFFFFFFFFFFFFFFFF + return self.s + + def operand(self, n): + out = np.empty(n, np.float16) + for i in range(n): + r = self._n() + sign = 1.0 if (r & 1) == 0 else -1.0 + exp = int((r >> 1) % 9) - 3 + mant = 1.0 + ((r >> 8) % 1024) / 1024.0 + out[i] = np.float16(sign * mant * (2.0 ** exp)) + return out + + +def _pow_key(seed_a: bytes) -> bytes: + """The jackpot subkey the host precomputes and passes to the kernel.""" + return blake3.blake3(_LABEL_JACKPOT, key=seed_a).digest(length=32) + + +def _oracle_scan(a16, b16, seed_a, nbits, rp_dims, cp_dims, h, w, k): + """Independent Python scan: per-tile tickets and the first winner.""" + from tests.helpers.fp16_pipeline_reference import ( + AxisPattern as RefAxis, + check_jackpot_difficulty, + compute_jackpot_ticket, + lane_assignment, + xor_fold_extract, + ) + from tests.helpers.fp16_policy_reference import replay_and_evaluate as ref_replay + + lanes = lane_assignment(RefAxis.new(rp_dims), RefAxis.new(cp_dims)) + ntr, ntc = a16.shape[0] // h, b16.shape[0] // w + tickets = [] + first_winner = None # (flat_idx, tr, tc, ticket) + for tr in range(ntr): + for tc in range(ntc): + a_tile = a16[tr * h : (tr + 1) * h] + b_tile = b16[tc * w : (tc + 1) * w] + tile_bits, _pc, _rep = ref_replay(a_tile, b_tile, h, w, k) + message = xor_fold_extract(tile_bits.reshape(-1), lanes) + ticket = compute_jackpot_ticket(seed_a, message) + tickets.append(ticket) + if first_winner is None and check_jackpot_difficulty(ticket, nbits, h, w, k): + first_winner = (tr * ntc + tc, tr, tc, ticket) + return tickets, first_winner + + +# (h, w, k, rp_dims, cp_dims, m, n): h/w == pattern tile_size, 16 blake lanes, +# whole lottery tiles in m and n. +_SHAPES = [ + (4, 64, 128, [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)], 16, 256), + (4, 64, 256, [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)], 12, 128), + (16, 64, 128, [(4, _BLAKE), (4, _FOLD)], [(4, _BLAKE), (16, _FOLD)], 32, 128), +] + + +@pytest.mark.parametrize(("h", "w", "k", "rp", "cp", "m", "n"), _SHAPES) +def test_search_is_bit_exact_vs_oracle(h, w, k, rp, cp, m, n): + from pearl_gemm.fp16_search import search + from pearl_gemm.fp16_pipeline import AxisPattern + + g = _Gen(0x5EED_1234_ABCD_0001 ^ (h * 131 + w * 17 + k + m * 7 + n * 3)) + a = g.operand(m * k).reshape(m, k) + b = g.operand(n * k).reshape(n, k) + a16 = a.view(np.uint16) + b16 = b.view(np.uint16) + seed_a = bytes([(h + w + k) & 0xFF]) * 32 + pow_key = _pow_key(seed_a) + rpa, cpa = AxisPattern.new(rp), AxisPattern.new(cp) + a_dev = torch.from_numpy(np.ascontiguousarray(a)).cuda() + b_dev = torch.from_numpy(np.ascontiguousarray(b)).cuda() + + # EASY target: every ticket is a winner, so the first tile (0, 0) must latch. + easy_nbits = 0x207F_FFFF # exponent 0x20 -> target ~ U256::MAX, so bound saturates + hit, tickets = search(a_dev, b_dev, pow_key, easy_nbits, rpa, cpa, collect_tickets=True) + + ref_tickets, ref_first = _oracle_scan(a16, b16, seed_a, easy_nbits, rp, cp, h, w, k) + got_tickets = [ + b"".join(int(wd).to_bytes(4, "little") for wd in tickets[i].numpy()) + for i in range(tickets.shape[0]) + ] + mismatches = sum(1 for i in range(len(ref_tickets)) if got_tickets[i] != ref_tickets[i]) + assert mismatches == 0, f"{mismatches}/{len(ref_tickets)} per-tile ticket mismatches" + + assert ref_first is not None, "easy target should have a winner" + assert hit.found + assert (hit.tile_row, hit.tile_col) == (ref_first[1], ref_first[2]), ( + f"latched tile {(hit.tile_row, hit.tile_col)} != oracle {(ref_first[1], ref_first[2])}" + ) + assert hit.ticket == ref_first[3], "latched ticket differs from oracle first winner" + + # HARD target: impossible (zero) difficulty -> no winner, empty latch. + hard_hit = search(a_dev, b_dev, pow_key, 0, rpa, cpa) + _, ref_hard = _oracle_scan(a16, b16, seed_a, 0, rp, cp, h, w, k) + assert ref_hard is None, "zero difficulty should admit no winner" + assert not hard_hit.found + assert hard_hit.tile_row == -1 and hard_hit.tile_col == -1 + + +def test_search_first_winner_is_lowest_tile_index(): + """With a medium bound chosen so only SOME tiles win, the latched tile is the + lowest flat index ``tr*ntc + tc`` among winners, matching the oracle.""" + from pearl_gemm.fp16_search import difficulty_bound, search + from pearl_gemm.fp16_pipeline import AxisPattern, check_jackpot_difficulty + + h, w, k = 4, 64, 128 + rp, cp = [(4, _BLAKE)], [(4, _BLAKE), (16, _FOLD)] + m, n = 24, 256 + g = _Gen(0xC0FF_EE00_1357_9BDF) + a = g.operand(m * k).reshape(m, k) + b = g.operand(n * k).reshape(n, k) + a16, b16 = a.view(np.uint16), b.view(np.uint16) + seed_a = b"\x3c" * 32 + pow_key = _pow_key(seed_a) + rpa, cpa = AxisPattern.new(rp), AxisPattern.new(cp) + a_dev = torch.from_numpy(np.ascontiguousarray(a)).cuda() + b_dev = torch.from_numpy(np.ascontiguousarray(b)).cuda() + + # Sweep nbits to find one that produces a partial (not all / not none) winner + # set, then confirm the kernel's first winner == the oracle's lowest index. + ref_all, _ = _oracle_scan(a16, b16, seed_a, 0x207F_FFFF, rp, cp, h, w, k) + vals = [int.from_bytes(t, "little") for t in ref_all] + # Sweep exponent x mantissa so the bound lands between ticket values. + candidates = [ + (exp << 24) | mant + for exp in (0x1D, 0x1E, 0x1F, 0x20) + for mant in (0x7FFFFF, 0x3FFFFF, 0x1FFFFF, 0x0FFFFF, 0x03FFFF, 0x00FFFF) + ] + found_partial = False + for nbits in candidates: + bound = difficulty_bound(nbits, h, w, k) + winners = [i for i, v in enumerate(vals) if v <= bound] + if 0 < len(winners) < len(vals): + hit = search(a_dev, b_dev, pow_key, nbits, rpa, cpa) + ntc = n // w + expected = min(winners) + assert hit.found + assert hit.tile_row * ntc + hit.tile_col == expected, ( + f"nbits={nbits:#x}: kernel first winner " + f"{hit.tile_row * ntc + hit.tile_col} != oracle {expected}" + ) + # Cross-check the latched ticket clears the threshold. + assert check_jackpot_difficulty(hit.ticket, nbits, h, w, k) + found_partial = True + break + assert found_partial, "no nbits produced a partial winner set; widen the sweep" diff --git a/miner/pearl-gemm/tests/test_pow_sm80.py b/miner/pearl-gemm/tests/test_pow_sm80.py new file mode 100644 index 000000000..4705b0c46 --- /dev/null +++ b/miner/pearl-gemm/tests/test_pow_sm80.py @@ -0,0 +1,187 @@ +"""On-GPU exercise of the PoW hit-signal record + reset path on the A100 (``sm_80``). + +The signal's device touchpoint is the re-arm kernel (``pow/_reset.py``): a tiny +all-atomics kernel (acquire load, system fence, GPU-scope ``atomic_cas``, all +sm_70+) that is arch-neutral, so one source serves every family -- including +SM80 (A100), the FP16 scheme's native target. This test forges published +records with plain host stores into the pinned record (the same oracle +``tests/test_hit_signal.py`` uses, which cannot allocate a signal on an A100 +until ``_reset.py`` admits ``Arch.SM80``) and asserts the record/reset/latch +protocol holds on real GA100 silicon: the expected record layout parses, the +first-wins latch stays closed until reset, and the device re-arm kernel +clears the magic + doorbell and atomically reopens the latch. Gated to +``sm_80`` hardware; a dead end on any other family. +""" + +import pytest +import torch + +from pearl_gemm import ( + HitRecordLayout, + HitSignal, + HitSignalConfig, +) +from pearl_gemm._utils._arch import Arch, arch_of +from pearl_gemm.pow import HIT_RECORD_MAGIC_WORDS + +pytestmark = pytest.mark.skipif( + not torch.cuda.is_available() or arch_of() is not Arch.SM80, + reason="the sm_80 PoW hit-signal path targets A100 (GA100) hardware", +) + +STATUS_IDLE = 0 +STATUS_PUBLISHED = 1 +DEFAULT_MAX_M = 8 +DEFAULT_MAX_K = 512 +FORGE_M = 4 +FORGE_N = 128 +FORGE_K = 64 +FORGE_LAYER_ID = 7 + + +def _make_signal(max_m=DEFAULT_MAX_M, max_k=DEFAULT_MAX_K) -> HitSignal: + return HitSignal(HitSignalConfig(max_m=max_m, max_k=max_k)) + + +def _forge_hit( + signal: HitSignal, + m=FORGE_M, + n=FORGE_N, + k=FORGE_K, + with_payload=True, + group_id=0, +) -> tuple[torch.Tensor, torch.Tensor]: + """Simulate a kernel publish with plain host stores: payloads, record + fields, magic, then the status doorbell LAST (same oracle as + ``tests/test_hit_signal.py``).""" + codes = torch.randint(-127, 128, (m, k), dtype=torch.int8) + scales = torch.rand(m, k // 8, dtype=torch.bfloat16) + if with_payload: + signal.codes_payload.narrow(0, 0, m * k).copy_(codes.reshape(-1)) + signal.scales_payload.narrow(0, 0, m * (k // 8)).copy_(scales.reshape(-1)) + torch.cuda.synchronize() + record = signal.record + record[HitRecordLayout.M] = m + record[HitRecordLayout.N] = n + record[HitRecordLayout.K] = k + record[HitRecordLayout.TILE_ROW] = 0 + record[HitRecordLayout.TILE_COLUMN] = 0 + record[HitRecordLayout.LTILE_ROWS] = 4 + record[HitRecordLayout.LTILE_COLS] = 128 + record[HitRecordLayout.CODES_PAYLOAD_BYTES] = m * k if with_payload else 0 + record[HitRecordLayout.SCALES_PAYLOAD_BYTES] = m * (k // 8) * 2 if with_payload else 0 + record[HitRecordLayout.LAYER_ID] = FORGE_LAYER_ID + record[HitRecordLayout.GROUP_ID] = group_id + for word in range(8): + record[HitRecordLayout.TARGET + word] = word + 1 + record[HitRecordLayout.HASH_A + word] = word + 100 + record[HitRecordLayout.HASH_B + word] = word + 200 + record[HitRecordLayout.MAGIC] = HIT_RECORD_MAGIC_WORDS[0] + record[HitRecordLayout.MAGIC + 1] = HIT_RECORD_MAGIC_WORDS[1] + record[HitRecordLayout.STATUS] = STATUS_PUBLISHED + return codes, scales + + +def test_signal_allocates_on_sm80(): + """``HitSignal.__init__`` compiles the re-arm kernel via ``prepare_hit_reset`` + (the sole arch gate for the whole pow stage): it must now admit the A100.""" + signal = _make_signal() + assert signal.record_device_view.data_ptr() == signal.record.data_ptr() + assert int(signal.lock.item()) == 0 + assert not signal.doorbell() + + +def test_record_parses_with_expected_layout_on_sm80(): + signal = _make_signal() + codes, scales = _forge_hit(signal) + + assert signal.doorbell() + hit = signal.read_hit() + assert hit is not None and hit.valid + assert hit.m == FORGE_M and hit.n == FORGE_N and hit.k == FORGE_K + assert (hit.tile_row, hit.tile_column) == (0, 0) + assert (hit.ltile_rows, hit.ltile_cols) == (4, 128) + assert hit.layer_id == FORGE_LAYER_ID + assert hit.target == b"".join((w + 1).to_bytes(4, "little") for w in range(8)) + assert hit.commitment_hash_A == b"".join((w + 100).to_bytes(4, "little") for w in range(8)) + assert hit.commitment_hash_B == b"".join((w + 200).to_bytes(4, "little") for w in range(8)) + assert torch.equal(hit.codes, codes) + assert torch.equal(hit.scales.view(torch.uint16), scales.view(torch.uint16)) + signal.reset_hit() + + +def test_device_reset_rearms_latch_on_sm80(): + """The device re-arm kernel (``cute.arch.atomic_cas``) runs on the A100: + it clears the magic + doorbell, fences, and atomically reopens the latch.""" + signal = _make_signal() + _forge_hit(signal) + signal.lock.fill_(1) # a producer claimed the first-wins latch + + assert signal.doorbell() + signal.reset_hit() + + # The device kernel cleared the host-visible markers and the latch. + assert not signal.doorbell() + assert signal.read_hit() is None + assert int(signal.lock.item()) == 0 + + # Re-ringing the doorbell alone parses invalid: reset zeroed the magic. + signal.record[HitRecordLayout.STATUS] = STATUS_PUBLISHED + hit = signal.read_hit() + assert hit is not None and not hit.valid + signal.reset_hit() + + +def test_reset_does_not_reopen_an_unpublished_producer_claim_on_sm80(): + """Device defense in depth: lock=1/status=0 is an in-flight producer + claim, never consumer ownership, so the re-arm CAS must not fire.""" + signal = _make_signal() + signal.lock.fill_(1) + signal.record[HitRecordLayout.STATUS] = STATUS_IDLE + + signal.reset_hit() + assert int(signal.lock.item()) == 1 + + # The private launch carries the same device-side guard. + signal._reset_hit_locked() + assert int(signal.lock.item()) == 1 + + _forge_hit(signal) + signal._reset_hit_locked() + assert int(signal.lock.item()) == 0 + assert not signal.doorbell() + + +def test_first_wins_latch_holds_until_device_reset_on_sm80(): + """A second forged publish while one is pending is dropped; only the + device re-arm reopens the latch for the next record.""" + signal = _make_signal() + first_codes, _ = _forge_hit(signal) + signal.lock.fill_(1) + + first = signal.read_hit() + assert first is not None and first.valid + first_hash_a = first.commitment_hash_A + assert torch.equal(first.codes, first_codes) + + signal.reset_hit() + assert int(signal.lock.item()) == 0 + + second_codes, _ = _forge_hit(signal, m=FORGE_M, k=FORGE_K) + rearmed = signal.read_hit() + assert rearmed is not None and rearmed.valid + assert rearmed.commitment_hash_A == first_hash_a # same forged header fields + assert torch.equal(rearmed.codes, second_codes) + signal.reset_hit() + + +def test_repeat_reset_determinism_on_sm80(): + """The all-atomics re-arm kernel is idempotent across many launches.""" + signal = _make_signal() + for _ in range(8): + _forge_hit(signal) + signal.lock.fill_(1) + assert signal.doorbell() + signal.reset_hit() + assert not signal.doorbell() + assert int(signal.lock.item()) == 0 diff --git a/miner/pearl-gemm/tests/test_protocol_constants.py b/miner/pearl-gemm/tests/test_protocol_constants.py index 3c435776d..39915daa8 100644 --- a/miner/pearl-gemm/tests/test_protocol_constants.py +++ b/miner/pearl-gemm/tests/test_protocol_constants.py @@ -10,12 +10,12 @@ # Blackwell-family arithmetic and commits the B200 device. @pytest.mark.parametrize( ("capability", "lg2_delta"), - [((9, 0), 0), ((10, 0), -1), ((10, 3), -1), ((12, 0), -1)], + [((8, 0), -1), ((9, 0), 0), ((10, 0), -1), ((10, 3), -1), ((12, 0), -1)], ) def test_delta_is_the_verifiers_noise_fraction(capability, lg2_delta): assert delta_for_capability(capability) == 2.0**lg2_delta def test_delta_fails_closed_without_a_committed_device(): - with pytest.raises(ValueError, match="sm89"): - delta_for_capability((8, 9)) + with pytest.raises(ValueError, match="sm75"): + delta_for_capability((7, 5)) diff --git a/miner/vllm-miner/src/vllm_miner/fp16_layer.py b/miner/vllm-miner/src/vllm_miner/fp16_layer.py new file mode 100644 index 000000000..fd089e27c --- /dev/null +++ b/miner/vllm-miner/src/vllm_miner/fp16_layer.py @@ -0,0 +1,193 @@ +"""Per-layer state for the FP16 (A100 / sm_80) plaintext scheme. + +The parallel of :mod:`vllm_miner.state` for cert-v5 FP16 mining, deliberately +kept as its own module and registry so the FP8 ``LayerState`` is untouched. + +How FP16 differs from FP8: + +* **No prequantization.** FP8 encodes every weight into committed int8 planes + + BF16 block scales (``PrequantMatrix``) and fuses the lottery into a mixed GEMM. + FP16 commits the **raw FP16 weight rows** directly (``miner_base.fp16_commitment`` + commits the ``u16`` bit patterns), so this state just holds the BF16/FP16 + weight -- on GPU for the search, and a CPU copy for the certificate opening. +* **Serving is a plain linear.** The FP16 search + (``pearl_gemm.fp16_miner.search_block``) only *searches* a noised matmul for a + jackpot tile; it does not produce the layer's output. The layer therefore + serves an ordinary BF16 matmul and runs the search opportunistically as a side + effect (``vllm_miner.fp16_mining``). +* **No steady per-job B buffers / HitSignal.** FP16 derives its whole seed chain + and noise inside ``search_block`` per forward from the header + operands, and + returns the decoded winner synchronously, so none of the FP8 ``LayerBuffers`` / + persistent hit-signal machinery applies. + +The committed A100 tile is fixed (``zk-pow/src/api/fp16/params.rs``): +``P_A = [(4, Blake)]`` (h=4), ``P_B = [(4, Blake), (16, Fold)]`` (w=64), r=32, +contiguous tile offsets. +""" + +from __future__ import annotations + +import itertools +import threading +from dataclasses import dataclass, field + +import torch +from miner_base.devices import Device, is_fp16_capable, local_device +from miner_base.layout import AxisPattern, DimType +from miner_utils import get_logger + +_LOGGER = get_logger(__name__) +_NEXT_FP16_LAYER_ID = itertools.count(1) + +# The committed A100 lottery patterns and noise rank (bit-identical to the +# fixture in miner_base.fp16_block_submission / zk-pow fp16/params.rs). +FP16_ROWS_PATTERN = AxisPattern(((4, DimType.BLAKE),)) # h = 4 +FP16_COLS_PATTERN = AxisPattern(((4, DimType.BLAKE), (16, DimType.FOLD))) # w = 64 +FP16_NOISE_RANK = 32 +FP16_TILE_H = FP16_ROWS_PATTERN.tile_size # 4 +FP16_TILE_W = FP16_COLS_PATTERN.tile_size # 64 + + +def fp16_mines_on(device: torch.device) -> bool: + """Whether ``device`` is an sm_80 (A100/GA100) the FP16 kernels run on. + + The FP16 analogue of ``state._mines_on`` -- and deliberately disjoint from + it: ``state._mines_on`` admits SM90/100/120 for FP8 and omits SM80, so + SM80 stays rejected for FP8 while this admits it for FP16 only.""" + return is_fp16_capable(device) + + +def _fp16_kernels_available() -> bool: + try: + import pearl_gemm.fp16_miner # noqa: F401 + except Exception: + _LOGGER.opt(exception=True).warning("pearl_gemm.fp16_miner import failed; no FP16 mining") + return False + return True + + +def can_mine_fp16_layer(n: int, k: int, device: torch.device) -> bool: + """Whether this device/shape runs the FP16 (A100) search. + + Admits sm_80 **only** (FP8 families are served by ``state.can_mine_layer``), + requires the FP16 kernels, and needs the committed tile to divide the + weight: ``n`` a multiple of w=64 (the search scans ``n // w`` column tiles; + a trailing partial tile is never committed). ``k`` is unconstrained -- the + FP16 Merkle commitment zero-pads each row to the hash-id leaf.""" + if not fp16_mines_on(device) or not _fp16_kernels_available(): + return False + return n > 0 and k > 0 and n % FP16_TILE_W == 0 + + +@dataclass +class Fp16LayerState: + """Everything one FP16 mining-enabled linear layer carries across forwards. + + ``weight`` is the raw ``(n, k)`` FP16/BF16 weight on CUDA (the committed B + operand and the serving operand both); ``weight_cpu`` is the stable host + copy the certificate opening commits from (bit-identical ``u16`` patterns). + Unlike FP8 there are no int8 planes, block scales, steady B buffers, or FP8 + fallback operands. + """ + + layer_name: str + layer_id: int + weight: torch.Tensor # (n, k) float16, contiguous, CUDA -- committed B + weight_cpu: torch.Tensor # (n, k) float16 host copy for the opening + n: int + k: int + mineable: bool + rows_pattern: AxisPattern = FP16_ROWS_PATTERN + cols_pattern: AxisPattern = FP16_COLS_PATTERN + r: int = FP16_NOISE_RANK + lock: threading.Lock = field(default_factory=threading.Lock) + disabled_reason: str | None = None + + @property + def committed_device(self) -> Device: + """The committed mining ``Device`` (always ``Device.A100`` for FP16).""" + return local_device(self.weight.device, allow_fp16=True) + + def disable_mining(self, reason: str) -> None: + """Permanently stop mining this layer (serving continues as a plain linear).""" + with self.lock: + first = self.disabled_reason is None + if first: + self.disabled_reason = reason + self.mineable = False + if first: + _LOGGER.error(f"FP16 mining disabled for {self.layer_name}: {reason}") + + +def _to_committed_fp16(weight: torch.Tensor) -> torch.Tensor: + """The committed FP16 view of a loaded 2D CUDA weight. + + BF16 weights are cast to FP16 (the committed operand dtype); an already-FP16 + weight is used as-is. The returned tensor is contiguous.""" + if weight.dim() != 2 or not weight.is_cuda: + raise ValueError(f"expected a 2D CUDA weight, got {tuple(weight.shape)} on {weight.device}") + if weight.dtype == torch.float16: + committed = weight + elif weight.dtype == torch.bfloat16: + committed = weight.to(torch.float16) + else: + raise ValueError(f"FP16 mining expects a float16/bfloat16 weight, got {weight.dtype}") + return committed.contiguous() + + +def create_fp16_layer_state(layer_name: str, weight: torch.Tensor) -> Fp16LayerState: + """Build one FP16 layer state from a loaded weight (callers gate on + :func:`can_mine_fp16_layer`).""" + committed = _to_committed_fp16(weight) + n, k = committed.shape + if not can_mine_fp16_layer(n, k, committed.device): + raise RuntimeError(f"FP16 layer {layer_name} (n={n}, k={k}) is not mineable on this device") + return Fp16LayerState( + layer_name=layer_name, + layer_id=next(_NEXT_FP16_LAYER_ID), + weight=committed, + weight_cpu=committed.detach().to("cpu").clone(), + n=n, + k=k, + mineable=True, + ) + + +_FP16_REGISTRY: dict[int, Fp16LayerState] = {} +_FP16_REGISTRY_LOCK = threading.RLock() + + +def register_fp16_state(state: Fp16LayerState) -> None: + if not state.weight.is_contiguous(): + raise RuntimeError("FP16 mining weight must be contiguous for data_ptr lookup") + pointer = state.weight.data_ptr() + with _FP16_REGISTRY_LOCK: + owner = _FP16_REGISTRY.get(pointer) + if owner is not None and owner is not state: + raise RuntimeError(f"FP16 mining weight pointer {pointer} is already registered") + _FP16_REGISTRY[pointer] = state + + +def unregister_fp16_state(state: Fp16LayerState) -> None: + with _FP16_REGISTRY_LOCK: + if _FP16_REGISTRY.get(state.weight.data_ptr()) is state: + del _FP16_REGISTRY[state.weight.data_ptr()] + + +def lookup_fp16_state(weight: torch.Tensor) -> Fp16LayerState | None: + """The FP16 layer state registered for ``weight``, or ``None``. + + Returns ``None`` for FP8-registered or unregistered weights, so the linear + op can probe FP16 first and fall through to the FP8 path unchanged.""" + with _FP16_REGISTRY_LOCK: + return _FP16_REGISTRY.get(weight.data_ptr()) + + +def all_fp16_states() -> list[Fp16LayerState]: + with _FP16_REGISTRY_LOCK: + return list(_FP16_REGISTRY.values()) + + +def clear_fp16_registry() -> None: + with _FP16_REGISTRY_LOCK: + _FP16_REGISTRY.clear() diff --git a/miner/vllm-miner/src/vllm_miner/fp16_mining.py b/miner/vllm-miner/src/vllm_miner/fp16_mining.py new file mode 100644 index 000000000..c237bfe7f --- /dev/null +++ b/miner/vllm-miner/src/vllm_miner/fp16_mining.py @@ -0,0 +1,202 @@ +"""Per-forward FP16 (A100) search + winner submission. + +The FP16 analogue of the FP8 ``pipeline.run_mining_forward`` + ``winners``: +``pearl_gemm.fp16_miner.search_block`` already fuses the whole per-attempt chain +(commit -> seed chain -> noise -> noisy-quant -> full-matrix lottery search -> +hit decode + host policy), so this module only has to: + +1. admit the launch through the shared ``AsyncLoopManager`` gate (retain-winner, + job freshness) exactly as FP8 does; +2. build the FP16 job statement (``Fp16JobParams``) from the committed patterns + and the proposed header's ``nbits``, run ``search_block`` under the + process-wide producer/attempt gates; +3. on an admissible ``WinningTile``, assemble the committed-operand opening + (:class:`miner_base.fp16_block_submission.Fp16OpenedBlock`) at the winning + *contiguous* tile and hand it to the manager's bounded submission executor + (``handle_submit_block``) -- the same executor the FP8 winner uses; the + executor dispatches ``submit_fp16_block`` by the job's cert version. + +Unlike FP8 this is fully synchronous: ``search_block`` returns the decoded +winner on the calling stream, so there is no persistent hit signal, no +completion lease, and no event-gated winner callback. The layer's serving +output is a plain BF16 linear produced by the caller; the search is a side +effect that never feeds serving. + +Everything here needs ``torch`` + ``pearl_gemm`` (the A100 kernels) and an +sm_80 device, so it is import-time light and GPU-work lazy: nothing runs off an +A100 with a V5 job. +""" + +from __future__ import annotations + +import struct + +import torch +from miner_base.fp16_block_submission import Fp16OpenedBlock +from miner_utils import get_logger +from pearl_gateway.comm.dataclasses import MiningJob + +from .capture import gpu_mining_producer, mining_launches_suspended +from .fp16_layer import FP16_TILE_H, Fp16LayerState +from .health import mining_attempt +from .mining_state import get_async_manager + +_LOGGER = get_logger(__name__) + +# Winner handoff must not wait forever behind saturated proof capacity; matches +# the FP8 winner handoff budget (winners.py::_WINNER_HANDOFF_TIMEOUT_S). +_WINNER_HANDOFF_TIMEOUT_S = 30.0 + +# FP16 difficulty comes from the proposed header's compact ``nbits`` (last u32 +# of the 76-byte header), exactly as the verifier takes its default difficulty. +_HEADER_NBITS_OFFSET = 72 + + +def _header_nbits(header_bytes: bytes) -> int: + if len(header_bytes) != 76: + raise ValueError(f"proposed header must be 76 bytes, got {len(header_bytes)}") + return struct.unpack_from(" torch.Tensor: + """The FP16 activation operand ``A`` (m x k), its rows truncated to a whole + number of h=4 row tiles. + + The committed A is exactly what ``search_block`` commits and what the + certificate opens, so any rows beyond the last full tile (never searchable) + are dropped rather than zero-padded: a padded row could latch a winning tile + on zeros that the opened real activation would not reproduce.""" + usable = x2d.shape[0] - (x2d.shape[0] % FP16_TILE_H) + if usable <= 0: + return x2d[:0] + a = x2d[:usable] + if a.dtype == torch.float16: + return a.contiguous() + return a.to(torch.float16).contiguous() + + +def run_fp16_mining_forward(state: Fp16LayerState, job: MiningJob, x2d: torch.Tensor) -> None: + """Run the FP16 search for one forward and submit an admissible winner. + + ``x2d`` is the ``(m_tokens, k)`` serving activation (any float dtype viewable + as FP16); only whole h=4 row tiles are mined. Never raises into serving: a + deterministic kernel failure disables the layer, an OOM is swallowed (the + shared device cooldown owns backoff), and a declined admission is a no-op. + """ + if not state.mineable or mining_launches_suspended(): + return + if torch.cuda.is_current_stream_capturing(): + # Per-launch host machinery is illegal inside a CUDA-graph capture. + return + try: + _attempt_fp16_launch(state, job, x2d) + except torch.cuda.OutOfMemoryError: + _LOGGER.warning(f"FP16 mining OOM on {state.weight.device}; serving continues unmined") + except Exception as exc: + state.disable_mining(f"deterministic FP16 forward failure ({type(exc).__name__})") + + +def _attempt_fp16_launch(state: Fp16LayerState, job: MiningJob, x2d: torch.Tensor) -> None: + from pearl_gemm.fp16_miner import search_block + + manager = get_async_manager() + with manager.mining_launch_admission(job) as decision: + # retain_winner is off when no proof could be submitted (no-gateway, + # skip-submission, a non-V5 job, or closed admission); running the + # search then only burns an A100 forward, so decline like FP8 does. + if not decision.launch or not decision.retain_winner: + return + + device = state.weight.device + a16 = _to_committed_activation(x2d, device) + if a16.shape[0] == 0: + return + header_bytes = bytes(job.incomplete_header_bytes) + params = _job_params(state, a16.shape[0], _header_nbits(header_bytes)) + + with gpu_mining_producer() as admitted: + if not admitted: + return + with mining_attempt(device) as attempt: + if not attempt: + return + winner = search_block(header_bytes, a16, state.weight, params, device) + attempt.mark_success(winner.found) + + if not winner.found: + return + if winner.report is not None and not winner.report.accept: + _LOGGER.info( + f"FP16 lottery winner failed host policy on {state.layer_name} " + f"(tile={winner.tile_row},{winner.tile_col}); filtered before submission" + ) + return + + _submit_fp16_winner(state, job, a16, winner) + + +def _submit_fp16_winner( + state: Fp16LayerState, job: MiningJob, a16: torch.Tensor, winner +) -> None: + """Assemble the committed-operand opening for the winning tile and hand it to + the manager's bounded submission executor. + + The committed A is exactly the ``a16`` the search ran on, and B is the + layer's stable host weight copy; the winning tile is contiguous, so the + grid coordinates ``(tile_row, tile_col)`` name the opened global rows + directly (``create_fp16_proof`` resolves ``base + tile_offsets``).""" + manager = get_async_manager() + if job != manager.get_mining_job(): + _LOGGER.info(f"dropping FP16 winner for replaced job on {state.layer_name}") + return + + opened = Fp16OpenedBlock( + a=a16.detach().to("cpu"), + b=state.weight_cpu, + k=state.k, + m=a16.shape[0], + n=state.n, + rows_pattern=state.rows_pattern, + cols_pattern=state.cols_pattern, + tile_row=winner.tile_row, + tile_col=winner.tile_col, + r=state.r, + ) + _LOGGER.info( + f"FP16 block candidate! layer={state.layer_name} " + f"tile=({winner.tile_row}, {winner.tile_col}) m={opened.m} n={state.n} k={state.k}" + ) + submitted = manager.handle_submit_block(opened, job, timeout=_WINNER_HANDOFF_TIMEOUT_S) + if submitted: + _LOGGER.info(f"FP16 winner handed off for proof construction ({state.layer_name})") + else: + _LOGGER.error(f"FP16 winner was not queued for submission ({state.layer_name})") diff --git a/miner/vllm-miner/src/vllm_miner/linear_op.py b/miner/vllm-miner/src/vllm_miner/linear_op.py index ee8411b41..2892a4954 100644 --- a/miner/vllm-miner/src/vllm_miner/linear_op.py +++ b/miner/vllm-miner/src/vllm_miner/linear_op.py @@ -172,13 +172,71 @@ def _validate_bf16_contract(x: torch.Tensor, bias: torch.Tensor | None) -> None: raise TypeError(f"pearl::apply_linear requires bfloat16 bias, got {bias.dtype}") +def _try_mine_fp16(state, x2d: torch.Tensor) -> None: + """Opportunistically run the FP16 (A100/v5) search for one forward. + + FP16 does not fuse mining into serving: the layer's output is a plain linear + (computed by the caller) and this runs the standalone search as a side + effect, gated exactly like the FP8 eager path. A non-V5 live job, or no job, + is a no-op (the manager's admission declines a non-submittable scheme).""" + if _eager_mining_blocked_fp16(state, x2d.shape[0]): + return + from .fp16_mining import run_fp16_mining_forward + from .job_prep import current_job + + job = current_job() + if job is None: + return + run_fp16_mining_forward(state, job, x2d.contiguous()) + + +def _eager_mining_blocked_fp16(state, m_tokens: int) -> bool: + return ( + not state.mineable + or _mining_disabled() + or m_tokens < runtime_settings().min_mining_tokens + or in_graph_setup_no_mining() + or mining_launches_suspended() + ) + + +def _serve_fp16_linear( + state, x2d: torch.Tensor, bias: torch.Tensor | None +) -> torch.Tensor: + """The FP16 layer's serving output: a plain linear against the committed + FP16 weight, returned in the activation (BF16) dtype.""" + out = torch.nn.functional.linear(x2d.to(state.weight.dtype), state.weight) + out = out.to(x2d.dtype) + if bias is not None: + out = out + bias + return out + + @torch.library.impl(_LIB, "apply_linear", "CUDA") def _apply_linear_impl( x: torch.Tensor, weight: torch.Tensor, bias: torch.Tensor | None ) -> torch.Tensor: _validate_bf16_contract(x, bias) - state = lookup_state(weight) x2d = x.reshape(-1, x.shape[-1]) + + # FP16 (A100/v5) is a parallel branch probed first: an FP16-registered + # weight serves a plain linear and mines via the standalone search; an + # FP8-registered or unregistered weight returns None here and falls through + # to the FP8 path below, which stays byte-identical to its prior behavior. + from .fp16_layer import lookup_fp16_state + + fp16_state = lookup_fp16_state(weight) + if fp16_state is not None: + if x2d.shape[1] != fp16_state.k or x2d.device != fp16_state.weight.device: + raise ValueError( + f"pearl::apply_linear expected (*, {fp16_state.k}) on " + f"{fp16_state.weight.device}, got {tuple(x2d.shape)} on {x2d.device}" + ) + _try_mine_fp16(fp16_state, x2d) + out = _serve_fp16_linear(fp16_state, x2d, bias) + return out.reshape(*x.shape[:-1], out.shape[-1]) + + state = lookup_state(weight) if x2d.shape[1] != state.k or x2d.device != state.weight.device: raise ValueError( f"pearl::apply_linear expected (*, {state.k}) on {state.weight.device}, " diff --git a/miner/vllm-miner/tests/test_fp16_mining_dispatch.py b/miner/vllm-miner/tests/test_fp16_mining_dispatch.py new file mode 100644 index 000000000..925b83f82 --- /dev/null +++ b/miner/vllm-miner/tests/test_fp16_mining_dispatch.py @@ -0,0 +1,212 @@ +"""FP16 (A100/v5) per-forward driver: search -> winner -> submission routing. + +Exercises ``vllm_miner.fp16_mining.run_fp16_mining_forward`` with the A100 +search (``pearl_gemm.fp16_miner.search_block``), the async manager, and the +capture/health gates all stubbed -- the pure runtime glue that turns a decoded +``WinningTile`` into an ``Fp16OpenedBlock`` handed to the manager's bounded +submission executor at the winning contiguous tile. + +Needs ``torch`` (the driver imports it); skipped in the proof-only interpreter. +The GPU search and ``pearl_mining`` proof construction are not invoked here -- +that chain is covered where it can run (``test_fp16_submission_glue`` in +miner-base and the GA100 kernel tests). +""" + +from __future__ import annotations + +import struct +import sys +import types +from dataclasses import dataclass + +import pytest + +torch = pytest.importorskip("torch") + +from vllm_miner import fp16_mining # noqa: E402 +from vllm_miner.fp16_layer import FP16_COLS_PATTERN, FP16_ROWS_PATTERN # noqa: E402 + + +def _header(nbits: int = 0x207FFFFF) -> bytes: + return struct.pack(" None: + self.accept = accept + + +class _FakeManager: + def __init__(self, job, launch=True, retain=True): + self._job = job + self._decision = types.SimpleNamespace(launch=launch, retain_winner=retain) + self.submitted = [] + + def mining_launch_admission(self, job): + from contextlib import contextmanager + + decision = self._decision + + @contextmanager + def _cm(): + yield decision + + return _cm() + + def get_mining_job(self): + return self._job + + def handle_submit_block(self, opening, job, *, timeout=None): + self.submitted.append((opening, job, timeout)) + return True + + +@pytest.fixture() +def patched(monkeypatch): + """Stub the admission/producer/attempt gates and inject a fake + ``pearl_gemm.fp16_miner`` so the driver runs without a GPU.""" + from contextlib import contextmanager + + @contextmanager + def _producer(): + yield True + + class _Attempt: + def __enter__(self): + return self + + def __exit__(self, *a): + return False + + def __bool__(self): + return True + + def mark_success(self, *a): + pass + + monkeypatch.setattr(fp16_mining, "mining_launches_suspended", lambda: False) + monkeypatch.setattr(fp16_mining, "gpu_mining_producer", _producer) + monkeypatch.setattr(fp16_mining, "mining_attempt", lambda device: _Attempt()) + monkeypatch.setattr(torch.cuda, "is_current_stream_capturing", lambda: False) + + # Fake pearl_gemm.fp16_miner.{search_block,Fp16JobParams,Fp16OperandParams}. + recorded = {} + + def fake_search_block(header, a, b, params, device): + recorded["call"] = (bytes(header), a.shape[0], b.shape[0], params) + return recorded["winner"] + + fake_mod = types.ModuleType("pearl_gemm.fp16_miner") + fake_mod.search_block = fake_search_block + fake_mod.Fp16JobParams = lambda **kw: types.SimpleNamespace(**kw) + fake_mod.Fp16OperandParams = lambda **kw: types.SimpleNamespace(**kw) + # _search_patterns imports from pearl_gemm.fp16_pipeline; stub its AxisPattern. + fake_pipe = types.ModuleType("pearl_gemm.fp16_pipeline") + fake_pipe.AxisPattern = types.SimpleNamespace(new=lambda dims: ("pattern", tuple(dims))) + monkeypatch.setitem(sys.modules, "pearl_gemm.fp16_miner", fake_mod) + monkeypatch.setitem(sys.modules, "pearl_gemm.fp16_pipeline", fake_pipe) + return recorded + + +def _state(n=128, k=256): + w = torch.zeros(n, k, dtype=torch.float16) + return _FakeState(weight=w, weight_cpu=w.clone(), n=n, k=k) + + +def test_admissible_winner_is_submitted_at_its_tile(patched, monkeypatch): + from miner_base.fp16_block_submission import Fp16OpenedBlock + + job = _Job(_header()) + mgr = _FakeManager(job) + monkeypatch.setattr(fp16_mining, "get_async_manager", lambda: mgr) + patched["winner"] = _WinningTile(found=True, tile_row=1, tile_col=2, report=_Report(True)) + + st = _state() + x2d = torch.zeros(8, st.k, dtype=torch.bfloat16) # 8 rows -> 2 whole h=4 tiles + fp16_mining.run_fp16_mining_forward(st, job, x2d) + + assert len(mgr.submitted) == 1 + opening, submitted_job, _timeout = mgr.submitted[0] + assert isinstance(opening, Fp16OpenedBlock) + assert (opening.tile_row, opening.tile_col) == (1, 2) + assert opening.m == 8 and opening.n == st.n and opening.k == st.k + assert submitted_job is job + # The search committed exactly the bucketed activation + the full weight. + _hdr, m_searched, n_searched, _params = patched["call"] + assert m_searched == 8 and n_searched == st.n + + +def test_no_winner_is_not_submitted(patched, monkeypatch): + job = _Job(_header()) + mgr = _FakeManager(job) + monkeypatch.setattr(fp16_mining, "get_async_manager", lambda: mgr) + patched["winner"] = _WinningTile(found=False) + fp16_mining.run_fp16_mining_forward(_state(), job, torch.zeros(8, 256, dtype=torch.bfloat16)) + assert mgr.submitted == [] + + +def test_policy_inadmissible_winner_is_filtered(patched, monkeypatch): + job = _Job(_header()) + mgr = _FakeManager(job) + monkeypatch.setattr(fp16_mining, "get_async_manager", lambda: mgr) + patched["winner"] = _WinningTile(found=True, report=_Report(False)) + fp16_mining.run_fp16_mining_forward(_state(), job, torch.zeros(8, 256, dtype=torch.bfloat16)) + assert mgr.submitted == [] + + +def test_declined_admission_skips_search(patched, monkeypatch): + job = _Job(_header()) + mgr = _FakeManager(job, retain=False) # no proof could be submitted + monkeypatch.setattr(fp16_mining, "get_async_manager", lambda: mgr) + patched["winner"] = _WinningTile(found=True, report=_Report(True)) + fp16_mining.run_fp16_mining_forward(_state(), job, torch.zeros(8, 256, dtype=torch.bfloat16)) + assert "call" not in patched # search_block never ran + assert mgr.submitted == [] + + +def test_sub_tile_activation_is_not_mined(patched, monkeypatch): + # Fewer than h=4 rows -> no whole tile -> nothing searched. + job = _Job(_header()) + mgr = _FakeManager(job) + monkeypatch.setattr(fp16_mining, "get_async_manager", lambda: mgr) + patched["winner"] = _WinningTile(found=True, report=_Report(True)) + fp16_mining.run_fp16_mining_forward(_state(), job, torch.zeros(3, 256, dtype=torch.bfloat16)) + assert "call" not in patched + assert mgr.submitted == [] + + +def test_header_nbits_parses_trailing_u32(): + assert fp16_mining._header_nbits(_header(0x1D00FFFF)) == 0x1D00FFFF diff --git a/node/blockchain/solve.go b/node/blockchain/solve.go index b50d02fe6..0b2c2c6b1 100644 --- a/node/blockchain/solve.go +++ b/node/blockchain/solve.go @@ -23,6 +23,8 @@ func SolveBlock(header *wire.BlockHeader, params *chaincfg.Params, height int32) if params.Net == wire.SimNet { switch version { + case wire.CertificateVersionV5: + return &wire.CertificateV5{ProofData: []byte{0x00}}, nil case wire.CertificateVersionV4: return &wire.CertificateV4{ProofData: []byte{0x00}}, nil case wire.CertificateVersionV3: @@ -42,5 +44,8 @@ func SolveBlock(header *wire.BlockHeader, params *chaincfg.Params, height int32) if version == wire.CertificateVersionV4 { return nil, fmt.Errorf("FP8 (V4) CPU mining is not available; submit an fp8 certificate") } + if version == wire.CertificateVersionV5 { + return nil, fmt.Errorf("FP16 (V5) CPU mining is not available; submit an fp16 certificate") + } return zkpow.Mine(header, version) } diff --git a/node/blockchain/validate.go b/node/blockchain/validate.go index 78a70c95f..f192ee330 100644 --- a/node/blockchain/validate.go +++ b/node/blockchain/validate.go @@ -515,8 +515,9 @@ func CheckBlockSanity(block *btcutil.Block, chainParams *chaincfg.Params, timeSo // carry a dense (non-MoE) proof // - At and after RankPenaltyForkHeight (softfork): the proof's noise rank // must meet a minimum and its jackpot must meet a difficulty bound scaled -// for that rank. V4 fp8 public data is a different encoding, so this -// rule is not applied to V4. +// for that rank. V4 fp8 public data is a different encoding and V5 (FP16) +// carries no public-data blob at all (its noise rank is fixed), so this +// rule is not applied to V4 or V5. // // These rules run here rather than alongside the proof verification in // checkProofOfWork because activation depends on the block height, which the @@ -548,7 +549,14 @@ func CheckCertificateRules(header *wire.BlockHeader, cert wire.BlockCertificate, return ruleError(ErrDisallowedCertVersion, str) } - if cert.Version() != wire.CertificateVersionV4 && + // The rank-penalty rule reads a version-specific public-data encoding, so it + // applies only to the versions that carry one. V4 (fp8) uses a different + // encoding and V5 (FP16/A100) carries no public-data blob at all — its noise + // rank is fixed, not a penalised dimension, and CheckRankPenalty would reject + // its nil public data outright — so both are exempt. + rankPenaltyExempt := cert.Version() == wire.CertificateVersionV4 || + cert.Version() == wire.CertificateVersionV5 + if !rankPenaltyExempt && params.IsRankPenaltyForkActive(height) && flags&BFNoPoWCheck != BFNoPoWCheck { if err := zkpow.CheckRankPenalty(header.Bits, cert.PublicDataBytes()); err != nil { str := fmt.Sprintf("certificate fails the rank penalty rule at "+ diff --git a/node/chaincfg/params.go b/node/chaincfg/params.go index a7e24b8fd..a37ab6f51 100644 --- a/node/chaincfg/params.go +++ b/node/chaincfg/params.go @@ -288,6 +288,20 @@ type Params struct { // scheduled (V4 supersedes V3), or before MoEForkHeight otherwise. Fp8ForkHeight int32 + // Fp16ForkHeight is the block height at which the FP16 (A100) hardfork + // activates: at and after it blocks must carry a V5 certificate + // (wire.CertificateVersionV5). A value of 0 disables the fork. + // + // STAGED, NOT ACTIVATED: this is 0 (disabled) on every network, so + // RequiredCertVersion never returns V5 and behavior is unchanged. It is the + // fork-height half of the V5 activation; the other half is allowing V5 in + // wire.IsCertVersionAllowed (deliberately still false). Activating V5 means + // setting this height AND flipping that allow-list entry together — see the + // activation note in node/wire/certificate.go. + // + // Must not activate before Fp8ForkHeight (V5 supersedes V4). + Fp16ForkHeight int32 + // Mempool parameters RelayNonStdTxs bool @@ -337,11 +351,22 @@ func (p *Params) IsFp8ForkActive(height int32) bool { return p.Fp8ForkHeight != 0 && height >= p.Fp8ForkHeight } +// IsFp16ForkActive reports whether the FP16 (A100) hardfork is active at the +// given block height. The fork is disabled when Fp16ForkHeight is 0 (its value +// on every network today — the fork is staged but not activated). +func (p *Params) IsFp16ForkActive(height int32) bool { + return p.Fp16ForkHeight != 0 && height >= p.Fp16ForkHeight +} + // RequiredCertVersion returns the block certificate version that a block at the -// given height must use under the strict hardfork cutovers: V4 at and after the -// FP8 fork, V3 at and after the salted noise-seed fork, V2 at and after the MoE -// fork, V1 before those (and always, when the forks are disabled). +// given height must use under the strict hardfork cutovers: V5 at and after the +// FP16 fork, V4 at and after the FP8 fork, V3 at and after the salted noise-seed +// fork, V2 at and after the MoE fork, V1 before those (and always, when the forks +// are disabled). The FP16 branch is inert until Fp16ForkHeight is set (staged). func (p *Params) RequiredCertVersion(height int32) wire.CertificateVersion { + if p.IsFp16ForkActive(height) { + return wire.CertificateVersionV5 + } if p.IsFp8ForkActive(height) { return wire.CertificateVersionV4 } diff --git a/node/chaincfg/params_test.go b/node/chaincfg/params_test.go index 7bd24b17c..e39ed1bdb 100644 --- a/node/chaincfg/params_test.go +++ b/node/chaincfg/params_test.go @@ -214,6 +214,59 @@ func TestShippedNetworksFp8ForkHeights(t *testing.T) { "simnet must require V4 certificates from genesis") } +// TestFp16ForkActivation verifies the (staged) V5 activation boundary: when +// Fp16ForkHeight is set, RequiredCertVersion returns V5 at and after it. +func TestFp16ForkActivation(t *testing.T) { + const forkHeight = int32(400) + p := Params{MoEForkHeight: 100, SaltedSeedForkHeight: 200, Fp8ForkHeight: 300, Fp16ForkHeight: forkHeight} + + tests := []struct { + name string + height int32 + wantActive bool + wantVersion wire.CertificateVersion + }{ + {"just before fork", forkHeight - 1, false, wire.CertificateVersionV4}, + {"at fork height", forkHeight, true, wire.CertificateVersionV5}, + {"after fork height", forkHeight + 1, true, wire.CertificateVersionV5}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.wantActive, p.IsFp16ForkActive(tt.height)) + require.Equal(t, tt.wantVersion, p.RequiredCertVersion(tt.height)) + }) + } +} + +// TestFp16ForkDisabled confirms the staged-but-off default: with Fp16ForkHeight 0, +// the fork is never active and RequiredCertVersion never returns V5. +func TestFp16ForkDisabled(t *testing.T) { + p := Params{MoEForkHeight: 1, SaltedSeedForkHeight: 1, Fp8ForkHeight: 1, Fp16ForkHeight: 0} + for _, height := range []int32{1, 100, 1_000_000} { + require.False(t, p.IsFp16ForkActive(height)) + require.Equal(t, wire.CertificateVersionV4, p.RequiredCertVersion(height)) + } +} + +// TestShippedNetworksFp16ForkDisabled asserts V5 is staged but NOT activated on +// EVERY network (including regtest/simnet): Fp16ForkHeight must be 0 everywhere, so +// RequiredCertVersion never requires V5 until a deployment sets it (and flips the +// wire.IsCertVersionAllowed allow-list in tandem). +func TestShippedNetworksFp16ForkDisabled(t *testing.T) { + for name, params := range map[string]*Params{ + "mainnet": &MainNetParams, + "testnet": &TestNetParams, + "testnet2": &TestNet2Params, + "regtest": &RegressionNetParams, + "simnet": &SimNetParams, + } { + require.Zerof(t, params.Fp16ForkHeight, "%s must ship with Fp16ForkHeight disabled (V5 staged, not activated)", name) + } + // And V5 is not in the sanity allow-list either (the other half of the gate). + require.False(t, wire.IsCertVersionAllowed(wire.CertificateVersionV5), + "V5 must not be network-allowed while staged") +} + // TestRankPenaltyForkActivation verifies the activation boundary of the // rank-penalty softfork, including the disabled case. func TestRankPenaltyForkActivation(t *testing.T) { diff --git a/node/mining/mining.go b/node/mining/mining.go index eef0aa6f1..04555f43a 100644 --- a/node/mining/mining.go +++ b/node/mining/mining.go @@ -657,6 +657,10 @@ mempoolLoop: // requires at this height, otherwise CheckConnectBlockTemplate rejects it. var certificate wire.BlockCertificate switch g.chainParams.RequiredCertVersion(nextBlockHeight) { + case wire.CertificateVersionV5: + // FP16 (A100) is a submit-direct plaintext cert like V4; template + // assembly needs no special handling beyond the block-hash placeholder. + certificate = &wire.CertificateV5{Hash: msgBlock.BlockHash()} case wire.CertificateVersionV4: certificate = &wire.CertificateV4{Hash: msgBlock.BlockHash()} case wire.CertificateVersionV3: diff --git a/node/wire/certificate.go b/node/wire/certificate.go index 455eb6214..ff9ab06c7 100644 --- a/node/wire/certificate.go +++ b/node/wire/certificate.go @@ -48,9 +48,13 @@ Certificate types implement perfectly mirrored Serialize/Deserialize methods: # NETWORK RESTRICTIONS -CertificateVersionV1 through CertificateVersionV4 are allowed. -IsCertVersionAllowed(v) returns true for all four. blockchain.checkBlockSanity -also validates via IsCertVersionAllowed. +CertificateVersionV1 through CertificateVersionV4 are network-allowed. +IsCertVersionAllowed(v) returns true for those four. blockchain.checkBlockSanity +also validates via IsCertVersionAllowed. CertificateVersionV5 is the FP16 (A100) +header-bound ZK certificate (see certificate_v5.go): it is fully decodable, routable, +and verifiable (VerifyCertificate -> the FP16 FFI), but intentionally NOT yet in +IsCertVersionAllowed — enabling it for consensus is a deployment activation +decision (height / version bits). # GENESIS BLOCKS @@ -59,7 +63,7 @@ Genesis blocks are never verified (hardcoded and trusted), only serialized. # IMPLEMENTATION NOTES -- CertificateMaxSize: 65 KB for every certificate version +- CertificateMaxSize: 65 KB for V1-V4; V5 (FP16/A100 header-bound ZK) uses the larger CertificateV5MaxSize (see MaxCertificateSize) - Integration: MsgHeader.BlockCertificate() and MsgBlock.BlockCertificate() accessors - Storage: Certificate-first serialization, stored with blocks (no separate indexing) */ @@ -73,12 +77,30 @@ import ( "github.com/pearl-research-labs/pearl/node/chaincfg/chainhash" ) -// MaxZKProofSize is the maximum size of a serialized ZK proof blob. +// MaxZKProofSize is the maximum size of a serialized ZK proof blob (V1-V4). const MaxZKProofSize = 60000 -// CertificateMaxSize is the maximum allowed certificate size. Has headroom on top of MaxZKProofSize. +// CertificateMaxSize is the maximum allowed certificate size for V1-V4. Has +// headroom on top of MaxZKProofSize. const CertificateMaxSize = 65000 +// MaxFp16ZkCertProofSize is the ProofData blob cap for a V5 (FP16/A100) header- +// bound ZK certificate. It matches the Rust FFI cap MAX_FP16_ZK_CERT_SIZE +// (256 KiB): the V5 ProofData is a serialized Fp16ZkCertificate (a constant +// ~71 KiB wrapped plonky2 proof + its small public Fp16JobParams), so this is +// generous headroom, not a tight fit. +const MaxFp16ZkCertProofSize = 256 * 1024 + +// CertificateV5MaxSize is the overall encoded-size cap for a V5 certificate: +// the ProofData blob plus the hash, length prefix, ancestor-count varint, and up +// to MaxCertificateV5AncestorHeaders full ancestor headers. +const CertificateV5MaxSize = MaxFp16ZkCertProofSize + 32 + 4 + 1 + MaxCertificateV5AncestorHeaders*MaxBlockHeaderPayload + +// MaxCertificateSizeAnyVersion is the largest MaxCertificateSize across all +// certificate versions, used to bound the per-certificate contribution to the +// block/headers message size caps. V5 (ZK) is the largest. +const MaxCertificateSizeAnyVersion = CertificateV5MaxSize + // CertificateVersion identifies the certificate format version. type CertificateVersion uint32 @@ -88,11 +110,17 @@ const ( CertificateVersionV2 CertificateVersion = 2 CertificateVersionV3 CertificateVersion = 3 CertificateVersionV4 CertificateVersion = 4 + CertificateVersionV5 CertificateVersion = 5 ) -// MaxCertificateSize returns the encoded-size cap for every certificate -// version, including the 4-byte version prefix. -func MaxCertificateSize(CertificateVersion) int { +// MaxCertificateSize returns the encoded-size cap for the given certificate +// version, including the 4-byte version prefix. V5 (FP16/A100 header-bound ZK) +// carries a larger ZK-proof blob than the FP8 V1-V4 versions, so it has its own +// cap; V1-V4 keep CertificateMaxSize. +func MaxCertificateSize(v CertificateVersion) int { + if v == CertificateVersionV5 { + return CertificateV5MaxSize + } return CertificateMaxSize } @@ -133,6 +161,21 @@ func IsCertVersionAllowed(v CertificateVersion) bool { case CertificateVersionV1, CertificateVersionV2, CertificateVersionV3, CertificateVersionV4: return true default: + // CertificateVersionV5 (FP16/A100) is intentionally NOT yet network-allowed: + // it is a genuine consensus activation decision (height / version bits) a + // deployment must make. The node can already decode, route, and fully + // verify a V5 certificate (MsgCertificate dispatch + VerifyCertificate -> + // the FP16 FFI). Until then V5 blocks fail checkBlockSanity. + // + // ACTIVATION (staged, not done): flip V5 into the allow-list above AND set + // chaincfg Params.Fp16ForkHeight (so RequiredCertVersion returns V5 at/after + // that height) — the two must move together. Prerequisites in place: the + // rank-penalty rule exempts V5 (blockchain.CheckCertificateRules), and the + // FP16 FFI now verifies the header-bound ZK certificate (VerifyCertificate -> + // verify_fp16_zk_cert_ffi -> the header-pinned wrapped-proof verify). Remaining + // activation blocker: the verifier currently rebuilds the FP16 wrapper circuit + // per tile geometry (an embedded FP16 verifier cache or the universal wrapper + // is needed before activation — see the zk-pow FFI notes). return false } } @@ -188,6 +231,9 @@ func (m *MsgCertificate) PrlDecode(r io.Reader, pver uint32) error { case CertificateVersionV4: m.Certificate = &CertificateV4{} + case CertificateVersionV5: + m.Certificate = &CertificateV5{} + default: return fmt.Errorf("unsupported certificate version: %d", version) } diff --git a/node/wire/certificate_v4.go b/node/wire/certificate_v4.go index 117eef92c..e1903833f 100644 --- a/node/wire/certificate_v4.go +++ b/node/wire/certificate_v4.go @@ -91,14 +91,20 @@ func (c *CertificateV4) Serialize(w io.Writer) error { } // readFp8Blob reads one length-prefixed (4-byte LE) blob, enforcing the common -// blob-size cap. A zero length decodes as nil. +// FP8 (V1-V4) blob-size cap. A zero length decodes as nil. func readFp8Blob(r io.Reader, fieldName string) ([]byte, error) { + return readBlobCapped(r, fieldName, MaxZKProofSize) +} + +// readBlobCapped reads one length-prefixed (4-byte LE) blob, rejecting a length +// above maxSize before allocating. A zero length decodes as nil. +func readBlobCapped(r io.Reader, fieldName string, maxSize uint32) ([]byte, error) { var length uint32 if err := binary.Read(r, binary.LittleEndian, &length); err != nil { return nil, err } - if length > MaxZKProofSize { - return nil, fmt.Errorf("fp8 %s_len %d exceeds max %d", fieldName, length, MaxZKProofSize) + if length > maxSize { + return nil, fmt.Errorf("%s_len %d exceeds max %d", fieldName, length, maxSize) } if length == 0 { return nil, nil diff --git a/node/wire/certificate_v5.go b/node/wire/certificate_v5.go new file mode 100644 index 000000000..ba678d4e7 --- /dev/null +++ b/node/wire/certificate_v5.go @@ -0,0 +1,138 @@ +// Copyright (c) 2025-2026 The Pearl Research Labs developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "encoding/binary" + "fmt" + "io" + + "github.com/pearl-research-labs/pearl/node/chaincfg/chainhash" +) + +// MaxCertificateV5AncestorHeaders bounds the parent/grandparent witness, matching +// the depth-D (D <= 2) state window the FP16 B-side key is authenticated against. +const MaxCertificateV5AncestorHeaders = 2 + +// CertificateV5 is a version-5 (FP16 / A100) block certificate. It carries a +// self-contained header-bound ZK certificate: a serialized Fp16ZkCertificate +// (the wrapped plonky2 proof + its public Fp16JobParams tuple, including the +// proof-carried ancestor header σ_Δ) plus the full ancestor headers that +// authenticate σ_Δ as a member of the state window. +// +// Unlike the FP8 V4 certificate there is no separate public-data blob: the whole +// certificate statement + witness rides in ProofData (opaque to Go), and +// ProofCommitment binds it. Wire layout: +// +// BlockHash(32) + ProofLen(4) + ProofData + AncestorCount(varint) +// + AncestorHeaders(108 bytes each, parent then grandparent). +// +// ProofData is capped at MaxFp16ZkCertProofSize (the V5 ZK-proof blob is larger +// than the FP8 blob) and the whole certificate at CertificateV5MaxSize. +type CertificateV5 struct { + Hash chainhash.Hash + + // ProofData is the serialized Fp16ZkCertificate (wrapped ZK proof + job). + ProofData []byte + + // AncestorHeaders supplies the parent, then grandparent, for window + // authentication of the proof-carried ancestor. They are excluded from + // ProofCommitment and authenticated through the proposed header's PrevBlock + // hash by the Rust verifier. + AncestorHeaders []BlockHeader +} + +func (c *CertificateV5) Version() CertificateVersion { + return CertificateVersionV5 +} + +func (c *CertificateV5) BlockHash() chainhash.Hash { + return c.Hash +} + +// PublicDataBytes returns nil: V5 carries no separate public-data blob (the FP16 +// statement is embedded in the serialized proof). +func (c *CertificateV5) PublicDataBytes() []byte { + return nil +} + +func (c *CertificateV5) ProofBytes() []byte { + return c.ProofData +} + +// IsMoE returns false: the FP16 scheme is dense. +func (c *CertificateV5) IsMoE() bool { + return false +} + +// ProofCommitment computes SHA256d(CertificateVersion_LE(4) || ProofData), +// binding the whole FP16 certificate to the header chain. V5 commits over +// ProofData (its only committed blob), domain-separated from other versions by +// the version prefix. +func (c *CertificateV5) ProofCommitment() chainhash.Hash { + return proofCommitment(c.Version(), c.ProofData) +} + +// Serialize writes the certificate fields followed by a canonical varint ancestor +// count and the full headers in parent-to-grandparent order. The count is +// mandatory, including zero for a depth-0 certificate (σ_Δ = σ̂). +func (c *CertificateV5) Serialize(w io.Writer) error { + if len(c.AncestorHeaders) > MaxCertificateV5AncestorHeaders { + return fmt.Errorf("too many v5 ancestor headers: %d (max %d)", + len(c.AncestorHeaders), MaxCertificateV5AncestorHeaders) + } + if _, err := w.Write(c.Hash[:]); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint32(len(c.ProofData))); err != nil { + return err + } + if _, err := w.Write(c.ProofData); err != nil { + return err + } + if err := WriteVarInt(w, 0, uint64(len(c.AncestorHeaders))); err != nil { + return err + } + for i := range c.AncestorHeaders { + if err := c.AncestorHeaders[i].Serialize(w); err != nil { + return err + } + } + return nil +} + +func (c *CertificateV5) Deserialize(r io.Reader) error { + if _, err := io.ReadFull(r, c.Hash[:]); err != nil { + return err + } + proofData, err := readBlobCapped(r, "fp16_zk_proof_data", MaxFp16ZkCertProofSize) + if err != nil { + return err + } + count, err := ReadVarInt(r, 0) + if err != nil { + return err + } + if count > MaxCertificateV5AncestorHeaders { + return fmt.Errorf("too many v5 ancestor headers: %d (max %d)", + count, MaxCertificateV5AncestorHeaders) + } + var ancestors []BlockHeader + for range count { + var header BlockHeader + if err := header.Deserialize(r); err != nil { + return err + } + ancestors = append(ancestors, header) + } + c.ProofData = proofData + c.AncestorHeaders = ancestors + return nil +} + +func (c *CertificateV5) SerializedSize() int { + return 32 + 4 + len(c.ProofData) + + VarIntSerializeSize(uint64(len(c.AncestorHeaders))) + len(c.AncestorHeaders)*MaxBlockHeaderPayload +} diff --git a/node/wire/msgblock.go b/node/wire/msgblock.go index dcd0568aa..2d1848cc8 100644 --- a/node/wire/msgblock.go +++ b/node/wire/msgblock.go @@ -311,9 +311,10 @@ func (msg *MsgBlock) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { // Certificate + header + transactions. MaxBlockPayload covers the serialized txs at the 1M-vbyte consensus - // cap; the certificate is excluded from vsize and must be accounted for separately. Every certificate - // version is capped at CertificateMaxSize, so this ensures any valid block can be relayed. - return MaxBlockPayload + CertificateMaxSize + // cap; the certificate is excluded from vsize and must be accounted for separately. Certificates are capped + // per version (V5/FP16 ZK is the largest); MaxCertificateSizeAnyVersion is that maximum, so this ensures any + // valid block of any certificate version can be relayed. + return MaxBlockPayload + MaxCertificateSizeAnyVersion } // BlockHash computes the block identifier hash for this block. diff --git a/node/wire/msgheaders.go b/node/wire/msgheaders.go index e101e6d38..f7d946617 100644 --- a/node/wire/msgheaders.go +++ b/node/wire/msgheaders.go @@ -152,7 +152,9 @@ func (msg *MsgHeaders) Command() string { // MaxPayloadLength returns the maximum length the payload can be for the // receiver. This is part of the Message interface implementation. func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { - return MaxVarIntPayload + ((MaxBlockHeaderPayload + CertificateMaxSize) * MaxBlockHeadersPerMsg) + // Each header may carry a certificate; V5 (FP16 ZK) is the largest version, so + // bound the per-header certificate contribution by MaxCertificateSizeAnyVersion. + return MaxVarIntPayload + ((MaxBlockHeaderPayload + MaxCertificateSizeAnyVersion) * MaxBlockHeadersPerMsg) } // NewMsgHeaders returns a new headers message that conforms to the diff --git a/node/zkpow/fp16_test.go b/node/zkpow/fp16_test.go new file mode 100644 index 000000000..90c31e4a5 --- /dev/null +++ b/node/zkpow/fp16_test.go @@ -0,0 +1,167 @@ +//go:build zkpow + +// Copyright (c) 2025-2026 The Pearl Research Labs developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package zkpow + +import ( + "bytes" + "encoding/binary" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/pearl-research-labs/pearl/node/wire" + "github.com/stretchr/testify/require" +) + +// loadFp16ZkFixture loads the committed real FP16 ZK-cert vector +// (`testdata/fp16_zk_cert_a100.bin`, format `header(76) | u32le cert_len | +// Fp16ZkCertificate bytes`), returning the proposed header bound to a +// CertificateV5 carrying the wrapped-proof cert. Skips if the fixture is absent +// (it is produced by the heavy Rust regenerator + the FP16 verifier cache). +func loadFp16ZkFixture(t *testing.T) (*wire.BlockHeader, *wire.CertificateV5) { + t.Helper() + path := filepath.Join("testdata", "fp16_zk_cert_a100.bin") + raw, err := os.ReadFile(path) + if err != nil { + t.Skipf("FP16 ZK-cert fixture not present (%v); regenerate with the Rust "+ + "api::fp16::zk::fixture::regenerate_zk_cert_fixture test", err) + } + require.Greater(t, len(raw), 80, "fixture too short") + certLen := binary.LittleEndian.Uint32(raw[76:80]) + require.Equal(t, 80+int(certLen), len(raw), "fixture length mismatch") + + header := &wire.BlockHeader{ + Version: int32(binary.LittleEndian.Uint32(raw[0:4])), + Timestamp: time.Unix(int64(binary.LittleEndian.Uint32(raw[68:72])), 0), + Bits: binary.LittleEndian.Uint32(raw[72:76]), + } + copy(header.PrevBlock[:], raw[4:36]) + copy(header.MerkleRoot[:], raw[36:68]) + + cert := &wire.CertificateV5{ProofData: raw[80 : 80+certLen]} + header.ProofCommitment = cert.ProofCommitment() + cert.Hash = header.BlockHash() + return header, cert +} + +// The FP16 (A100) consensus path is the header-bound ZK proof: CertificateV5 +// carries an opaque Fp16ZkCertificate (the wrapped plonky2 proof + its public +// Fp16JobParams) in ProofData, which verifyCertificateV5 hands to the Rust +// verifier verify_fp16_zk_cert_ffi. The committed fixture is a real honest +// certificate, so the accept path below runs end-to-end whenever the embedded +// FP16 verifier cache covers the fixture's degree profile. That cache is a heavy +// offline artifact (one compiled wrapper per profile): the default dev/CI build +// embeds only the sample (smallest-profile) bootstrap blob, which will not cover +// the fixture, so the accept test SKIPS rather than fails when the cache is absent +// or does not cover the geometry (detected via the FFI's "no cached fp16 verifier +// setup" rejection). Build the full fp16_cache.bin (drop FP16_CACHE_SAMPLE) to run +// it for real. The tamper-reject, wire-codec, binding, size-cap, and activation-gate +// tests need no valid proof and always run. + +// fp16CacheMiss reports whether err is the verifier's "geometry not in the +// embedded cache" rejection — i.e. the cache is absent or does not cover the +// fixture's profile, as opposed to a genuine verification failure (which would be +// a real regression that must fail the test). +func fp16CacheMiss(err error) bool { + return err != nil && strings.Contains(err.Error(), "no cached fp16 verifier setup") +} + +// fp16CertFixture builds a CertificateV5 with opaque placeholder ProofData and +// binds the proposed header to it (BlockHash + ProofCommitment), exactly as a +// miner would. The ProofData is NOT a valid Fp16ZkCertificate — it only drives +// the wire/binding/gating tests, which never reach the ZK verifier. +func fp16CertFixture(t *testing.T) (*wire.BlockHeader, *wire.CertificateV5) { + t.Helper() + proofData := make([]byte, 128) + for i := range proofData { + proofData[i] = byte(i * 7) + } + header := &wire.BlockHeader{Version: 1, Bits: 0x207fffff} + for i := range header.PrevBlock { + header.PrevBlock[i] = byte(i) + header.MerkleRoot[i] = byte(0x40 + i) + } + cert := &wire.CertificateV5{ProofData: proofData} + header.ProofCommitment = cert.ProofCommitment() + cert.Hash = header.BlockHash() + return header, cert +} + +// TestVerifyCertificateV5Routes drives the honest ZK-cert fixture through the +// polymorphic VerifyCertificate dispatch -> verifyCertificateV5 -> the Rust +// verify_fp16_zk_cert_ffi (header-bound verify via the embedded FP16 verifier +// cache, O(1) lookup, no circuit rebuild) and requires ACCEPT. +func TestVerifyCertificateV5Routes(t *testing.T) { + header, cert := loadFp16ZkFixture(t) + err := VerifyCertificate(header, cert) + if fp16CacheMiss(err) { + t.Skipf("embedded FP16 verifier cache does not cover the fixture geometry "+ + "(build the full fp16_cache.bin via `FP16_CACHE_SAMPLE= task build:zk-cache` "+ + "or `build_cache - - - src/api/fp16/fp16_cache.bin`): %v", err) + } + require.NoError(t, err, + "the honest FP16 ZK certificate must route through VerifyCertificate and verify") +} + +// TestVerifyCertificateV5Tampered flips a proof byte (re-binding the header so the +// tamper reaches the FFI); the header-bound ZK verification must reject it. +func TestVerifyCertificateV5Tampered(t *testing.T) { + header, cert := loadFp16ZkFixture(t) + cert.ProofData[len(cert.ProofData)-1] ^= 0x01 + header.ProofCommitment = cert.ProofCommitment() + cert.Hash = header.BlockHash() + require.ErrorContains(t, VerifyCertificate(header, cert), "rejected", + "a tampered V5 ZK certificate must be rejected") +} + +// TestVerifyCertificateV5ProofCommitmentMismatch confirms a V5 certificate whose +// proof commitment does not match the header is rejected before the FFI (so it +// needs no valid proof). +func TestVerifyCertificateV5ProofCommitmentMismatch(t *testing.T) { + header, cert := fp16CertFixture(t) + cert.ProofData[0] ^= 0x01 // changes ProofCommitment but header still binds the old one + require.ErrorContains(t, VerifyCertificate(header, cert), "proof commitment mismatch") +} + +// TestCertificateV5WireRoundTrip confirms the V5 wire codec is symmetric over an +// opaque ZK-cert ProofData blob and that V5 stays out of the network allow-list. +func TestCertificateV5WireRoundTrip(t *testing.T) { + _, cert := fp16CertFixture(t) + var buf bytes.Buffer + msg := &wire.MsgCertificate{Certificate: cert} + require.NoError(t, msg.PrlEncode(&buf, 0)) + + var back wire.MsgCertificate + require.NoError(t, back.PrlDecode(&buf, 0)) + rt, ok := back.Certificate.(*wire.CertificateV5) + require.True(t, ok, "decoded certificate must be a CertificateV5") + require.Equal(t, cert.Hash, rt.Hash) + require.Equal(t, cert.ProofData, rt.ProofData) + require.Equal(t, cert.ProofCommitment(), rt.ProofCommitment()) + // V5 is decodable/routable/verifiable but intentionally gated out of the + // network allow-list pending a deployment activation decision. + require.False(t, wire.IsCertVersionAllowed(wire.CertificateVersionV5), + "V5 must stay out of the network allow-list until consensus activation") +} + +// TestCertificateV5OversizeRejected confirms the version-aware size cap rejects a +// V5 certificate whose ProofData exceeds the V5 ceiling on decode. +func TestCertificateV5OversizeRejected(t *testing.T) { + oversize := wire.MaxCertificateSize(wire.CertificateVersionV5) + 1 + cert := &wire.CertificateV5{ProofData: make([]byte, oversize)} + var buf bytes.Buffer + msg := &wire.MsgCertificate{Certificate: cert} + // Encoding may succeed locally; the decode side must enforce the cap. + if err := msg.PrlEncode(&buf, 0); err != nil { + return // encoder already refuses oversize, which is also acceptable + } + var back wire.MsgCertificate + require.Error(t, back.PrlDecode(&buf, 0), + "a V5 certificate above the version-aware cap must fail to decode") +} diff --git a/node/zkpow/testdata/fp16_plain_proof_a100.bin b/node/zkpow/testdata/fp16_plain_proof_a100.bin new file mode 100644 index 000000000..a1667a78f Binary files /dev/null and b/node/zkpow/testdata/fp16_plain_proof_a100.bin differ diff --git a/node/zkpow/testdata/fp16_zk_cert_a100.bin b/node/zkpow/testdata/fp16_zk_cert_a100.bin new file mode 100644 index 000000000..e71140b9b Binary files /dev/null and b/node/zkpow/testdata/fp16_zk_cert_a100.bin differ diff --git a/node/zkpow/verify.go b/node/zkpow/verify.go index 2e9deba4a..a8cd6d1af 100644 --- a/node/zkpow/verify.go +++ b/node/zkpow/verify.go @@ -42,6 +42,8 @@ const MinNoiseRank = C.MIN_NOISE_RANK // V1 certificates (CertificateV1) are verified using the V1 proof format. func VerifyCertificate(header *wire.BlockHeader, cert wire.BlockCertificate) error { switch c := cert.(type) { + case *wire.CertificateV5: + return verifyCertificateV5(header, c) case *wire.CertificateV4: return verifyCertificateV4(header, c) case *wire.CertificateV3: @@ -290,6 +292,101 @@ func CheckRankPenalty(bits uint32, publicData []byte) error { } } +// ================================================================================ +// V5 (FP16 / A100) CONSENSUS CERTIFICATE VERIFICATION +// ================================================================================ + +// verifyCertificateV5 verifies an FP16 (A100) header-bound ZK consensus +// certificate. It mirrors verifyCertificateV4: it checks the block-hash and +// proof-commitment binding, serializes the proposed header followed by the +// ancestor headers, and hands them with the serialized Fp16ZkCertificate +// (CertificateV5.ProofData, carried opaquely) to the Rust verifier. Rust owns +// window authentication of the proof-carried ancestor (the SHA256d hash-walk) and +// the full header-bound ZK verification (wrapped-proof verify + header-pinned +// keys/seeds/jackpot-key + native difficulty). The difficulty target is the +// proposed header's own Bits. +func verifyCertificateV5(header *wire.BlockHeader, cert *wire.CertificateV5) error { + certHash := cert.BlockHash() + blockHash := header.BlockHash() + if !certHash.IsEqual(&blockHash) { + return fmt.Errorf("block hash mismatch: certificate has %s, header has %s", + certHash, blockHash) + } + proofCommitment := cert.ProofCommitment() + if header.ProofCommitment != proofCommitment { + return fmt.Errorf("proof commitment mismatch: header has %s, certificate has %s", + header.ProofCommitment, proofCommitment) + } + + proofData := cert.ProofBytes() + if len(proofData) == 0 { + return fmt.Errorf("empty fp16 proof") + } + if len(cert.AncestorHeaders) > wire.MaxCertificateV5AncestorHeaders { + return fmt.Errorf("v5 certificate has %d ancestor headers, max %d", + len(cert.AncestorHeaders), wire.MaxCertificateV5AncestorHeaders) + } + + // Serialize the proposed header, then the ancestors (parent, grandparent), in + // canonical 108-byte wire form; Rust authenticates the window from these. + var headers bytes.Buffer + headers.Grow((1 + len(cert.AncestorHeaders)) * wire.MaxBlockHeaderPayload) + if err := header.Serialize(&headers); err != nil { + return err + } + for i := range cert.AncestorHeaders { + if err := cert.AncestorHeaders[i].Serialize(&headers); err != nil { + return err + } + } + // nil override: consensus checks against the proposed header's own Bits. + return verifyFp16ZkCertFFI(headers.Bytes(), proofData, nil) +} + +// verifyFp16ZkCertFFI hands a serialized header window and a serialized +// Fp16ZkCertificate (the wrapped ZK proof + its public Fp16JobParams) to the Rust +// consensus verifier (verify_fp16_zk_cert_ffi). nbitsOverride selects the +// difficulty target: nil uses the proposed header's own Bits (FFI value 0); a +// non-nil value is a pool-share target. +func verifyFp16ZkCertFFI(headerBytes, certBytes []byte, nbitsOverride *uint32) error { + if len(headerBytes) == 0 { + return fmt.Errorf("empty fp16 header window") + } + if len(certBytes) == 0 { + return fmt.Errorf("empty fp16 proof") + } + + var pinner runtime.Pinner + pinner.Pin(&headerBytes[0]) + pinner.Pin(&certBytes[0]) + defer pinner.Unpin() + + var cNbits C.uint32_t + if nbitsOverride != nil { + cNbits = C.uint32_t(*nbitsOverride) + } + + var errorBuf [C.ERROR_MSG_MAX_SIZE]C.char + result := C.verify_fp16_zk_cert_ffi( + (*C.uint8_t)(unsafe.Pointer(&headerBytes[0])), C.uintptr_t(len(headerBytes)), + (*C.uint8_t)(unsafe.Pointer(&certBytes[0])), C.uintptr_t(len(certBytes)), + cNbits, + &errorBuf[0], + ) + msg := C.GoString(&errorBuf[0]) + + switch result { + case 0: + return nil + case 1: + return fmt.Errorf("fp16 proof rejected: %s", msg) + case 2: + return fmt.Errorf("fp16 verification system error: %s", msg) + default: + return fmt.Errorf("unknown fp16 verification result %d: %s", result, msg) + } +} + // ================================================================================ // FFI CONVERSION HELPERS // ================================================================================ diff --git a/py-pearl-mining/src/lib.rs b/py-pearl-mining/src/lib.rs index 5d82312d1..05f159ad6 100644 --- a/py-pearl-mining/src/lib.rs +++ b/py-pearl-mining/src/lib.rs @@ -18,12 +18,17 @@ use zk_pow::api::fp8::plain_proof::{MoeWitness, PlainProofV4}; use zk_pow::api::fp8::public_params::{ CommonParams, Device, HashId, MoeParams, OperandParams, Quant, }; +use zk_pow::api::fp16::params::Fp16Device; +use zk_pow::api::fp16::plain_proof::{ + Fp16JobParams, Fp16MatrixProof, Fp16OperandParams, Fp16PlainProof, +}; +use zk_pow::api::fp16::verify as fp16_verify; use zk_pow::api::layout::{AxisPattern, DimType}; use zk_pow::api::primitives::IncompleteBlockHeader; use zk_pow::api::seed::SeedDerivation; use zk_pow::api::verify as fp8_verify; use zk_pow::ffi::plain_proof::{CertificateVersion, MatrixMerkleProof, MoEProofParams, PlainProof}; -use zk_pow::ffi::pybind::{PyFp8Prover, PyFp8Verifier}; +use zk_pow::ffi::pybind::{PyFp16Prover, PyFp8Prover, PyFp8Verifier}; use zk_pow::v2::api::sanity_checks; use zk_pow::v1::api::proof as v1_proof; @@ -268,6 +273,25 @@ fn verify_plain_proof_v4( } } +/// Cert v5 (PlainFP16 / A100) plain verification against the FP16 verifier. +/// +/// Like v4, the proof carries its own `ancestor_header` (σ_Δ) in the job; +/// `block_header` (σ̂) keys the A side and supplies the default difficulty. +/// Authenticating σ_Δ (a member of the state window) is the caller's +/// responsibility. +#[pyfunction] +#[pyo3(signature = (block_header, plain_proof, nbits_override=None))] +fn verify_fp16_plain_proof( + block_header: IncompleteBlockHeader, + plain_proof: Fp16PlainProof, + nbits_override: Option, +) -> PyResult<(bool, String)> { + match fp16_verify::verify_fp16_plain_proof(&block_header, &plain_proof, nbits_override) { + Ok(()) => Ok((true, "Mining solution verified successfully".into())), + Err(e) => Ok((false, e.to_string())), + } +} + #[pyfunction] fn penalized_target_bound<'py>( py: Python<'py>, @@ -485,6 +509,15 @@ fn not_implemented_fp8() -> PyErr { ) } +/// Cert v5 (FP16/A100) proving does not go through this int7-shaped dispatcher: +/// the FP16 ZK prover takes the opened tile operand codes + the public job (not a +/// `PlainProof`), so the miner drives it directly via the `Fp16Prover` class. +fn not_implemented_fp16() -> PyErr { + pyo3::exceptions::PyNotImplementedError::new_err( + "cert v5 (FP16) proving uses the Fp16Prover class directly (prove(header, job, a_codes, b_codes)), not generate_proof_for_cert_version", + ) +} + #[pyfunction] #[pyo3(name = "check_cert_version_eligible")] fn py_check_cert_version_eligible( @@ -502,6 +535,10 @@ fn py_check_cert_version_eligible( extract_v4(plain_proof)?; Ok(()) } + CertificateVersion::PlainFp16 => { + extract_fp16(plain_proof)?; + Ok(()) + } } } @@ -519,6 +556,7 @@ fn generate_proof_for_cert_version( CertificateVersion::ZkMoe => generate_proof_v2(block_header, plain_proof), CertificateVersion::ZkV3 => generate_proof_v3(block_header, plain_proof), CertificateVersion::PlainFp8 => Err(not_implemented_fp8()), + CertificateVersion::PlainFp16 => Err(not_implemented_fp16()), } } @@ -534,6 +572,7 @@ fn verify_proof_for_cert_version( CertificateVersion::ZkMoe => verify_proof_v2(block_header, proof), CertificateVersion::ZkV3 => verify_proof_v3(block_header, proof), CertificateVersion::PlainFp8 => Err(not_implemented_fp8()), + CertificateVersion::PlainFp16 => Err(not_implemented_fp16()), } } @@ -571,6 +610,10 @@ fn verify_plain_proof_for_cert_version( let proof = extract_v4(plain_proof)?; verify_plain_proof_v4(block_header, proof, nbits_override) } + CertificateVersion::PlainFp16 => { + let proof = extract_fp16(plain_proof)?; + verify_fp16_plain_proof(block_header, proof, nbits_override) + } } } @@ -586,6 +629,12 @@ fn extract_v4(plain_proof: &Bound<'_, PyAny>) -> PyResult { }) } +fn extract_fp16(plain_proof: &Bound<'_, PyAny>) -> PyResult { + plain_proof.extract().map_err(|_| { + pyo3::exceptions::PyTypeError::new_err("certificate version 5 requires Fp16PlainProof") + }) +} + // ============================================================================ // Module // ============================================================================ @@ -629,6 +678,11 @@ fn pearl_mining(m: &Bound<'_, pyo3::types::PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -654,8 +708,12 @@ fn pearl_mining(m: &Bound<'_, pyo3::types::PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(verify_proof_v3, m)?)?; m.add_function(wrap_pyfunction!(verify_plain_proof_v3, m)?)?; m.add_function(wrap_pyfunction!(verify_plain_proof_v4, m)?)?; + m.add_function(wrap_pyfunction!(verify_fp16_plain_proof, m)?)?; m.add_class::()?; m.add_class::()?; + // FP16 (A100) ZK prover: produces the Fp16ZkCertificate bytes the node's + // CertificateV5 carries (consensus verification is the node's FFI, not here). + m.add_class::()?; // V1 functions (legacy circuit; dense proofs only) m.add( "V1_PUBLICDATA_SIZE", @@ -674,6 +732,10 @@ fn pearl_mining(m: &Bound<'_, pyo3::types::PyModule>) -> PyResult<()> { "CERT_VERSION_PLAIN_FP8", CertificateVersion::PlainFp8 as u32, )?; + m.add( + "CERT_VERSION_PLAIN_FP16", + CertificateVersion::PlainFp16 as u32, + )?; m.add_function(wrap_pyfunction!(py_check_cert_version_eligible, m)?)?; m.add_function(wrap_pyfunction!(generate_proof_for_cert_version, m)?)?; m.add_function(wrap_pyfunction!(verify_proof_for_cert_version, m)?)?; diff --git a/zk-pow/.gitignore b/zk-pow/.gitignore index 363ab6fd5..0cbeefe66 100644 --- a/zk-pow/.gitignore +++ b/zk-pow/.gitignore @@ -2,6 +2,7 @@ src/v2/circuit/v2_cache.bin src/v1/v1_cache.bin src/api/fp8/fp8_cache.bin +src/api/fp16/fp16_cache.bin # Auto-generated C header (cbindgen) bindings/go/zk_pow_ffi.h diff --git a/zk-pow/bindings/go/Cargo.lock b/zk-pow/bindings/go/Cargo.lock index 699d18c21..3c020d79f 100644 --- a/zk-pow/bindings/go/Cargo.lock +++ b/zk-pow/bindings/go/Cargo.lock @@ -2125,6 +2125,8 @@ dependencies = [ "itertools 0.14.0", "lazy_static", "log", + "plonky2", + "plonky2_field", "primitive-types 0.12.2", "rand 0.8.6", "rand_chacha 0.9.0", diff --git a/zk-pow/bindings/go/Cargo.toml b/zk-pow/bindings/go/Cargo.toml index 75bec05c1..1e3d7fd9b 100644 --- a/zk-pow/bindings/go/Cargo.toml +++ b/zk-pow/bindings/go/Cargo.toml @@ -11,6 +11,10 @@ crate-type = ["staticlib"] [dependencies] blake3 = "1.5" zk-pow = { path = "../..", default-features = false, features = ["embedded_cache"] } +# The FP16 ZK consensus FFI (src/fp16.rs) deserializes and verifies the wrapped +# plonky2 proof directly, so it needs the proof/field/config types. +plonky2 = { path = "../../../plonky2/plonky2" } +plonky2_field = { path = "../../../plonky2/field" } lazy_static = "1.5" anyhow = "1.0" itertools = "0.14" diff --git a/zk-pow/bindings/go/src/fp16.rs b/zk-pow/bindings/go/src/fp16.rs new file mode 100644 index 000000000..f1b4fa067 --- /dev/null +++ b/zk-pow/bindings/go/src/fp16.rs @@ -0,0 +1,342 @@ +//! FP16 (A100) ZK consensus-certificate verification FFI. +//! +//! This is the FP16 analogue of the FP8 v4 wrapped-proof path +//! ([`crate::verify::verify_zk_proof_v4`]): it deserializes an +//! [`Fp16ZkCertificate`] (the public job statement + the constant-size stage-2 +//! recursive proof), authenticates the proof-carried ancestor against the +//! supplied header window, header-binds the proof's public inputs, and verifies +//! the wrapped plonky2 proof. +//! +//! It REPLACES the former plaintext FP16 certificate FFI +//! (`verify_fp16_plain_proof_ffi` / `verify_fp16_cert_ffi`). The plaintext +//! certificate carried the opened operand strips (cert size scaled with the +//! tile, up to several MiB); the ZK certificate is a constant-size recursive +//! proof, so the wire-size pressure the plaintext path put on the V5 certificate +//! and block/headers message caps is gone. +//! +//! # PROVISIONING (read before activating V5 on a network) +//! +//! Unlike FP8 — whose verifier uses a preloaded *universal* trusted setup +//! (`fp8_cache.bin`, one circuit covering every envelope-legal geometry) — the +//! FP16 wrapper is compiled **per degree profile** (the universal FP16 wrapper is +//! the documented residual, `docs/fp16_scheme/stark_feasibility.md §8`). To avoid +//! an attacker-chosen geometry forcing a multi-minute circuit build at verify time, +//! this entry NEVER compiles: it loads the pre-compiled wrapper for the proof's +//! degree profile from the embedded [`FP16_VERIFIER_CACHE`] (the per-profile +//! analogue of FP8's universal per-device cache) and rejects any profile the cache +//! does not contain. Verification is therefore constant-cost and geometry-bounded; +//! the former verify-time-rebuild DoS is closed. +//! +//! The one remaining provisioning step before activation is the cache CONTENTS: +//! the embedded `fp16_cache.bin` must enumerate every consensus-legal degree +//! profile (built offline by `build_cache … src/api/fp16/fp16_cache.bin`; the +//! sample/bootstrap blob covers only the smallest profile and is for building and +//! exercising the load path, not for consensus). A legal geometry whose profile is +//! absent from the embedded cache is rejected — fail-closed, but it would reject +//! honest work, so the full cache must be embedded before V5 is allowed. + +use std::os::raw::c_char; +use std::slice; + +use anyhow::{ensure, Result}; +use lazy_static::lazy_static; +use plonky2::plonk::proof::ProofWithPublicInputs; +use sha2::{Digest, Sha256}; + +use zk_pow::api::fp16::embedded_cache; +use zk_pow::api::fp16::zk_cert::Fp16ZkCertificate; +use zk_pow::api::primitives::IncompleteBlockHeader as Fp16BlockHeader; +use zk_pow::circuit::fp16::driver::Fp16System; +use zk_pow::circuit::fp16::verifier_cache::Fp16VerifierCache; +use zk_pow::circuit::fp16::wrapper::{verify_wrapped_proof_with_headers, D, F}; + +lazy_static! { + /// The embedded FP16 wrapper verifier cache (one compiled stage-2 verifier per + /// reachable degree profile). Loaded once; verification looks up the proof's + /// geometry profile and NEVER compiles a circuit, so an attacker-chosen geometry + /// cannot force a multi-minute setup build. An empty embedded blob (feature off / + /// cache not yet built) loads as an empty cache and every verify then rejects. + static ref FP16_VERIFIER_CACHE: Fp16VerifierCache = + Fp16VerifierCache::from_bytes(embedded_cache::CACHE_DATA) + .expect("the embedded fp16 verifier cache must decode"); +} + +use crate::common::{catch_panic, set_error_msg}; + +/// Canonical full block-header wire length (incomplete 76-byte projection plus +/// the 32-byte proof commitment), matching the FP8 v4 ancestry codec. +const FULL_BLOCK_HEADER_SIZE: usize = 108; + +/// Maximum accepted FP16 ZK certificate byte length. The stage-2 wrapped proof is +/// constant-size (~71 KiB today) and the job statement is small, so 256 KiB is a +/// generous ceiling that still bounds the work an untrusted blob can force before +/// the (geometry-bounded) circuit work. `Fp16ZkCertificate::from_bytes` has no +/// internal limit, so an untrusted blob is capped here (denial-of-service guard). +const MAX_FP16_ZK_CERT_SIZE: usize = 256 * 1024; + +/// Authenticate the supplied full headers against the proof-carried ancestor, +/// returning the proposed header's incomplete projection. +/// +/// `headers` is the concatenation of canonical 108-byte wire headers in +/// proposed, parent, grandparent order (length 108, 216, or 324). Each link is +/// authenticated by SHA256d of the full header (including its proof commitment) +/// equalling the next header's `prev_block`. The proof-carried ancestor +/// ([`Fp16ZkCertificate`]'s `job.ancestor_header`, which keys the B-side +/// commitment + noise seeds) must equal the incomplete projection of one of these +/// headers — i.e. it lies within the depth-`D` (`D <= 2`) state window. This +/// mirrors the FP8 v4 `check_certificate_ancestors` gate. +fn check_fp16_certificate_ancestors(headers: &[u8], ancestor: &Fp16BlockHeader) -> Result { + ensure!( + matches!(headers.len(), 108 | 216 | 324), + "invalid fp16 headers length {}", + headers.len() + ); + let (headers, _) = headers.as_chunks::(); + let (proposed_bytes, ancestors) = headers.split_first().unwrap(); + let proposed = Fp16BlockHeader::from_bytes(&proposed_bytes[..Fp16BlockHeader::SERIALIZED_SIZE])?; + let mut matched = ancestor == &proposed; + let mut prev_hash = &proposed_bytes[4..36]; + for (i, header) in ancestors.iter().enumerate() { + let hash = Sha256::digest(Sha256::digest(header)); + ensure!( + hash[..] == prev_hash[..], + "fp16 ancestor header at depth {} does not connect", + i + 1 + ); + let parsed = Fp16BlockHeader::from_bytes(&header[..Fp16BlockHeader::SERIALIZED_SIZE])?; + matched |= ancestor == &parsed; + prev_hash = &header[4..36]; + } + ensure!( + matched, + "fp16 proof-carried ancestor is not the proposed header, its parent, or its grandparent" + ); + Ok(proposed) +} + +/// Verify an FP16 (A100) ZK consensus certificate: authenticate the proof-carried +/// ancestor against the supplied header window, then header-bind and verify the +/// wrapped recursive proof against the proposed header. +/// +/// `headers` is proposed ‖ parent ‖ grandparent in canonical 108-byte wire form +/// (`headers_len` must be 108, 216, or 324). `cert_bytes` is a serialized +/// [`Fp16ZkCertificate`] (`{ job, proof_bytes }`). The job's ancestor header keys +/// the B-side commitment + noise seeds, which [`check_fp16_certificate_ancestors`] +/// confirms is a member of the state window before verification. +/// +/// `nbits_override`: `0` uses the proposed header's own `nbits` (a full-block +/// check); a non-zero value is a pool-share target. +/// +/// # Returns +/// - 0: certificate verified and accepted +/// - 1: certificate rejected (malformed, oversized, out-of-window ancestor, bad +/// proof, inadmissible tile, or unmet difficulty) +/// - 2: system error (null/empty input or internal panic) +/// +/// # Safety +/// - `headers` must point to `headers_len` readable bytes +/// - `cert_bytes` must point to `cert_len` readable bytes +/// - `error_msg_out` must be null or a valid pointer to a caller-allocated buffer +/// of `ERROR_MSG_MAX_SIZE` bytes +#[no_mangle] +pub unsafe extern "C" fn verify_fp16_zk_cert_ffi( + headers: *const u8, + headers_len: usize, + cert_bytes: *const u8, + cert_len: usize, + nbits_override: u32, + error_msg_out: *mut c_char, +) -> i32 { + if headers.is_null() || cert_bytes.is_null() || cert_len == 0 { + set_error_msg(error_msg_out, "Null/empty input"); + return 2; + } + if !matches!(headers_len, 108 | 216 | 324) { + set_error_msg(error_msg_out, &format!("invalid fp16 headers length {}", headers_len)); + return 1; + } + if cert_len > MAX_FP16_ZK_CERT_SIZE { + set_error_msg(error_msg_out, "FP16 ZK certificate too large"); + return 1; + } + + let headers = slice::from_raw_parts(headers, headers_len); + let bytes = slice::from_raw_parts(cert_bytes, cert_len); + + let result = catch_panic(|| { + let cert = match Fp16ZkCertificate::from_bytes(bytes) { + Ok(c) => c, + Err(e) => return (1, format!("deserialize: {e}")), + }; + let proposed = match check_fp16_certificate_ancestors(headers, &cert.job.ancestor_header) { + Ok(h) => h, + Err(e) => return (1, format!("rejected: {e}")), + }; + let nbits = if nbits_override == 0 { proposed.nbits } else { nbits_override }; + match verify_fp16_zk_cert(&cert, &proposed, nbits) { + Ok(()) => (0, "accepted".to_string()), + Err(e) => (1, format!("rejected: {e}")), + } + }); + + match result { + Ok((code, msg)) => { + set_error_msg(error_msg_out, &msg); + code + } + Err(panic_msg) => { + set_error_msg(error_msg_out, &format!("panic: {panic_msg}")); + 2 + } + } +} + +/// Load the pre-compiled verifier setup for the proof's geometry and run the +/// header-bound wrapped-proof verifier. Verification cost is constant and +/// geometry-INDEPENDENT: `Fp16System::new` is cheap (closed-form snapped degree +/// bits), and the expensive wrapper circuit is LOADED from the embedded cache by +/// its degree profile — never compiled on the verify path. An attacker-chosen +/// geometry therefore cannot force a circuit build: a legal geometry hits a cached +/// profile; a geometry whose profile is absent (out of envelope, or a stale cache) +/// is rejected before any circuit work. This closes the former verify-time-rebuild +/// DoS. The cache is a consensus / trusted-setup artifact, keyed by degree profile +/// (the per-geometry analogue of FP8's universal per-device cache). +fn verify_fp16_zk_cert(cert: &Fp16ZkCertificate, proposed: &Fp16BlockHeader, nbits: u32) -> Result<()> { + let (h, w, k) = cert.tile_geometry(); + let a_hash = cert.job.operands.a.hash_id; + let b_hash = cert.job.operands.b.hash_id; + + // Reject any geometry outside the consensus / wrapper-legal envelope BEFORE + // constructing the system (whose ladder height-snap would otherwise panic on an + // oversize tile). This is a clean fail-closed rejection, not a system error, and + // mirrors the api-level envelope the miner and plaintext oracle enforce. + zk_pow::api::fp16::params::Fp16Params { + device: cert.job.device, + h, + w, + k, + r: cert.job.r as usize, + } + .validate() + .map_err(|e| anyhow::anyhow!("fp16 geometry rejected: {e}"))?; + + // Cheap: AIR definitions + the closed-form, ladder-snapped degree profile that + // keys the cache. No trace generation, no circuit compilation. (The verifier + // folds the job's `p` into it; hence `mut`.) + let mut system = Fp16System::::new(h, w, k, a_hash, b_hash); + let verifier = FP16_VERIFIER_CACHE.get(system.degree_bits()).ok_or_else(|| { + anyhow::anyhow!( + "no cached fp16 verifier setup for degree profile {:?} (geometry h={h} w={w} k={k}); \ + the geometry is out of the compiled envelope or fp16_cache.bin is stale \ + (regenerate with build_cache)", + system.degree_bits() + ) + })?; + let verifier_data = verifier.circuit(); + + // Deserialize the stage-2 proof against the cached wrapper common data. + let proof = ProofWithPublicInputs::from_bytes(cert.proof_bytes.clone(), &verifier_data.common) + .map_err(|e| anyhow::anyhow!("deserialize wrapped proof: {e}"))?; + + // Header-bound verification: pins KEY_A/KEY_B/jackpot-key + noise seeds to the + // header, derives the statement digest from the proven HASH_JACKPOT, pins the + // whole PI vector, verifies the ZK proof, and checks difficulty vs `nbits`. + verify_wrapped_proof_with_headers(&mut system, verifier_data, &proof, proposed, &cert.job, nbits) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A 108-byte canonical wire header: the fixed 76-byte incomplete projection + /// plus a 32-byte proof commitment. + fn full_header(proj76: &[u8; 76], commitment: [u8; 32]) -> Vec { + let mut full = proj76.to_vec(); + full.extend_from_slice(&commitment); + full + } + + fn proj76() -> [u8; 76] { + // Asymmetric, so any header-orientation regression on the FFI seam shows. + let mut p = [0u8; 76]; + for (i, b) in p.iter_mut().enumerate() { + *b = (i as u8).wrapping_mul(7).wrapping_add(3); + } + p + } + + /// Hash-walk unit check (does not need a wrapped proof): a connected depth-1 + /// chain authenticates a parent-as-ancestor, a broken link is rejected, and an + /// ancestor outside the window is rejected. + #[test] + fn fp16_ancestor_hash_walk_connects() { + let mut parent_proj = proj76(); + parent_proj[68] ^= 0x5A; // perturb the parent's timestamp vs proposed + let parent_full = full_header(&parent_proj, [7u8; 32]); + let parent_incomplete = Fp16BlockHeader::from_bytes(&parent_full[..76]).unwrap(); + + // Link the proposed header to the parent: prev_block = SHA256d(parent). + let link = Sha256::digest(Sha256::digest(&parent_full)); + let mut proposed_proj = proj76(); + proposed_proj[4..36].copy_from_slice(&link); + let proposed_full = full_header(&proposed_proj, [0u8; 32]); + let mut chain = proposed_full.clone(); + chain.extend_from_slice(&parent_full); + + assert!(check_fp16_certificate_ancestors(&chain, &parent_incomplete).is_ok()); + + let mut broken = chain.clone(); + broken[4] ^= 0x01; + assert!(check_fp16_certificate_ancestors(&broken, &parent_incomplete).is_err()); + + let stranger = Fp16BlockHeader { version: 0xDEAD_BEEF, ..parent_incomplete }; + assert!(check_fp16_certificate_ancestors(&chain, &stranger).is_err()); + } + + /// An invalid header-chain length is rejected (must be 108/216/324). + #[test] + fn fp16_zk_cert_rejects_bad_headers_len() { + let cert = [0xABu8; 64]; + let headers = vec![0u8; 100]; + let mut err = [0 as c_char; crate::common::ERROR_MSG_MAX_SIZE]; + let code = unsafe { + verify_fp16_zk_cert_ffi(headers.as_ptr(), headers.len(), cert.as_ptr(), cert.len(), 0, err.as_mut_ptr()) + }; + assert_eq!(code, 1, "bad headers length must be rejected"); + } + + /// Garbage certificate bytes deserialize-fail and are rejected with code 1. + #[test] + fn fp16_zk_cert_rejects_garbage() { + let garbage = [0xABu8; 64]; + let headers = full_header(&proj76(), [0u8; 32]); + let mut err = [0 as c_char; crate::common::ERROR_MSG_MAX_SIZE]; + let code = unsafe { + verify_fp16_zk_cert_ffi(headers.as_ptr(), headers.len(), garbage.as_ptr(), garbage.len(), 0, err.as_mut_ptr()) + }; + assert_eq!(code, 1, "garbage cert must be rejected"); + } + + /// Null / empty input is a bad-input system error (code 2). + #[test] + fn fp16_zk_cert_rejects_null_and_empty() { + let cert = [0xABu8; 64]; + let headers = full_header(&proj76(), [0u8; 32]); + let mut err = [0 as c_char; crate::common::ERROR_MSG_MAX_SIZE]; + let code = unsafe { + verify_fp16_zk_cert_ffi(std::ptr::null(), 108, cert.as_ptr(), cert.len(), 0, err.as_mut_ptr()) + }; + assert_eq!(code, 2, "null headers must be bad input"); + let code = unsafe { + verify_fp16_zk_cert_ffi(headers.as_ptr(), headers.len(), cert.as_ptr(), 0, 0, err.as_mut_ptr()) + }; + assert_eq!(code, 2, "empty cert must be bad input"); + } + + // NOTE: an end-to-end accept test needs a real wrapped stage-2 proof, which + // costs a ~12-minute recursive wrap (and the per-geometry circuit build). It + // is therefore not a committed unit test here; regenerate the Go fixture (a + // serialized `Fp16ZkCertificate`) with a dedicated, explicitly-run tool once + // the FP16 verifier cache / universal wrapper (see the module-level blocker) + // lands, mirroring the FP8 `fp8_zk_proof_b200.bin` fixture flow. +} diff --git a/zk-pow/bindings/go/src/lib.rs b/zk-pow/bindings/go/src/lib.rs index 1eb09374a..ab5620f2b 100644 --- a/zk-pow/bindings/go/src/lib.rs +++ b/zk-pow/bindings/go/src/lib.rs @@ -11,6 +11,7 @@ use tikv_jemallocator::Jemalloc; static GLOBAL: Jemalloc = Jemalloc; mod common; +mod fp16; mod mine; mod plain; mod verify; @@ -18,6 +19,7 @@ mod verify; pub use common::{CZKProof, PUBLICDATA_MAX_SIZE, PUBLICDATA_SIZE}; pub use zk_pow::v2::api::proof::{IncompleteBlockHeader, MiningConfiguration}; +pub use fp16::verify_fp16_zk_cert_ffi; pub use mine::mine; pub use verify::verify_zk_proof_v1; pub use verify::verify_zk_proof_v2; diff --git a/zk-pow/examples/fp16_noise_tool.rs b/zk-pow/examples/fp16_noise_tool.rs new file mode 100644 index 000000000..cfcf9697a --- /dev/null +++ b/zk-pow/examples/fp16_noise_tool.rs @@ -0,0 +1,59 @@ +//! Seed-exact FP16 noised-operand tool for offline calibration +//! (`docs/fp16_scheme/validation/calibration.py --rust-noise`). +//! +//! Drives the REAL consensus noise pipeline +//! ([`zk_pow::circuit::fp16::driver::fp16_noised_operands`]: root-derived seeds -> +//! keyed-BLAKE3 noise lines -> `noisy_quantize`), so the calibration harness can +//! compute `f_bp`/`rho` over the exact bytes the verifier would, instead of a +//! shape-faithful reimplementation of the noise. +//! +//! Protocol (stdin, whitespace-separated integers): +//! h w k +//! a_codes[h*k] (FP16 bit patterns, u16) +//! b_codes[w*k] (FP16 bit patterns, u16) +//! The opening keys and hash ids are fixed (the f_bp/rho distribution does not +//! depend on them, only on the derived noise being the real pipeline's). +//! +//! Output (stdout): `h*k` noised A codes then `w*k` noised B codes, space-separated. +//! +//! Run: cargo run --release --example fp16_noise_tool < input.txt + +use std::io::{self, Read, Write}; + +use zk_pow::api::fp8::public_params::HashId; +use zk_pow::circuit::fp16::driver::fp16_noised_operands; + +const KEY_A: [u8; 32] = [0x11; 32]; +const KEY_B: [u8; 32] = [0x22; 32]; +const HASH_ID: HashId = HashId::Blake3Chunk1024; + +fn main() -> anyhow::Result<()> { + let mut input = String::new(); + io::stdin().read_to_string(&mut input)?; + let mut it = input.split_whitespace().map(|t| t.parse::()); + let mut next = || -> anyhow::Result { + it.next().ok_or_else(|| anyhow::anyhow!("unexpected end of input"))?.map_err(Into::into) + }; + + let h = next()? as usize; + let w = next()? as usize; + let k = next()? as usize; + + let mut a_codes = Vec::with_capacity(h * k); + for _ in 0..h * k { + a_codes.push(next()? as u16); + } + let mut b_codes = Vec::with_capacity(w * k); + for _ in 0..w * k { + b_codes.push(next()? as u16); + } + + let (noised_a, noised_b) = + fp16_noised_operands(h, w, k, &a_codes, &b_codes, KEY_A, KEY_B, HASH_ID, HASH_ID)?; + + let out = io::stdout(); + let mut w_out = io::BufWriter::new(out.lock()); + let strs: Vec = noised_a.iter().chain(noised_b.iter()).map(|v| v.to_string()).collect(); + writeln!(w_out, "{}", strs.join(" "))?; + Ok(()) +} diff --git a/zk-pow/src/api/fp16/accumulate.rs b/zk-pow/src/api/fp16/accumulate.rs new file mode 100644 index 000000000..721d9d8bc --- /dev/null +++ b/zk-pow/src/api/fp16/accumulate.rs @@ -0,0 +1,309 @@ +//! Bit-exact model of the NVIDIA A100 (GA100, `sm_80`) `HMMA.16816.F32` +//! accumulation for FP16 operands with FP32 accumulation. +//! +//! This mirrors the reference emulator validated bit-for-bit against A100 +//! silicon (see the FP16 scheme whitepaper, Appendix "Empirical validation"). +//! The model: +//! +//! * The `k` axis is split into groups of `G = 8` consecutive products, +//! processed in order. (Instruction boundaries are invisible: `m16n8k8` and +//! `m16n8k16` chains agree bit-for-bit, so only the group size matters.) +//! * Each product `a_u * b_u` is exact, with stored exponent +//! `e_u = eps(a_u) + eps(b_u)`. +//! * One group step, with incoming FP32 accumulator `c`: +//! - `eta = max(e_u over nonzero products, eps(c))`, where `c = 0` does not +//! participate (a subnormal `c` contributes `-126`); an all-zero group with +//! unchanged `c` is a no-op. +//! - every product and `c` are truncated toward zero onto the grid +//! `2^(eta - W)` with `W = 24`; +//! - the integers are summed exactly; +//! - the sum is rounded toward zero to FP32 (24 significant bits, subnormals +//! on the `2^-149` grid). +//! * A zero result is `+0`; `|result| >= 2^128` is overflow. The verifier +//! rejects non-finite operands and intermediates, so overflow aborts. + +use super::dtype::decompose_fp16; + +/// Internal accumulator precision (FP32 significand bits). +const W: i32 = 24; +/// Products per hardware accumulation group. +pub const GROUP: usize = 8; +/// Sentinel "no exponent" (empty group / zero term). +const NEG: i32 = i32::MIN / 2; +/// FP32 minimum nonzero (subnormal) exponent. +const FP32_MIN_EXP: i32 = -149; + +/// Per-group policy census, recorded during the verifier's replay. See the +/// whitepaper "unpredictable accumulation steps" check. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct PolicyStep { + /// The step did real work (not an empty no-op group). + pub nonempty: bool, + /// Breakpoint: the accumulator alignment or the FP32 rounding discarded a + /// nonzero bit. + pub breakpoint: bool, + /// Number of products in the group whose truncation discarded nonzero bits. + pub products_truncated: u32, +} + +/// Decomposes an FP32 accumulator into `(sign, significand, el, ulp)` with +/// `value = sign * significand * 2^ulp` and `el` the stored exponent used for +/// the alignment max (clamped to `-126` for subnormals). Returns `el = NEG` +/// for a zero accumulator (it does not participate in the alignment). +fn acc_parts(c: f32) -> (i64, u64, i32, i32) { + debug_assert!(c.is_finite()); + if c == 0.0 { + return (1, 0, NEG, 0); + } + let sign: i64 = if c.is_sign_negative() { -1 } else { 1 }; + let bits = c.to_bits(); + let exp_field = ((bits >> 23) & 0xFF) as i32; + let man = (bits & 0x7F_FFFF) as u64; + if exp_field > 0 { + // Normal: 24-bit significand (implicit 1), value = m * 2^(el - 23). + let el = exp_field - 127; + (sign, 0x80_0000 | man, el, el - 23) + } else { + // Subnormal: value = man * 2^-149, stored exponent clamped to -126. + (sign, man, -126, FP32_MIN_EXP) + } +} + +/// `x` shifted by `s` (left if positive, truncating-right if negative). +#[inline] +fn shift_i128(x: i128, s: i32) -> i128 { + if s >= 0 { + x << s + } else if -s >= 127 { + 0 + } else { + x >> (-s) + } +} + +/// Rounds the integer `s * 2^unit` toward zero to an FP32 value (24 significant +/// bits, subnormals floored onto the `2^-149` grid). Mirrors `rz` in the +/// reference emulator. +fn rz_to_f32(s: i128, unit: i32) -> f32 { + if s == 0 { + return 0.0; + } + let sign = s.signum() as f64; + let a = s.unsigned_abs(); + let nb = 127 - a.leading_zeros() as i32; // floor(log2|s|) + let keep = (nb + unit - 23).max(FP32_MIN_EXP); + let drop = (keep - unit).clamp(0, 127); + let truncated = (a >> drop) << drop; + let val = sign * (truncated as f64) * 2f64.powi(unit); + val as f32 +} + +/// Computes the A100 device dot product of FP16 rows `a` and `b` (bit patterns), +/// with FP32 carry-in `c`. When `census` is `Some`, appends one [`PolicyStep`] +/// per group. Panics on NaN/inf operands; aborts (via the final finiteness +/// check by the caller) on overflow. +pub fn a100_dot(a: &[u16], b: &[u16], c: f32, mut census: Option<&mut Vec>) -> f32 { + assert_eq!(a.len(), b.len(), "operand length mismatch"); + let mut cur = c; + let k = a.len(); + let mut g0 = 0; + while g0 < k { + let g1 = (g0 + GROUP).min(k); + let (cs, cm, cel, culp) = acc_parts(cur); + + // Alignment exponent over nonzero products and the accumulator. + let mut eta = cel; + for u in g0..g1 { + let (sa, ma, ea) = decompose_fp16(a[u]); + let (sb, mb, eb) = decompose_fp16(b[u]); + if ma != 0 && mb != 0 { + let _ = (sa, sb); + eta = eta.max(ea + eb); + } + } + if eta == NEG { + // Empty group, accumulator zero: no-op. + if let Some(v) = census.as_deref_mut() { + v.push(PolicyStep::default()); + } + g0 = g1; + continue; + } + let unit = eta - W; + + // Sum products and the accumulator, all truncated onto the 2^unit grid. + let mut sum: i128 = 0; + let mut products_truncated = 0u32; + for u in g0..g1 { + let (sa, ma, ea) = decompose_fp16(a[u]); + let (sb, mb, eb) = decompose_fp16(b[u]); + if ma == 0 || mb == 0 { + continue; + } + let prod = (ma * mb) as i128; // < 2^22, exact + let sh = (ea + eb) - 20 - unit; // product LSB is 2^(ea+eb-20) + let aligned = shift_i128(prod, sh); + if sh < 0 && (prod & ((1i128 << (-sh).min(126)) - 1)) != 0 { + products_truncated += 1; + } + sum += (sa * sb) as i128 * aligned; + } + // Accumulator term. + let csh = culp - unit; + let acc_aligned = shift_i128(cm as i128, csh); + let acc_truncated = csh < 0 && cm != 0 && (cm & ((1u64 << (-csh).min(63)) - 1)) != 0; + sum += cs as i128 * acc_aligned; + + let new = rz_to_f32(sum, unit); + + if let Some(v) = census.as_deref_mut() { + // Breakpoint: accumulator alignment or FP32 rounding dropped a + // nonzero bit. (`rz` dropped bits iff it differs from the exact sum.) + let rz_dropped = (new as f64) != (sum as f64) * 2f64.powi(unit); + v.push(PolicyStep { + nonempty: true, + breakpoint: acc_truncated || rz_dropped, + products_truncated, + }); + } + cur = new; + g0 = g1; + } + cur +} + +/// Device matmul of an `m x k` operand `a` against an `n x k` operand `b` (both +/// row-major FP16 bit patterns; `b` is the transposed logical operand), with +/// optional `m x n` carry-in. Returns the `m x n` FP32 tile. This is the +/// datapath the verifier replays and the ticket hashes. +pub fn a100_matmul( + a: &[u16], + b: &[u16], + acc: Option<&[f32]>, + m: usize, + n: usize, + k: usize, +) -> Vec { + assert_eq!(a.len(), m * k); + assert_eq!(b.len(), n * k); + let mut out = vec![0f32; m * n]; + for i in 0..m { + for j in 0..n { + let c = acc.map_or(0.0, |a| a[i * n + j]); + out[i * n + j] = a100_dot(&a[i * k..i * k + k], &b[j * k..j * k + k], c, None); + } + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::fp16::dtype::fp16_to_f32; + + // Reference vectors generated from the GPU-validated emulator (emu3.py). + // Each line: k, then k a-bits, k b-bits, c-bits (f32), d-bits (f32). + const VECTORS: &str = include_str!("testdata/a100_dot_vectors.txt"); + + // Hardware-captured edge-case corpus: run on real sm_80 silicon (CMP 170HX / + // A100) via `mma.sync.m16n8k16.f32.f16` and cross-checked against this model, + // by `docs/fp16_scheme/validation/generate_and_capture.py`. Extends the corpus + // above (which tops out at k=256) with k up to 1024 and explicit + // subnormal-operand / subnormal-accumulator / subnormal-output / cancellation / + // grid-boundary / max-magnitude edges. Same line format. + const VECTORS_K1024: &str = include_str!("testdata/a100_dot_vectors_k1024.txt"); + + fn check_vectors(data: &str, min_count: usize) -> usize { + let mut n = 0; + for line in data.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let c = f32::from_bits(t[1 + 2 * k].parse().unwrap()); + let d = f32::from_bits(t[2 + 2 * k].parse().unwrap()); + let got = a100_dot(&a, &b, c, None); + assert_eq!( + got.to_bits(), + d.to_bits(), + "vector {n} (k={k}): got {got} ({:#010x}) expected {d} ({:#010x})", + got.to_bits(), + d.to_bits() + ); + n += 1; + } + assert!(n >= min_count, "expected >= {min_count} reference vectors, got {n}"); + n + } + + #[test] + fn matches_reference_emulator() { + check_vectors(VECTORS, 100); + } + + /// The model reproduces the hardware-captured edge corpus bit-for-bit, + /// including k=1024 and the subnormal/cancellation/grid-boundary edges the + /// original k<=256 corpus did not cover. This is the model-vs-silicon + /// cross-check (the device bits were captured on sm_80, not model-ported). + #[test] + fn matches_hardware_capture_k1024() { + let n = check_vectors(VECTORS_K1024, 200); + // The corpus includes k=1024 vectors (the study's dimension, absent above). + let has_k1024 = VECTORS_K1024 + .lines() + .filter(|l| !l.trim().is_empty() && !l.trim_start().starts_with('#')) + .any(|l| l.split_whitespace().next() == Some("1024")); + assert!(has_k1024, "capture corpus must include k=1024 vectors"); + // And at least one subnormal-FP32 output (exp field 0, nonzero mantissa). + let has_subnormal_out = VECTORS_K1024 + .lines() + .filter(|l| !l.trim().is_empty() && !l.trim_start().starts_with('#')) + .any(|l| { + let t: Vec<&str> = l.split_whitespace().collect(); + let d: u32 = t[t.len() - 1].parse().unwrap(); + (d >> 23) & 0xFF == 0 && (d & 0x7F_FFFF) != 0 + }); + assert!(has_subnormal_out, "capture corpus must exercise the subnormal-output branch"); + assert!(n >= 200, "expected the full captured corpus"); + } + + #[test] + fn single_product_exact() { + // 3 * 5 = 15, no accumulation effects. + let a = [f32_to_bits(3.0)]; + let b = [f32_to_bits(5.0)]; + assert_eq!(a100_dot(&a, &b, 0.0, None), 15.0); + } + + #[test] + fn zero_result_is_positive_zero() { + let a = [f32_to_bits(1.0)]; + let b = [f32_to_bits(-1.0)]; + let d = a100_dot(&a, &b, 1.0, None); + assert_eq!(d.to_bits(), 0.0f32.to_bits()); + } + + #[test] + fn breakpoint_census_detects_rz_drop() { + // Accumulator 2^24 plus a unit product: the sum 2^24 + 1 needs 25 bits, + // so the round-toward-zero to FP32 drops the low bit -> a breakpoint. + let a = [f32_to_bits(1.0)]; + let b = [f32_to_bits(1.0)]; + let mut census = Vec::new(); + let d = a100_dot(&a, &b, 16_777_216.0, Some(&mut census)); + assert_eq!(d, 16_777_216.0); // 2^24 + 1 truncates back to 2^24 + assert_eq!(census.len(), 1); + assert!(census[0].breakpoint, "RZ dropped a nonzero bit"); + } + + fn f32_to_bits(x: f32) -> u16 { + let b = super::super::dtype::f32_to_fp16(x).unwrap(); + // sanity: decodes back to a representable neighbor + let _ = fp16_to_f32(b); + b + } +} diff --git a/zk-pow/src/api/fp16/commitment.rs b/zk-pow/src/api/fp16/commitment.rs new file mode 100644 index 000000000..ea4d324b2 --- /dev/null +++ b/zk-pow/src/api/fp16/commitment.rs @@ -0,0 +1,255 @@ +//! Merkle commitment over raw FP16 operand rows, with minimal multi-row openings. +//! +//! The FP16 scheme commits each operand as a keyed-BLAKE3 Merkle tree directly +//! over its FP16 rows (`u16`, little-endian, row-major) — there is no int8 + +//! block-scale prequant layer, so the committed leaves ARE the FP16 values. This +//! is strictly simpler than the FP8 commitment ([`crate::api::fp8::openings`]), +//! which commits a separate values tree and scales tree and runs the compiled +//! Blake program; here one tree per operand suffices. +//! +//! The tree/key/hash-id discipline matches FP8: leaves are fixed-size chunks +//! ([`HashId::chunk_len`]) of the zero-padded row bytes, built under a per-tree +//! key. An opening discloses exactly the selected tile rows as the unique-minimal +//! leaf/sibling set; [`verify_and_open_rows`] rebuilds the root under the key, +//! checks it against the claimed root, and extracts the opened FP16 rows. + +use anyhow::{Context, Result, ensure}; +use pearl_blake3::{MerkleProof, MerkleTree}; + +use super::dtype::fp16_to_f32; +use crate::api::fp8::public_params::HashId; +use crate::api::primitives::Hash256; +use crate::circuit::utils::macros::ensure_eq; + +/// Bytes per committed FP16 row: `k` values, 2 bytes each (little-endian). +pub fn row_bytes(k: usize) -> usize { + k * 2 +} + +/// Little-endian byte image of an FP16 row-major matrix (the committed leaf data, +/// before hash-id padding). +pub fn rows_to_bytes(rows: &[u16]) -> Vec { + rows.iter().flat_map(|v| v.to_le_bytes()).collect() +} + +/// Builds the keyed Merkle tree committing `rows` (`num_rows x k` FP16 values, +/// row-major) under `key`, with leaves of `hash_id` chunk length. +pub fn commit_operand(rows: &[u16], num_rows: usize, k: usize, hash_id: HashId, key: Hash256) -> Result { + ensure!(rows.len() == num_rows * k, "operand is not num_rows x k ({} != {num_rows}*{k})", rows.len()); + let bytes = rows_to_bytes(rows); + MerkleTree::with_chunk_len(&hash_id.pad(&bytes), key, hash_id.chunk_len()) +} + +/// Opens exactly the `row_indices` rows of a committed tree: the unique-minimal +/// leaf/sibling set for those rows. `row_indices` must be valid rows of the +/// `num_rows x k` matrix. +pub fn open_rows(tree: &MerkleTree, row_indices: &[usize], num_rows: usize, k: usize, hash_id: HashId) -> Result { + ensure!(!row_indices.is_empty(), "must open at least one row"); + ensure!( + row_indices.iter().all(|&r| r < num_rows), + "opened row index out of range for {num_rows} rows" + ); + let rb = row_bytes(k); + let leaves = MerkleTree::compute_leaf_indices_from_rows(row_indices, (num_rows, rb), hash_id.chunk_len())?; + Ok(tree.get_multileaf_proof(&leaves)) +} + +/// Authenticates `proof` as the unique-minimal opening of `row_indices` from the +/// `num_rows x k` operand committed under `key` with root `claimed_root`, then +/// extracts and returns the opened FP16 rows (flattened, in `row_indices` order, +/// `row_indices.len() * k` values). +/// +/// Rejects: a leaf set that is not the unique-minimal one for the opened rows, a +/// wrong total-leaf count, a root that does not reconstruct under `key` (wrong +/// key / wrong header / tampered leaf or sibling), a root that disagrees with the +/// claimed root, and any opened FP16 value that is NaN/±inf. +pub fn verify_and_open_rows( + proof: &MerkleProof, + row_indices: &[usize], + num_rows: usize, + k: usize, + hash_id: HashId, + key: Hash256, + claimed_root: &Hash256, +) -> Result> { + ensure!(!row_indices.is_empty(), "must open at least one row"); + ensure!( + row_indices.iter().all(|&r| r < num_rows), + "opened row index out of range for {num_rows} rows" + ); + let chunk_len = hash_id.chunk_len(); + let rb = row_bytes(k); + + // Structural gates before any Merkle work (sanity_check bounds proof fields). + proof.sanity_check().context("FP16 operand: merkle proof structure")?; + if let Some(leaf) = proof.leaf_data.first() { + ensure_eq!(leaf.len(), chunk_len, "FP16 operand: leaf length must match hash_id chunk_len"); + } + let tree_bytes = num_rows + .checked_mul(rb) + .ok_or_else(|| anyhow::anyhow!("FP16 operand: matrix byte length overflow"))?; + ensure_eq!( + proof.total_leaves, + hash_id.padded_len(tree_bytes) / chunk_len, + "FP16 operand: total_leaves mismatch" + ); + + // The opened leaves must be exactly the unique-minimal set for these rows. + let minimal = MerkleTree::compute_leaf_indices_from_rows(row_indices, (num_rows, rb), chunk_len)?; + ensure_eq!( + proof.leaf_indices, + minimal, + "FP16 operand: leaf set is not the unique minimal set for the opened rows" + ); + ensure_eq!( + proof.leaf_data.len(), + minimal.len(), + "FP16 operand: leaf_data count must match the unique leaf set" + ); + + // Reconstruct the root under the key and bind it to the claimed root. + let root = proof + .compute_root(key) + .ok_or_else(|| anyhow::anyhow!("FP16 operand: Merkle reconstruction failed"))?; + ensure_eq!(&root, claimed_root, "FP16 operand: reconstructed root != claimed root"); + ensure_eq!(&proof.root, claimed_root, "FP16 operand: proof root != claimed root"); + + // Extract the opened rows and decode FP16 (rejecting NaN/inf). + let mut out = Vec::with_capacity(row_indices.len() * k); + for &idx in row_indices { + let start = idx.checked_mul(rb).ok_or_else(|| anyhow::anyhow!("row offset overflow"))?; + let bytes = proof.extract_bytes(start, rb).context("extract FP16 row")?; + for pair in bytes.as_chunks::<2>().0 { + let v = u16::from_le_bytes(*pair); + ensure!((v >> 10) & 0x1F != 0x1F, "opened FP16 value {v:#06x} is NaN/inf"); + out.push(v); + } + } + debug_assert_eq!(out.len(), row_indices.len() * k); + // Touch the decoder so a future layout change that breaks decoding is caught. + debug_assert!(out.iter().all(|&v| fp16_to_f32(v).is_finite())); + Ok(out) +} + +#[cfg(test)] +mod tests { + use super::*; + + use super::super::dtype::f32_to_fp16; + + const KEY: Hash256 = [7u8; 32]; + + /// Valid (finite) FP16 row-major matrix with spread magnitudes. + fn matrix(num_rows: usize, k: usize) -> Vec { + (0..num_rows * k) + .map(|i| f32_to_fp16(((i * 37 % 193) as f32 - 96.0) * 0.5).unwrap()) + .collect() + } + + #[test] + fn round_trips_the_opened_rows() { + let (num_rows, k) = (8usize, 256usize); + let rows = matrix(num_rows, k); + for hash_id in HashId::ALL { + let tree = commit_operand(&rows, num_rows, k, hash_id, KEY).unwrap(); + let open_idx = vec![0usize, 3, 7]; + let proof = open_rows(&tree, &open_idx, num_rows, k, hash_id).unwrap(); + let opened = verify_and_open_rows(&proof, &open_idx, num_rows, k, hash_id, KEY, &tree.root()).unwrap(); + assert_eq!(opened.len(), open_idx.len() * k); + for (slot, &row) in open_idx.iter().enumerate() { + assert_eq!(&opened[slot * k..slot * k + k], &rows[row * k..row * k + k], "row {row}"); + } + } + } + + #[test] + fn wrong_key_or_root_rejected() { + let (num_rows, k) = (8usize, 128usize); + let rows = matrix(num_rows, k); + let hash_id = HashId::Blake3Chunk1024; + let tree = commit_operand(&rows, num_rows, k, hash_id, KEY).unwrap(); + let open_idx = vec![1usize, 2]; + let proof = open_rows(&tree, &open_idx, num_rows, k, hash_id).unwrap(); + + // Wrong key -> reconstruction differs from the claimed root. + assert!(verify_and_open_rows(&proof, &open_idx, num_rows, k, hash_id, [9u8; 32], &tree.root()).is_err()); + // Wrong claimed root. + assert!(verify_and_open_rows(&proof, &open_idx, num_rows, k, hash_id, KEY, &[0u8; 32]).is_err()); + // Honest opening still passes. + assert!(verify_and_open_rows(&proof, &open_idx, num_rows, k, hash_id, KEY, &tree.root()).is_ok()); + } + + #[test] + fn tampered_leaf_rejected() { + let (num_rows, k) = (8usize, 128usize); + let rows = matrix(num_rows, k); + let hash_id = HashId::Blake3Chunk1024; + let tree = commit_operand(&rows, num_rows, k, hash_id, KEY).unwrap(); + let open_idx = vec![0usize, 4]; + let mut proof = open_rows(&tree, &open_idx, num_rows, k, hash_id).unwrap(); + proof.leaf_data[0][0] ^= 0xFF; + assert!(verify_and_open_rows(&proof, &open_idx, num_rows, k, hash_id, KEY, &tree.root()).is_err()); + } + + #[test] + fn wrong_leaf_set_rejected() { + let (num_rows, k) = (8usize, 128usize); + let rows = matrix(num_rows, k); + let hash_id = HashId::Blake3Chunk1024; + let tree = commit_operand(&rows, num_rows, k, hash_id, KEY).unwrap(); + // Open rows [0,4] but claim we opened [1,2]: the minimal leaf set won't match. + let proof = open_rows(&tree, &[0usize, 4], num_rows, k, hash_id).unwrap(); + assert!(verify_and_open_rows(&proof, &[1usize, 2], num_rows, k, hash_id, KEY, &tree.root()).is_err()); + } + + /// Additive oracle dump for the sm_80 miner commitment kernel. Prints, for + /// several operand shapes / keys / hash-ids, the committed root (and a few + /// leaf-hash bytes) so the GPU kernel can be asserted bit-exact against it. + /// `cargo test -p zk-pow api::fp16::commitment::dump_commit_oracle -- --ignored --nocapture`. + #[test] + #[ignore] + fn dump_commit_oracle() { + // Deterministic raw u16 rows (arbitrary bit patterns; commit does not + // validate finiteness), reproducible in the Python/GPU oracle. + fn gen_rows(n: usize, seed: u32) -> Vec { + (0..n) + .map(|i| ((i as u32).wrapping_mul(40503).wrapping_add(seed) & 0xFFFF) as u16) + .collect() + } + let cases: &[(usize, usize, u8, u8)] = &[ + // (num_rows, k, chunk_len_id(0..3), key_byte) + (1, 1, 3, 0x11), // tiny single-leaf + (2, 64, 3, 0x22), // 256 bytes, single 1024 leaf + (8, 256, 3, 0x07), // 4096 bytes = 4 leaves of 1024 + (8, 256, 0, 0x5A), // same bytes, 128-byte leaves (32 leaves) + (8, 256, 1, 0xA5), // 256-byte leaves (16 leaves) + (8, 256, 2, 0x33), // 512-byte leaves (8 leaves) + (5, 100, 2, 0x44), // 1000 bytes, 512-byte leaves -> padded 1024 -> 2 leaves + (7, 333, 0, 0x99), // odd shapes, 128-byte leaves + (13, 777, 3, 0xFE),// non-power-of-two leaf count, 1024-byte leaves + (3, 1500, 1, 0x80),// 9000 bytes, 256-byte leaves + ]; + for (idx, &(num_rows, k, cl_id, kb)) in cases.iter().enumerate() { + let hash_id = HashId::try_from(cl_id).unwrap(); + let key = [kb; 32]; + let rows = gen_rows(num_rows * k, (idx as u32).wrapping_mul(2654435761)); + let tree = commit_operand(&rows, num_rows, k, hash_id, key).unwrap(); + let root = tree.root(); + let seed = (idx as u32).wrapping_mul(2654435761); + let root_hex: String = root.iter().map(|b| format!("{b:02x}")).collect(); + println!("ORACLE {num_rows} {k} {} {kb} {seed} {root_hex}", hash_id.chunk_len()); + } + } + + #[test] + fn nan_value_rejected() { + let (num_rows, k) = (2usize, 64usize); + let mut rows = matrix(num_rows, k); + rows[0] = 0x7C01; // FP16 NaN (exp=0x1F, man!=0) + let hash_id = HashId::Blake3Chunk1024; + let tree = commit_operand(&rows, num_rows, k, hash_id, KEY).unwrap(); + let proof = open_rows(&tree, &[0usize], num_rows, k, hash_id).unwrap(); + let err = verify_and_open_rows(&proof, &[0usize], num_rows, k, hash_id, KEY, &tree.root()).unwrap_err(); + assert!(err.to_string().contains("NaN/inf"), "got: {err}"); + } +} diff --git a/zk-pow/src/api/fp16/dtype.rs b/zk-pow/src/api/fp16/dtype.rs new file mode 100644 index 000000000..b98ca76dd --- /dev/null +++ b/zk-pow/src/api/fp16/dtype.rs @@ -0,0 +1,202 @@ +//! IEEE-754 half precision (FP16, E5M10) decode/encode and the integer +//! decomposition the A100 accumulation model consumes. +//! +//! FP16 is bias 15, 5 exponent bits, 10 mantissa bits. Every finite FP16 value +//! is exactly representable in f32, so decoding to f32 and multiplying on the +//! f32 datapath reproduces the hardware product bit-for-bit (the A100 tensor +//! core promotes FP16 operands to an f32 product; see [`super::accumulate`]). +//! NaN and infinity are banned, matching the rest of the proof arithmetic. + +/// Decodes an FP16 (E5M10) bit pattern to f32. Exact. Panics on NaN/±inf. +pub fn fp16_to_f32(bits: u16) -> f32 { + let exp = (bits >> 10) & 0x1F; + let man = bits & 0x03FF; + assert!(exp != 0x1F, "FP16 NaN/inf encoding {bits:#06x} is not allowed"); + let sign = ((bits & 0x8000) as u32) << 16; + let magnitude = match (exp, man) { + (0, 0) => 0, + (0, _) => { + // Subnormal: value = man * 2^-24. Renormalize into a normal f32. + let man = man as u32; + let hb = 31 - man.leading_zeros(); // index of the top set bit, 0..=9 + let exp_biased = hb + 103; // f32 bias of 2^(hb-24) + let man_f32 = (man ^ (1 << hb)) << (23 - hb); + (exp_biased << 23) | man_f32 + } + _ => ((exp as u32 + 112) << 23) | ((man as u32) << 13), + }; + f32::from_bits(sign | magnitude) +} + +/// Encodes a finite f32 as FP16 (E5M10), round-to-nearest-ties-to-even, +/// saturating to the largest finite magnitude (65504) on overflow. On values +/// FP16 can represent exactly this is the inverse of [`fp16_to_f32`]. Returns +/// `None` on NaN or infinity. +pub fn f32_to_fp16(x: f32) -> Option { + if !x.is_finite() { + return None; + } + let sign: u16 = if x.is_sign_negative() { 0x8000 } else { 0 }; + let m = x.abs(); + if m == 0.0 { + return Some(sign); + } + let bits = m.to_bits(); + let e = (bits >> 23) as i32 - 127; // unbiased exponent of |x| + let man23 = bits & 0x7F_FFFF; + // Round the 24-bit significand (implicit 1 + 23 bits) to 10 fractional bits. + let magnitude: u16 = if e < -14 { + // Subnormal FP16 (or underflow to zero): value = q * 2^-24. + let full = 0x80_0000 | man23; // 24-bit significand at scale 2^(e-23) + let rshift = (-14 - e) as u32 + 13; // align to the 2^-24 grid + if rshift >= 32 { + 0 + } else { + round_shift(full as u64, rshift) as u16 + } + } else if e > 15 { + 0x7BFF // saturate to 65504 + } else { + let full = 0x80_0000 | man23; + let q = round_shift(full as u64, 13) as u32; // keep 11 significand bits + // round_shift may carry into bit 11 (q == 0x800), bumping the exponent. + let e_adj = e + (q >> 11) as i32; + if e_adj > 15 { + 0x7BFF + } else { + (((e_adj + 15) as u16) << 10) | ((q as u16) & 0x03FF) + } + }; + Some(sign | magnitude) +} + +/// `x >> shift`, rounded to nearest with ties to even. +fn round_shift(x: u64, shift: u32) -> u64 { + if shift == 0 { + return x; + } + let dropped = x & ((1u64 << shift) - 1); + let kept = x >> shift; + let half = 1u64 << (shift - 1); + if dropped > half || (dropped == half && (kept & 1) == 1) { + kept + 1 + } else { + kept + } +} + +/// Integer decomposition of an FP16 operand: `value = sign * m * 2^(eps - 10)`, +/// where `eps` is the stored (unbiased) exponent clamped to the format minimum +/// `-14` for subnormals, and `m` is the integer significand (11 bits for +/// normals, `1..=1023` for subnormals, `0` for zero). `sign` is `+1`/`-1`, or +/// `+1` for zero. This matches the `decompose` of the validated reference +/// emulator. Panics on NaN/±inf. +pub fn decompose_fp16(bits: u16) -> (i64, i64, i32) { + let exp = (bits >> 10) & 0x1F; + let man = (bits & 0x03FF) as i64; + assert!(exp != 0x1F, "FP16 NaN/inf encoding {bits:#06x} is not allowed"); + let sign: i64 = if bits & 0x8000 != 0 { -1 } else { 1 }; + match (exp, man) { + (0, 0) => (1, 0, 0), + (0, _) => (sign, man, -14), // subnormal: m = man, eps = -14 + _ => (sign, 0x400 | man, exp as i32 - 15), // normal: m = 1024+man + } +} + +/// The FP16DECODE committed-LUT fields of an operand code, in the order the A100 matmul AIR +/// binds them: `(sig, sign_bit, eps_biased, is_zero)` with +/// +/// * `sig` the integer significand (`0`, `1..=1023` subnormal, `1024..=2047` normal) — equal +/// to the `m` of [`decompose_fp16`]; +/// * `sign_bit` the raw sign bit (bit 15), used only on nonzero lanes (zero products drop it); +/// * `eps_biased = stored_exponent + 15 >= 0`, so a nonzero product's biased stored exponent +/// is `eps_biased(a) + eps_biased(b) + 97 = (ea + eb) + 127`; +/// * `is_zero = [sig == 0]`. +/// +/// Matches [`decompose_fp16`] on every finite code. NaN/inf codes (exponent field `0x1F`) +/// decode through the normal formula (`sig = 0x400 | man`, `eps = 16`); they never occur in +/// the scheme (operand finiteness is enforced upstream, as FP8 QCAST saturation does), and the +/// table is total so the lookup argument stays well defined. +pub fn fp16_decode_fields(code: u16) -> (u64, u64, u64, u64) { + let exp = (code >> 10) & 0x1F; + let man = u64::from(code & 0x03FF); + let sign_bit = u64::from(code >> 15); + let (sig, eps): (u64, i64) = match (exp, man) { + (0, 0) => (0, 0), + (0, _) => (man, -14), + _ => (0x400 | man, exp as i64 - 15), + }; + (sig, sign_bit, (eps + 15) as u64, u64::from(sig == 0)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fp16_decode_fields_match_decompose() { + for bits in 0u16..=0xFFFF { + if (bits >> 10) & 0x1F == 0x1F { + continue; // NaN/inf: decompose panics; the table uses the normal formula + } + let (sig, sign_bit, eps_biased, is_zero) = fp16_decode_fields(bits); + let (s, m, eps) = decompose_fp16(bits); + assert_eq!(sig, m as u64, "sig {bits:#06x}"); + assert_eq!(eps_biased, (eps + 15) as u64, "eps {bits:#06x}"); + assert_eq!(is_zero, u64::from(m == 0), "is_zero {bits:#06x}"); + // sign_bit is the raw bit; decompose forces +1 for zero, so only compare nonzero. + if m != 0 { + assert_eq!(sign_bit, u64::from(s < 0), "sign {bits:#06x}"); + } + } + // The biased stored exponent of a nonzero product reconstructs ea+eb+127 from the two + // operands' eps_biased fields: eps_biased(a) + eps_biased(b) + 97. + for (ca, cb) in [(0x3C00u16, 0x4000u16), (0x0001, 0x7BFF), (0xC000, 0x3800)] { + let (_, _, ea_b, _) = fp16_decode_fields(ca); + let (_, _, eb_b, _) = fp16_decode_fields(cb); + let (_, _, ea) = decompose_fp16(ca); + let (_, _, eb) = decompose_fp16(cb); + assert_eq!(ea_b + eb_b + 97, (ea + eb + 127) as u64, "biased exp link {ca:#06x},{cb:#06x}"); + } + } + + #[test] + fn fp16_roundtrip_exhaustive() { + // Every finite FP16 value decodes to f32 and re-encodes to itself. + for bits in 0u16..=0xFFFF { + let exp = (bits >> 10) & 0x1F; + if exp == 0x1F { + continue; // NaN/inf + } + let f = fp16_to_f32(bits); + // Normalize -0 and +0: both encode from their own bit pattern. + let re = f32_to_fp16(f).unwrap(); + assert_eq!(re, bits, "roundtrip {bits:#06x} -> {f} -> {re:#06x}"); + } + } + + #[test] + fn decompose_reconstructs_value() { + for bits in 0u16..=0xFFFF { + let exp = (bits >> 10) & 0x1F; + if exp == 0x1F { + continue; + } + let (s, m, eps) = decompose_fp16(bits); + let v = (s as f64) * (m as f64) * 2f64.powi(eps - 10); + assert_eq!(v as f32, fp16_to_f32(bits), "decompose {bits:#06x}"); + } + } + + #[test] + fn known_values() { + assert_eq!(fp16_to_f32(0x3C00), 1.0); // 1.0 + assert_eq!(fp16_to_f32(0x4000), 2.0); // 2.0 + assert_eq!(fp16_to_f32(0xC000), -2.0); + assert_eq!(fp16_to_f32(0x7BFF), 65504.0); // max finite + assert_eq!(fp16_to_f32(0x0001), 2f32.powi(-24)); // min subnormal + assert_eq!(f32_to_fp16(1.0), Some(0x3C00)); + assert_eq!(f32_to_fp16(65505.0), Some(0x7BFF)); // saturate + assert_eq!(f32_to_fp16(f32::INFINITY), None); + } +} diff --git a/zk-pow/src/api/fp16/embedded_cache.rs b/zk-pow/src/api/fp16/embedded_cache.rs new file mode 100644 index 000000000..0e3c5944a --- /dev/null +++ b/zk-pow/src/api/fp16/embedded_cache.rs @@ -0,0 +1,15 @@ +//! Embedded FP16 ZK wrapper verifier cache +//! ([`crate::circuit::fp16::verifier_cache::Fp16VerifierCache`] wire bytes). +//! +//! Generated offline by: `cargo run --release --no-default-features --bin build_cache` +//! (the `fp16_cache.bin` trailing path). The blob is a gitignored build artifact; when +//! the `embedded_cache` feature is off (e.g. while `build_cache` is *producing* it) the +//! cache is empty, and a loader treats an empty blob as an empty cache. + +/// The embedded cache binary data (only when the `embedded_cache` feature is enabled). +#[cfg(feature = "embedded_cache")] +pub const CACHE_DATA: &[u8] = include_bytes!("fp16_cache.bin"); + +/// Empty cache when the `embedded_cache` feature is disabled. +#[cfg(not(feature = "embedded_cache"))] +pub const CACHE_DATA: &[u8] = &[]; diff --git a/zk-pow/src/api/fp16/mod.rs b/zk-pow/src/api/fp16/mod.rs new file mode 100644 index 000000000..44fef4958 --- /dev/null +++ b/zk-pow/src/api/fp16/mod.rs @@ -0,0 +1,27 @@ +//! FP16 accumulation-hardness proof-of-useful-work scheme (A100 / `sm_80`). +//! +//! An alternative Pearl PoUW instantiation whose unit of work is FP16 matrix +//! multiplication on NVIDIA A100 tensor cores. Hardness comes from the +//! nonlinearity of the device's per-product accumulation truncation rather than +//! from coarse quantization, so recovered products carry FP16-level accuracy. +//! See `docs/fp16_scheme/` for the specification. +//! +//! This module provides the full plaintext path: the FP16 `Dtype` ([`dtype`]), +//! the bit-exact A100 accumulation model ([`accumulate`]), the noisy +//! quantization ([`quantization`]), the unpredictable-accumulation-steps jackpot +//! policy ([`policy`]), the tile parameters ([`params`]), and the plaintext tile +//! verifier ([`verify`]). The commitment wire codec/FFI and the ZK circuit are +//! built on top of these (see the implementation staging notes). + +pub mod accumulate; +pub mod commitment; +pub mod dtype; +pub mod embedded_cache; +pub mod noise; +pub mod params; +pub mod plain_proof; +pub mod policy; +pub mod quantization; +pub mod verify; +pub mod zk; +pub mod zk_cert; diff --git a/zk-pow/src/api/fp16/noise.rs b/zk-pow/src/api/fp16/noise.rs new file mode 100644 index 000000000..800820efc --- /dev/null +++ b/zk-pow/src/api/fp16/noise.rs @@ -0,0 +1,419 @@ +//! Deterministic low-rank FP16 noise factors for one A100 tile. +//! +//! The direct analogue of the FP8 noise module ([`crate::api::fp8::noise`]): the +//! per-matmul noise `N = E @ F^T` is a stack of keyed-BLAKE3 "lines", one rule +//! ([`sample_line`]) for every factor. A line is `r` XOF bytes -> sign x UNIFORM +//! magnitude in `[1, 128]` (never zero, no modulo bias), L2-NORMALIZED to the +//! shared constant norm [`NOISE_TARGET_NORM`] with the exact integer-`isqrt` + +//! one-BF16-division recipe (byte-identical on any host), then rounded. The ONLY +//! difference from the FP8 draw is the final element type: FP16 (`u16`) rather +//! than FP8 E4M3 (`u8`), because the A100 datapath consumes FP16 lines and +//! [`super::quantization::noisy_quantize`] expects `E`/`F` as `u16`. +//! +//! A constant line norm makes an `E@F` entry (``) have a known peak +//! (`~c^2`) and rms (`~c^2/sqrt(r)`), so the quant scheme derives its per-row +//! scales from `X`'s norms alone, never measuring `E@F` — see the FP8 rationale. +//! +//! # Seed chain (B then A), FP16 domain +//! +//! The FP16 scheme is a parallel scheme to FP8, so it gets its own transcript +//! domain (`pearl/v4/FP16/...`): a shared label would let the two schemes collide +//! on a reused seed. The chain mirrors the FP8 dense derivation: +//! +//! ```text +//! keyA := H_"key-A"(proposed_header) (A-side tree key) +//! keyB := H_"key-B"(ancestor_header) (B-side tree key) +//! noise seedB := H_"seed-B"(root_B || keyB || pB) +//! noise seedA := H_"seed-A"(root_A || noise_seedB || keyA || pA) +//! ``` +//! +//! `root_X` is the operand's Merkle commitment root; `pX` is the per-side public +//! parameter encoding ([`crate::api::fp16::plain_proof`]). `E_A` keys off +//! `seedA`; both `F` bases and `E_B` key off `seedB` (with distinct `Side` +//! addresses), exactly as FP8. +//! +//! ## Window-authenticated ancestor keying +//! +//! Mirroring the full FP8 scheme ([`crate::api::fp8::transcript`]), the A-side +//! tree is keyed by `H_"key-A"(proposed_header)` (`σ̂`) and the B-side tree by +//! `H_"key-B"(ancestor_header)` (`σ_Δ`), a header drawn from the depth-`D` state +//! window preceding the proposed header. The ancestor is authenticated as a +//! member of that window by the consensus verifier's `check_fp16_certificate_ancestors` +//! (a SHA256d hash-walk from the proposed header through the supplied full +//! ancestor headers; see `zk-pow/bindings/go/src/fp16.rs`) before verification. +//! Because B's commitment root only rebuilds under `keyB`, an +//! ancestor that is not the one the operand was committed against — whether +//! out-of-window or merely unauthenticated — fails the B-side Merkle rebuild. +//! The ancestor is also folded into `pB` and hence the seed chain. + +use pearl_blake3::blake3_digest; + +use super::dtype::f32_to_fp16; +use crate::api::fp8::compute::{bf16_div, bf16_mul}; +use crate::api::fp8::dtype::{bf16_to_f32, f32_to_bf16}; +use crate::api::fp8::quantization::NOISE_TARGET_NORM; +use crate::api::primitives::{Hash256, IncompleteBlockHeader, Sides}; + +/// Fixed-point factor carrying `log2(32) = 5` fractional norm bits through the +/// exact integer `isqrt`. It cancels in the scale division; it only preserves +/// precision in the floored square root. Identical to the FP8 constant. +const INT_SQRT_PREC: u64 = 32; + +/// FP16 transcript labels. A distinct domain from the FP8 `pearl/v4/FP8/` +/// labels so the two schemes never derive the same seed from the same inputs. +/// `key-A`/`key-B` mirror the FP8 per-side opening keys: the A-side tree keys on +/// the proposed header, the B-side tree on the window-authenticated ancestor. +const LABEL_KEY_A: &[u8] = b"pearl/v4/FP16/key-A"; +const LABEL_KEY_B: &[u8] = b"pearl/v4/FP16/key-B"; +const LABEL_SEED_A: &[u8] = b"pearl/v4/FP16/seed-A"; +const LABEL_SEED_B: &[u8] = b"pearl/v4/FP16/seed-B"; +const LABEL_NOISE_LINE: &[u8] = b"pearl/v4/FP16/noise-line"; + +/// Derive a 32-byte role key from an FP16 label and an optional parent. +pub(crate) fn subkey(label: &[u8], parent: Option<&Hash256>) -> Hash256 { + blake3_digest(label, parent.copied()) +} + +/// Hash `message` under [`subkey`] of `label` (unkeyed parent). +fn hash_labelled(message: &[u8], label: &[u8]) -> Hash256 { + blake3_digest(message, Some(subkey(label, None))) +} + +/// `keyA = H_"key-A"(proposed_header)` — the A-side tree/opening key. +pub(crate) fn key_a(proposed_header: &IncompleteBlockHeader) -> Hash256 { + hash_labelled(&proposed_header.to_bytes(), LABEL_KEY_A) +} + +/// `keyB = H_"key-B"(ancestor_header)` — the B-side tree/opening key, keyed on +/// the proof-carried, window-authenticated ancestor header. +pub(crate) fn key_b(ancestor_header: &IncompleteBlockHeader) -> Hash256 { + hash_labelled(&ancestor_header.to_bytes(), LABEL_KEY_B) +} + +/// `Sides { a: keyA, b: keyB }` — the per-side opening keys, mirroring +/// [`crate::api::fp8::transcript`]. `proposed_header` (`σ̂`) keys the A side; +/// `ancestor_header` (`σ_Δ`) keys the B side. +pub(crate) fn commitment_keys( + proposed_header: &IncompleteBlockHeader, + ancestor_header: &IncompleteBlockHeader, +) -> Sides { + Sides { + a: key_a(proposed_header), + b: key_b(ancestor_header), + } +} + +/// The per-side noise seeds, derived B-then-A from the committed roots, the +/// per-side opening keys and the per-side public-parameter encodings. `seedB` +/// keys off `keyB` (the ancestor), `seedA` off `keyA` (the proposed header). See +/// the module docs. +pub fn noise_seeds(keys: &Sides, roots: &Sides, p: &Sides>) -> Sides { + let message_b = [roots.b.as_slice(), keys.b.as_slice(), p.b.as_slice()].concat(); + let seed_b = hash_labelled(&message_b, LABEL_SEED_B); + let message_a = [roots.a.as_slice(), seed_b.as_slice(), keys.a.as_slice(), p.a.as_slice()].concat(); + let seed_a = hash_labelled(&message_a, LABEL_SEED_A); + Sides { a: seed_a, b: seed_b } +} + +/// Which operand a noise line belongs to. The discriminants are committed bytes. +#[repr(u8)] +pub(crate) enum Side { + A = 0, + B = 1, +} + +/// Which factor a line contributes to: the row/col-keyed `E` or the shared `F`. +#[repr(u8)] +pub(crate) enum NoiseFactor { + E = 0, + F = 1, +} + +/// One operand's paired noise factors, FP16 bit patterns, whose product +/// `N = E @ F^T` is the injected noise. +pub struct NoiseFactors16 { + /// `(num_rows x r)` FP16 values, row-major (the row/col-keyed E-lines). + pub e: Vec, + /// `(k x r)` FP16 values, row-major (the shared F basis). + pub f: Vec, +} + +/// Both operands' deterministic FP16 noise factors. +pub type Noise16 = Sides; + +/// Draws one keyed, L2-normalized line of `rank` FP16 entries. +/// +/// Derives the line key as [`subkey`] of [`LABEL_NOISE_LINE`] under `seed`, then +/// keyed-BLAKE3-XOF's the address `side | factor | line(u32 LE)` — zero-padded to +/// a constant 64 bytes (one BLAKE3 block) — to `rank` output bytes and normalizes +/// them (see [`normalize_line`]). +pub(crate) fn sample_line(seed: &Hash256, side: Side, factor: NoiseFactor, line: u32, rank: u16) -> Vec { + normalize_line(&sample_line_xof_bytes(seed, side, factor, line, rank)) +} + +/// The raw keyed-BLAKE3-XOF bytes a line is drawn from, *before* [`normalize_line`]. These are the +/// free-witness bytes the circuit's NoiseStark normalizes (its seed-keyed-XOF binding is a later +/// increment); exposing them lets the batch driver feed NoiseStark the REAL per-line bytes so its +/// normalized output is bit-exact with [`sample_line`]/[`sample_noise`]. +pub(crate) fn sample_line_xof_bytes(seed: &Hash256, side: Side, factor: NoiseFactor, line: u32, rank: u16) -> Vec { + let key = subkey(LABEL_NOISE_LINE, Some(seed)); + let mut material = Vec::with_capacity(64); + material.push(side as u8); + material.push(factor as u8); + material.extend_from_slice(&line.to_le_bytes()); + assert!(material.len() <= 64, "noise line material must fit one BLAKE3 block"); + material.resize(64, 0); + + let mut bytes = vec![0u8; usize::from(rank)]; + let mut hasher = blake3::Hasher::new_keyed(&key); + hasher.update(&material); + hasher.finalize_xof().fill(&mut bytes); + bytes +} + +/// The `noise-line` subkey label ([`LABEL_NOISE_LINE`]) — the 24-byte message whose keyed-BLAKE3 +/// digest under a `seed` is that seed's `line_key` ([`subkey`]). Exposed so the FP16 ZK noise +/// binding ([`crate::circuit::fp16::noise_blake3`]) can pin the subkey compression's message to this +/// exact public constant. +pub(crate) fn noise_line_label() -> &'static [u8] { + LABEL_NOISE_LINE +} + +/// The 64-byte keyed-BLAKE3 material block of one noise line — `side | factor | line(u32 LE)` then +/// zero-padded to one BLAKE3 block, byte-identical to the block [`sample_line_xof_bytes`] hashes +/// under the seed's `line_key`. Exposed so the ZK noise binding can pin each line compression's +/// message to this exact public constant (the material is a pure function of the public line +/// address, never free witness). +pub(crate) fn noise_line_material(side: Side, factor: NoiseFactor, line: u32) -> [u8; 64] { + let mut material = [0u8; 64]; + material[0] = side as u8; + material[1] = factor as u8; + material[2..6].copy_from_slice(&line.to_le_bytes()); + material +} + +/// Decodes `bytes` into a signed integer line and renormalizes it to L2 norm +/// [`NOISE_TARGET_NORM`], cast to FP16. +/// +/// `norm_scaled = floor(||x||_2 * INT_SQRT_PREC)` (exact integer `isqrt`), then +/// `scale = bf16(NOISE_TARGET_NORM * INT_SQRT_PREC) / bf16(norm_scaled)` (one +/// BF16 rounding), then `entry_i = fp16(bf16(x_i) * scale)`. Identical to the FP8 +/// recipe except the final cast target. +fn normalize_line(bytes: &[u8]) -> Vec { + // Each `x_i` in ±[1, 128]: bit 7 the sign, `(b & 0x7F) + 1` the magnitude. + let x: Vec = bytes + .iter() + .map(|&b| { + let sign = 1 - 2 * ((b >> 7) as i64); // +1 (bit 7 = 0) or -1 + let magnitude = ((b & 0x7F) as i64) + 1; // uniform in [1, 128], never 0 + sign * magnitude + }) + .collect(); + + let sumsq: u64 = x.iter().map(|&xi| (xi * xi) as u64).sum(); + let norm_scaled = (sumsq * (INT_SQRT_PREC * INT_SQRT_PREC)).isqrt(); + + let numer = f32_to_bf16((NOISE_TARGET_NORM * INT_SQRT_PREC as f64) as f32).expect("8192 is representable"); + let denom = f32_to_bf16(norm_scaled as f32).expect("norm_scaled < 2^24 is representable"); + let scale = bf16_div(numer, denom).expect("noise-line scale is finite"); + + x.iter() + .map(|&xi| { + let xb = f32_to_bf16(xi as f32).expect("|x_i| <= 128 is representable in bf16"); + let entry = bf16_mul(xb, scale).expect("noise entry is finite"); + f32_to_fp16(bf16_to_f32(entry)).expect("noise entry is representable in FP16") + }) + .collect() +} + +/// Draws the four FP16 noise factors for one tile. +/// +/// `a_rows`/`b_cols` are the selected global row/column indices (the `E` lines key +/// off them); both `F` bases are `0..k` lines. `rank` is the peel rank `r`. `E_A` +/// keys off `seeds.a`; `E_B`, `F_A`, `F_B` all key off `seeds.b` with distinct +/// `Side` addresses. +pub(crate) fn sample_noise(k: usize, rank: u16, seeds: Sides, a_rows: &[u32], b_cols: &[u32]) -> Noise16 { + let line = |seed: &Hash256, side: Side, factor: NoiseFactor, idx: u32| sample_line(seed, side, factor, idx, rank); + + let e_a: Vec = a_rows.iter().flat_map(|&row| line(&seeds.a, Side::A, NoiseFactor::E, row)).collect(); + let e_b: Vec = b_cols.iter().flat_map(|&col| line(&seeds.b, Side::B, NoiseFactor::E, col)).collect(); + let f_a: Vec = (0..k as u32).flat_map(|i| line(&seeds.b, Side::A, NoiseFactor::F, i)).collect(); + let f_b: Vec = (0..k as u32).flat_map(|i| line(&seeds.b, Side::B, NoiseFactor::F, i)).collect(); + + Noise16 { + a: NoiseFactors16 { e: e_a, f: f_a }, + b: NoiseFactors16 { e: e_b, f: f_b }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::fp16::dtype::fp16_to_f32; + + fn seeds() -> Sides { + Sides { a: [0x22u8; 32], b: [0x11u8; 32] } + } + + /// Additive, test-only oracle dump for the sm_80 miner `fp16_noise_lines` + /// kernel. Writes XOF bytes, per-seed line keys, and full `sample_noise` + /// E/F `u16` outputs for several seeds/shapes so the GA100 kernel can be + /// asserted bit-exact. Ignored by default; run with + /// `PEARL_FP16_NOISE_VEC= cargo test -p zk-pow api::fp16::noise::dump_noise_vectors -- --ignored --nocapture`. + #[test] + #[ignore] + fn dump_noise_vectors() { + use std::fmt::Write as _; + + let path = std::env::var("PEARL_FP16_NOISE_VEC") + .unwrap_or_else(|_| "/tmp/fp16_noise_vectors.txt".to_string()); + + fn hx(b: &[u8]) -> String { + b.iter().map(|x| format!("{x:02x}")).collect() + } + fn us(v: &[u16]) -> String { + v.iter().map(|x| x.to_string()).collect::>().join(" ") + } + + // (seed_a, seed_b, k, r, a_rows, b_cols) + let cases: Vec<([u8; 32], [u8; 32], usize, u16, Vec, Vec)> = vec![ + ([0x22u8; 32], [0x11u8; 32], 128, 32, vec![0, 8, 64], vec![1, 2]), + ([0x01u8; 32], [0xfeu8; 32], 64, 32, vec![0, 1, 2, 255], vec![7, 300, 1000]), + ([0xa5u8; 32], [0x5au8; 32], 256, 32, vec![0], vec![0]), + // Non-protocol ranks to exercise XOF beyond 32/64 bytes. + ([0x33u8; 32], [0x44u8; 32], 40, 16, vec![3, 9], vec![4]), + ([0x7fu8; 32], [0x80u8; 32], 48, 48, vec![0, 17], vec![1, 2, 65535]), + ([0x00u8; 32], [0xffu8; 32], 24, 72, vec![5], vec![6]), + ]; + + let mut out = String::new(); + for (ci, (seed_a, seed_b, k, r, a_rows, b_cols)) in cases.iter().enumerate() { + let key_a = subkey(LABEL_NOISE_LINE, Some(seed_a)); + let key_b = subkey(LABEL_NOISE_LINE, Some(seed_b)); + writeln!(out, "CASE {ci}").unwrap(); + writeln!(out, "seed_a {}", hx(seed_a)).unwrap(); + writeln!(out, "seed_b {}", hx(seed_b)).unwrap(); + writeln!(out, "line_key_a {}", hx(&key_a)).unwrap(); + writeln!(out, "line_key_b {}", hx(&key_b)).unwrap(); + writeln!(out, "k {k}").unwrap(); + writeln!(out, "r {r}").unwrap(); + writeln!(out, "a_rows {}", a_rows.iter().map(|x| x.to_string()).collect::>().join(",")).unwrap(); + writeln!(out, "b_cols {}", b_cols.iter().map(|x| x.to_string()).collect::>().join(",")).unwrap(); + + // Isolate the hash: raw XOF bytes for a few representative addresses. + let addrs: Vec<(u8, char, u8, char, u32)> = vec![ + (0, 'a', 0, 'E', a_rows[0]), // Side::A, NoiseFactor::E + (1, 'b', 0, 'E', b_cols[0]), // Side::B, NoiseFactor::E + (0, 'b', 1, 'F', 0u32), // Side::A, NoiseFactor::F + (1, 'b', 1, 'F', (k - 1) as u32), // Side::B, NoiseFactor::F + ]; + for (side_b, sc, _factor_b, fc, line) in addrs { + let seed = if sc == 'a' { seed_a } else { seed_b }; + let side = if side_b == 0 { Side::A } else { Side::B }; + let factor = if fc == 'E' { NoiseFactor::E } else { NoiseFactor::F }; + let xof = sample_line_xof_bytes(&seed, side, factor, line, *r); + writeln!(out, "XOF {} {} {} {}", fc, side_b, line, hx(&xof)).unwrap(); + } + + let noise = sample_noise(*k, *r, Sides { a: *seed_a, b: *seed_b }, a_rows, b_cols); + writeln!(out, "e_a {}", us(&noise.a.e)).unwrap(); + writeln!(out, "f_a {}", us(&noise.a.f)).unwrap(); + writeln!(out, "e_b {}", us(&noise.b.e)).unwrap(); + writeln!(out, "f_b {}", us(&noise.b.f)).unwrap(); + writeln!(out, "END").unwrap(); + } + std::fs::write(&path, out).unwrap(); + eprintln!("wrote fp16 noise vectors to {path}"); + } + + #[test] + fn discriminants_are_wire_stable() { + assert_eq!(Side::A as u8, 0); + assert_eq!(Side::B as u8, 1); + assert_eq!(NoiseFactor::E as u8, 0); + assert_eq!(NoiseFactor::F as u8, 1); + } + + #[test] + fn noise_shapes_and_determinism() { + let (k, r) = (128usize, 32u16); + let noise = sample_noise(k, r, seeds(), &[0, 8, 64], &[1, 2]); + assert_eq!(noise.a.e.len(), 3 * r as usize); + assert_eq!(noise.b.e.len(), 2 * r as usize); + assert_eq!(noise.a.f.len(), k * r as usize); + assert_eq!(noise.b.f.len(), k * r as usize); + + let again = sample_noise(k, r, seeds(), &[0, 8, 64], &[1, 2]); + assert_eq!(noise.a.e, again.a.e); + assert_eq!(noise.b.f, again.b.f); + } + + #[test] + fn line_is_normalized_to_target_norm() { + let r = 64u16; + let noise = sample_noise(64, r, Sides { a: [4u8; 32], b: [3u8; 32] }, &[7], &[]); + let sq_norm: f32 = noise.a.e.iter().map(|&c| fp16_to_f32(c).powi(2)).sum(); + let norm = sq_norm.sqrt(); + assert!( + (norm - NOISE_TARGET_NORM as f32).abs() < 0.1 * NOISE_TARGET_NORM as f32, + "line L2 norm {norm} should be near {NOISE_TARGET_NORM}" + ); + assert!(noise.a.e.iter().all(|&c| fp16_to_f32(c) != 0.0), "noise never draws zero"); + } + + #[test] + fn lines_key_on_address_side_and_seed() { + let base = Sides { a: [9u8; 32], b: [7u8; 32] }; + let a_changed = Sides { a: [8u8; 32], b: [7u8; 32] }; + let b_changed = Sides { a: [9u8; 32], b: [6u8; 32] }; + let n0 = sample_noise(64, 32, base, &[0], &[0]); + let n_a = sample_noise(64, 32, a_changed, &[0], &[0]); + let n_b = sample_noise(64, 32, b_changed, &[0], &[0]); + + // Global addressing: only E keys on the selected indices. + let n_cols = sample_noise(64, 32, base, &[0], &[256]); + assert_ne!(n0.b.e, n_cols.b.e, "distinct global B-columns must draw distinct E-lines"); + assert_eq!(n0.a.e, n_cols.a.e, "the A E-line depends only on its row"); + assert_eq!(n0.a.f, n_cols.a.f, "the F basis never varies across instances"); + + // Side addressing: FA and FB share seedB but never a Side address. + assert_ne!(n0.a.f, n0.b.f, "FA and FB are distinct Side addresses under seedB"); + + // Seed addressing: EA from seedA; both F bases and EB from seedB. + assert_eq!(n0.a.f, n_a.a.f, "FA is independent of seedA"); + assert_ne!(n0.a.e, n_a.a.e, "EA draws from seedA"); + assert_eq!(n0.b.e, n_a.b.e, "EB is independent of seedA"); + assert_ne!(n0.a.f, n_b.a.f, "FA draws from seedB"); + assert_ne!(n0.b.f, n_b.b.f, "FB draws from seedB"); + } + + #[test] + fn seed_chain_binds_roots_key_and_params() { + let keys = Sides { a: [0x5au8; 32], b: [0x5bu8; 32] }; + let roots = Sides { a: [1u8; 32], b: [2u8; 32] }; + let p = Sides { a: vec![10, 11], b: vec![20, 21] }; + let base = noise_seeds(&keys, &roots, &p); + + // seedB folds root_B, keyB and pB; seedA folds root_A, seedB, keyA and pA. + let other_root_b = noise_seeds(&keys, &Sides { a: roots.a, b: [9u8; 32] }, &p); + assert_ne!(base.b, other_root_b.b, "seedB binds root_B"); + assert_ne!(base.a, other_root_b.a, "seedA binds seedB (and hence root_B)"); + + let other_root_a = noise_seeds(&keys, &Sides { a: [9u8; 32], b: roots.b }, &p); + assert_eq!(base.b, other_root_a.b, "seedB is independent of root_A"); + assert_ne!(base.a, other_root_a.a, "seedA binds root_A"); + + // keyB feeds seedB (and hence seedA); keyA feeds only seedA. + let other_key_b = noise_seeds(&Sides { a: keys.a, b: [0u8; 32] }, &roots, &p); + assert_ne!(base.b, other_key_b.b, "seedB binds keyB"); + assert_ne!(base.a, other_key_b.a, "seedA binds keyB through seedB"); + + let other_key_a = noise_seeds(&Sides { a: [0u8; 32], b: keys.b }, &roots, &p); + assert_eq!(base.b, other_key_a.b, "seedB is independent of keyA"); + assert_ne!(base.a, other_key_a.a, "seedA binds keyA"); + + let other_pa = noise_seeds(&keys, &roots, &Sides { a: vec![99], b: p.b.clone() }); + assert_ne!(base.a, other_pa.a, "seedA binds pA"); + assert_eq!(base.b, other_pa.b, "seedB is independent of pA"); + } +} diff --git a/zk-pow/src/api/fp16/params.rs b/zk-pow/src/api/fp16/params.rs new file mode 100644 index 000000000..2b2a81e0a --- /dev/null +++ b/zk-pow/src/api/fp16/params.rs @@ -0,0 +1,167 @@ +//! Public parameters and bounds for the FP16 (A100) scheme. +//! +//! A standalone parameter type, deliberately not an arm of the FP8 +//! `Device`/`Quant` enums: the FP16 scheme is a parallel scheme, and wire-level +//! unification of the two under one consensus `Device` enum is a later +//! integration step (it would force the ZK circuit layer to handle A100 before +//! its STARK exists). The constants here fix the plaintext scheme. + +use anyhow::{ensure, Result}; +use serde::{Deserialize, Serialize}; + +/// The committed device for this scheme. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[repr(u8)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(eq, eq_int))] +pub enum Fp16Device { + /// NVIDIA A100 (GA100, `sm_80`). + A100 = 0, +} + +impl Fp16Device { + /// The committed wire tag (folded into the noise-seed public-param encoding). + pub const fn wire_tag(self) -> u8 { + self as u8 + } +} + +impl Fp16Device { + /// Per-row relative noise weight `delta`. + pub const fn delta(self) -> f64 { + match self { + Fp16Device::A100 => 0.5, + } + } + /// Internal accumulator precision (FP32 significand bits). + pub const fn window_bits(self) -> u32 { + match self { + Fp16Device::A100 => 24, + } + } + /// Products per hardware accumulation group. + pub const fn group(self) -> usize { + match self { + Fp16Device::A100 => 8, + } + } +} + +/// The fixed noise rank `r`. +pub const NOISE_RANK: usize = 32; + +/// The recursive ZK wrapper's fold-ladder top height (`2^16`, +/// `circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS[0]`). The current wrapper is +/// one-group-per-row, so every batch table's live height must fit under this; the +/// fuller envelope awaits the deferred groups-per-row packing. Kept here (api) as a +/// closed-form mirror so a geometry the wrapper cannot prove is rejected before any +/// circuit work; keep in sync with the circuit ladder. +pub const WRAPPER_LADDER_TOP: usize = 1 << 16; + +/// Public parameters of one FP16 lottery tile. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Fp16Params { + pub device: Fp16Device, + /// Rows of `A` in the tile (`|I_A|`). + pub h: usize, + /// Rows of `B` in the tile (`|I_B|`), i.e. output-tile columns. + pub w: usize, + /// Inner dimension. + pub k: usize, + /// Noise rank. + pub r: usize, +} + +impl Fp16Params { + /// Validates the tile bounds (the `CheckPublic` analogue). Mirrors the + /// whitepaper's admissible ranges, with the inner dimension a multiple of + /// the device group size. + pub fn validate(&self) -> Result<()> { + ensure!(self.r == NOISE_RANK, "noise rank must be {NOISE_RANK}"); + ensure!(self.k > 0 && self.k % self.device.group() == 0, "k must be a positive multiple of the group size"); + ensure!(self.h >= 4, "|I_A| must be >= 4"); + ensure!(self.w >= 16, "|I_B| must be >= 16"); + let cells = self.h.checked_mul(self.w).expect("tile area overflow"); + ensure!((256..=2048).contains(&cells), "tile area |I_A|*|I_B| must be in [256, 2048]"); + ensure!(self.k.checked_mul(self.h + self.w).map(|x| x <= 1 << 22).unwrap_or(false), "k*(|I_A|+|I_B|) must be <= 2^22"); + + // Wrapper-legal envelope: every batch table's live height must fit under the + // one-group-per-row wrapper's 2^16 ladder top (see [`WRAPPER_LADDER_TOP`]), or + // the tile cannot be ZK-proved/verified. These mirror the circuit table-height + // formulas in `circuit::fp16::driver` (matmul/policy `h*w*k/g`; quant chain + // `(h+w)*k`; per-side noise matmul `max(h,w)*k*(r/g)`; NoiseStark `(h+w+2k)*r`), + // with `r == NOISE_RANK` and `g` the device group; the noise-BLAKE3 table + // (`8*(h+w+2k+3)`) is looser than NoiseStark and thus implied. + let (h, w, k, r, g) = (self.h, self.w, self.k, self.r, self.device.group()); + let top = WRAPPER_LADDER_TOP; + let fits = |live: Option| live.map(|x| x <= top).unwrap_or(false); + ensure!( + fits(h.checked_mul(w).and_then(|x| x.checked_mul(k)).map(|x| x / g)), + "tile exceeds the FP16 wrapper matmul height (|I_A|*|I_B|*k/{g} <= 2^16)" + ); + ensure!( + fits((h + w).checked_mul(k)), + "tile exceeds the FP16 wrapper quant height ((|I_A|+|I_B|)*k <= 2^16)" + ); + ensure!( + fits(h.max(w).checked_mul(k).and_then(|x| x.checked_mul(r)).map(|x| x / g)), + "tile exceeds the FP16 wrapper noise-matmul height (max(|I_A|,|I_B|)*k*r/{g} <= 2^16)" + ); + ensure!( + fits((h + w).checked_add(2 * k).and_then(|s| s.checked_mul(r))), + "tile exceeds the FP16 wrapper NoiseStark height ((|I_A|+|I_B|+2k)*r <= 2^16)" + ); + + // The jackpot lottery extracts exactly 16 lanes as a `br x bc` Blake split of + // the tile (`br | h`, `bc | w`, `br*bc = 16`). A tile admitting no such split + // cannot produce a ticket, so require at least one factorization of 16 to + // divide the two tile dims. + const LANES: usize = 16; + ensure!( + (1..=LANES).filter(|br| LANES % br == 0).any(|br| h % br == 0 && w % (LANES / br) == 0), + "tile admits no 16-lane Blake split (need br|{h}, bc|{w}, br*bc=16)" + ); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a100_constants() { + assert_eq!(Fp16Device::A100.delta(), 0.5); + assert_eq!(Fp16Device::A100.window_bits(), 24); + assert_eq!(Fp16Device::A100.group(), 8); + } + + #[test] + fn bounds() { + let ok = Fp16Params { device: Fp16Device::A100, h: 4, w: 64, k: 256, r: 32 }; + ok.validate().unwrap(); + // k not a multiple of 8. + assert!(Fp16Params { k: 100, ..ok }.validate().is_err()); + // tile too small. + assert!(Fp16Params { h: 4, w: 16, ..ok }.validate().is_err()); + // wrong rank. + assert!(Fp16Params { r: 16, ..ok }.validate().is_err()); + } + + #[test] + fn wrapper_legal_envelope() { + let ok = Fp16Params { device: Fp16Device::A100, h: 4, w: 64, k: 256, r: 32 }; + ok.validate().unwrap(); + // k=256 is the largest wrapper-legal k for w=64 (noise matmul max(h,w)*k*(r/g) + // = 64*256*4 = 2^16, exactly the ladder top). k=512 overflows it. + let err = Fp16Params { k: 512, ..ok }.validate().unwrap_err(); + assert!(format!("{err:#}").contains("wrapper"), "got: {err:#}"); + // A large-k tile that passed the old k*(h+w) <= 2^22 bound but blows the + // one-group-per-row wrapper (h*w*k/8 = 2^17 > 2^16) is now rejected. + let err = Fp16Params { k: 4096, ..ok }.validate().unwrap_err(); + assert!(format!("{err:#}").contains("wrapper"), "got: {err:#}"); + // A narrow tile reaches larger k (w=16): noise matmul 16*k*4 <= 2^16 -> k <= 1024, + // but NoiseStark (h+w+2k)*r <= 2^16 -> h+w+2k <= 2048 binds k <= ~990. + Fp16Params { device: Fp16Device::A100, h: 16, w: 16, k: 960, r: 32 }.validate().unwrap(); + assert!(Fp16Params { device: Fp16Device::A100, h: 16, w: 16, k: 1024, r: 32 }.validate().is_err()); + } +} diff --git a/zk-pow/src/api/fp16/plain_proof.rs b/zk-pow/src/api/fp16/plain_proof.rs new file mode 100644 index 000000000..e8ecc5a0d --- /dev/null +++ b/zk-pow/src/api/fp16/plain_proof.rs @@ -0,0 +1,535 @@ +//! FP16 (A100) plaintext certificate: the wire witness and its parse gate. +//! +//! The FP16 analogue of [`crate::api::fp8::plain_proof::PlainProofV4`], over raw +//! FP16 operands. The public statement (device, `h`/`w`/`k`/`r`, the periodic +//! tile patterns `P_A`/`P_B`, the hash ids, the proof-carried ancestor header) +//! rides in [`Fp16JobParams`]; the private witness is the two committed FP16 +//! operand trees opened at the selected tile rows ([`Fp16MatrixProof`]). +//! +//! The codec is canonical fixint bincode and rejects trailing bytes. +//! [`Fp16PlainProof::parse_proof`] is the security gate: it checks witness shape, +//! derives the opening key and the B-then-A noise-seed chain, authenticates and +//! opens both operand trees (the real Merkle open+rebuild), and derives the +//! deterministic FP16 noise — returning everything +//! [`crate::api::fp16::verify::verify_fp16_plain_proof`] needs to replay the tile. + +use anyhow::{Result, ensure}; +use pearl_blake3::MerkleProof; +use serde::{Deserialize, Serialize}; + +use super::commitment::verify_and_open_rows; +use super::noise::{Noise16, commitment_keys, noise_seeds, sample_noise}; +use super::params::{Fp16Device, Fp16Params}; +use crate::api::fp8::public_params::HashId; +use crate::api::layout::AxisPattern; +use crate::api::primitives::{Hash256, IncompleteBlockHeader, Sides}; +use crate::circuit::utils::macros::ensure_eq; + +/// Per-operand public parameters: total committed rows, Merkle chunking, and the +/// periodic tile pattern selecting the opened rows. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(name = "Fp16OperandParams", get_all))] +pub struct Fp16OperandParams { + /// Total rows committed in this operand's tree (`m` for A, `n` for B). + pub num_rows: u32, + /// Merkle leaf chunk length. + pub hash_id: HashId, + /// The periodic tile partition (`P_A` or `P_B`). + pub pattern: AxisPattern, +} + +/// The public statement tuple carried by the witness. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(name = "Fp16JobParams"))] +pub struct Fp16JobParams { + /// The proof-carried ancestor header `σ_Δ` (folded into the seed chain). + pub ancestor_header: IncompleteBlockHeader, + /// The committed device (A100). + pub device: Fp16Device, + /// Inner dimension `k`. + pub k: u32, + /// Noise rank `r`. + pub r: u32, + /// A-side (rows) and B-side (columns) operand params. + pub operands: Sides, +} + +impl Fp16JobParams { + /// `pB` for the seed chain: `σ_Δ ‖ k ‖ r ‖ device ‖ n ‖ hash_id_B ‖ P_B`. Exposed in-crate so the + /// FP16 ZK driver can derive the noise seeds from the same public-parameter encoding + /// ([`crate::circuit::fp16::driver`]). + pub(crate) fn encode_p_b(&self) -> Vec { + let mut v = self.ancestor_header.to_bytes().to_vec(); + v.extend_from_slice(&self.k.to_le_bytes()); + v.extend_from_slice(&self.r.to_le_bytes()); + v.push(self.device.wire_tag()); + v.extend_from_slice(&self.operands.b.num_rows.to_le_bytes()); + v.push(self.operands.b.hash_id as u8); + v.extend_from_slice(&self.operands.b.pattern.to_bytes()); + v + } + + /// `pA` for the seed chain: `k ‖ r ‖ device ‖ m ‖ hash_id_A ‖ P_A`. Exposed in-crate (see + /// [`Self::encode_p_b`]). + pub(crate) fn encode_p_a(&self) -> Vec { + let mut v = Vec::new(); + v.extend_from_slice(&self.k.to_le_bytes()); + v.extend_from_slice(&self.r.to_le_bytes()); + v.push(self.device.wire_tag()); + v.extend_from_slice(&self.operands.a.num_rows.to_le_bytes()); + v.push(self.operands.a.hash_id as u8); + v.extend_from_slice(&self.operands.a.pattern.to_bytes()); + v + } +} + +/// One operand's committed tree opened at the selected tile rows. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(name = "Fp16MatrixProof"))] +pub struct Fp16MatrixProof { + #[serde( + serialize_with = "MerkleProof::serialize_variable_chunk", + deserialize_with = "MerkleProof::deserialize_variable_chunk" + )] + pub proof: MerkleProof, + /// The opened global row indices (must equal the pattern's tile offsets). + pub row_indices: Vec, +} + +/// The FP16 plaintext certificate. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(name = "Fp16PlainProof"))] +pub struct Fp16PlainProof { + pub job: Fp16JobParams, + pub values: Sides, +} + +/// Validates `claimed` opened row indices as exactly one committed lottery tile +/// of `pattern`: a valid periodic base plus the pattern's tile offsets +/// (`base + P.tile_offsets()`), every index inside `num_rows`. Returns the +/// indices as `usize` (GLOBAL addresses). +/// +/// `tile_offsets()` always starts at `0`, so the base is the first opened index +/// (`t_r * h` for the contiguous A100 layout; `base == 0` is the dense origin +/// tile). This mirrors the FP8 `_validate_indices` discipline and keeps the +/// opened indices global, so the `E` noise lines — which key on the selected +/// global row/col index — match the miner's full-matrix search. +fn tile_row_indices(pattern: &AxisPattern, claimed: &[usize], num_rows: usize, name: &str) -> Result> { + let offsets = pattern.tile_offsets(); + ensure_eq!(claimed.len(), offsets.len(), "{name}: opened rows must select exactly one lottery tile"); + let base = *claimed.first().expect("non-empty: length checked against tile_offsets above"); + let base_u32 = u32::try_from(base).map_err(|_| anyhow::anyhow!("{name}: tile base {base} overflows u32"))?; + ensure!( + pattern.offset_is_valid(base_u32), + "{name}: opened rows are not based at a valid periodic tile offset (base={base})" + ); + let expected: Vec = offsets.iter().map(|&o| base + o as usize).collect(); + ensure_eq!(claimed, expected.as_slice(), "{name}: opened rows must equal base + tile offsets"); + ensure!(claimed.iter().all(|&i| i < num_rows), "{name}: opened tile row out of range for {num_rows} rows"); + Ok(expected) +} + +/// The authenticated, opened witness: what the tile replay needs. +pub struct Fp16Opened { + pub params: Fp16Params, + pub rows_pattern: AxisPattern, + pub cols_pattern: AxisPattern, + /// `h x k` opened FP16 A rows, row-major. + pub a_rows: Vec, + /// `w x k` opened FP16 B rows (columns of `B^T`), row-major. + pub b_rows: Vec, + /// The deterministic FP16 noise factors. + pub noise: Noise16, + /// The A-side noise seed that keys the jackpot ticket. + pub seed_a: Hash256, +} + +impl Fp16PlainProof { + /// Strict fixint bincode. + pub fn to_bytes(&self) -> Result> { + use bincode::Options; + bincode::options() + .with_fixint_encoding() + .serialize(self) + .map_err(|e| anyhow::anyhow!("serialize Fp16PlainProof: {e}")) + } + + /// Inverse of [`Self::to_bytes`]. No compat ladder; rejects trailing bytes. + pub fn from_bytes(bytes: &[u8]) -> Result { + use bincode::Options; + bincode::options() + .with_fixint_encoding() + .reject_trailing_bytes() + .deserialize(bytes) + .map_err(|e| anyhow::anyhow!("deserialize Fp16PlainProof: {e}")) + } + + /// Authenticate the witness and derive everything the tile replay needs. + /// + /// This is the security gate: do not treat a deserialized [`Fp16PlainProof`] + /// as validated. `proposed_header` (`σ̂`) is the caller's header: it keys the + /// A-side tree and the A branch of the seed chain. The B-side tree and the B + /// branch key on the proof-carried ancestor header (`σ_Δ`, the + /// [`Fp16JobParams::ancestor_header`]). NOTE: this plaintext path is retired as + /// a consensus path (the wired V5 consensus certificate is the header-bound ZK + /// cert, `verify_fp16_zk_cert_ffi`); it performs NO state-window authentication + /// of the ancestor itself — only the consensus verifier's + /// `check_fp16_certificate_ancestors` (`zk-pow/bindings/go/src/fp16.rs`) does + /// that. Do not wire this as a standalone acceptance gate (see the FP16 keying + /// docs in [`crate::api::fp16::noise`]). + pub fn parse_proof(&self, proposed_header: &IncompleteBlockHeader) -> Result { + ensure!(self.job.device == Fp16Device::A100, "FP16 device must be A100"); + + let rows_pattern = self.job.operands.a.pattern.clone(); + let cols_pattern = self.job.operands.b.pattern.clone(); + let k = self.job.k as usize; + let r = self.job.r as usize; + let h = rows_pattern.tile_size() as usize; + let w = cols_pattern.tile_size() as usize; + + let params = Fp16Params { device: self.job.device, h, w, k, r }; + params.validate()?; + + let m = self.job.operands.a.num_rows as usize; + let n = self.job.operands.b.num_rows as usize; + + // The opened rows must be one committed lottery tile: a valid periodic + // base plus the pattern's tile offsets (`base + P.tile_offsets()`). The + // base is the tile's global row origin (`t_r * h` for the contiguous + // A100 layout); `base == 0` is the dense origin tile. + let a_idx = tile_row_indices(&rows_pattern, &self.values.a.row_indices, m, "P_A")?; + let b_idx = tile_row_indices(&cols_pattern, &self.values.b.row_indices, n, "P_B")?; + + // The per-side opening keys: keyA = H_"key-A"(proposed), keyB = + // H_"key-B"(ancestor). B's tree only rebuilds under the ancestor it was + // committed against, so an out-of-window / unauthenticated ancestor fails + // the B-side Merkle rebuild below. + let keys = commitment_keys(proposed_header, &self.job.ancestor_header); + let root_a = self.values.a.proof.root; + let root_b = self.values.b.proof.root; + + // Authenticate and open both operand trees (real Merkle open + rebuild). + let a_rows = + verify_and_open_rows(&self.values.a.proof, &a_idx, m, k, self.job.operands.a.hash_id, keys.a, &root_a)?; + let b_rows = + verify_and_open_rows(&self.values.b.proof, &b_idx, n, k, self.job.operands.b.hash_id, keys.b, &root_b)?; + + // The B-then-A noise-seed chain over the authenticated roots. + let roots = Sides { a: root_a, b: root_b }; + let p = Sides { a: self.job.encode_p_a(), b: self.job.encode_p_b() }; + let seeds = noise_seeds(&keys, &roots, &p); + + let a_idx_u32: Vec = a_idx.iter().map(|&i| i as u32).collect(); + let b_idx_u32: Vec = b_idx.iter().map(|&i| i as u32).collect(); + let noise = sample_noise(k, r as u16, seeds, &a_idx_u32, &b_idx_u32); + + Ok(Fp16Opened { params, rows_pattern, cols_pattern, a_rows, b_rows, noise, seed_a: seeds.a }) + } +} + +#[cfg(feature = "pyo3")] +#[pyo3::pymethods] +impl Fp16OperandParams { + #[new] + fn py_new(num_rows: u32, hash_id: HashId, pattern: AxisPattern) -> Self { + Self { + num_rows, + hash_id, + pattern, + } + } +} + +#[cfg(feature = "pyo3")] +#[pyo3::pymethods] +impl Fp16MatrixProof { + #[new] + fn py_new(proof: &MerkleProof, row_indices: Vec) -> Self { + Self { + proof: proof.clone(), + row_indices, + } + } + + #[getter] + fn row_indices(&self) -> Vec { + self.row_indices.clone() + } + + #[getter] + fn root<'py>(&self, py: pyo3::Python<'py>) -> pyo3::Bound<'py, pyo3::types::PyBytes> { + pyo3::types::PyBytes::new(py, &self.proof.root) + } +} + +#[cfg(feature = "pyo3")] +#[pyo3::pymethods] +impl Fp16JobParams { + #[new] + fn py_new( + ancestor_header: IncompleteBlockHeader, + device: Fp16Device, + k: u32, + r: u32, + a: Fp16OperandParams, + b: Fp16OperandParams, + ) -> Self { + Self { + ancestor_header, + device, + k, + r, + operands: Sides { a, b }, + } + } + + #[getter] + fn ancestor_header(&self) -> IncompleteBlockHeader { + self.ancestor_header + } + + #[getter] + fn device(&self) -> Fp16Device { + self.device + } + + #[getter] + fn k(&self) -> u32 { + self.k + } + + #[getter] + fn r(&self) -> u32 { + self.r + } + + #[getter] + fn a(&self) -> Fp16OperandParams { + self.operands.a.clone() + } + + #[getter] + fn b(&self) -> Fp16OperandParams { + self.operands.b.clone() + } +} + +#[cfg(feature = "pyo3")] +#[pyo3::pymethods] +impl Fp16PlainProof { + #[new] + #[allow(clippy::too_many_arguments)] + fn py_new( + ancestor_header: IncompleteBlockHeader, + device: Fp16Device, + k: u32, + r: u32, + a: Fp16OperandParams, + b: Fp16OperandParams, + values_a: Fp16MatrixProof, + values_b: Fp16MatrixProof, + ) -> Self { + Self { + job: Fp16JobParams { + ancestor_header, + device, + k, + r, + operands: Sides { a, b }, + }, + values: Sides { + a: values_a, + b: values_b, + }, + } + } + + #[getter] + fn ancestor_header(&self) -> IncompleteBlockHeader { + self.job.ancestor_header + } + + #[getter] + fn device(&self) -> Fp16Device { + self.job.device + } + + #[getter] + fn k(&self) -> u32 { + self.job.k + } + + #[getter] + fn r(&self) -> u32 { + self.job.r + } + + #[getter] + fn a(&self) -> Fp16OperandParams { + self.job.operands.a.clone() + } + + #[getter] + fn b(&self) -> Fp16OperandParams { + self.job.operands.b.clone() + } + + #[getter] + fn values_a(&self) -> Fp16MatrixProof { + self.values.a.clone() + } + + #[getter] + fn values_b(&self) -> Fp16MatrixProof { + self.values.b.clone() + } + + #[getter] + fn min_cert_version(&self) -> u32 { + crate::ffi::plain_proof::CertificateVersion::PlainFp16 as u32 + } + + #[pyo3(name = "to_bytes")] + fn py_to_bytes(&self) -> pyo3::PyResult> { + Self::to_bytes(self).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) + } + + #[staticmethod] + #[pyo3(name = "from_bytes")] + fn py_from_bytes(data: Vec) -> pyo3::PyResult { + Self::from_bytes(&data).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) + } + + fn to_base64(&self) -> pyo3::PyResult { + use base64::{Engine as _, engine::general_purpose::STANDARD}; + Ok(STANDARD.encode(self.py_to_bytes()?)) + } + + #[staticmethod] + fn from_base64(data: &str) -> pyo3::PyResult { + use base64::{Engine as _, engine::general_purpose::STANDARD}; + let bytes = STANDARD + .decode(data) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Base64 decode failed: {e}")))?; + Self::from_bytes(&bytes).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) + } +} + +#[cfg(test)] +mod seed_chain_dump { + //! Additive, test-only oracle dump for the host-side FP16 miner seed chain + //! (`pearl_gemm.fp16_miner._seed_chain`). For a fixed (header, operands, + //! params) it writes the per-side opening keys, the committed Merkle roots, + //! the `encode_p_a`/`encode_p_b` public-parameter encodings, the B-then-A + //! noise seeds, and the jackpot `pow_key` -- so the Python host reproduction + //! can be asserted bit-for-bit. Ignored by default; run with: + //! ```text + //! PEARL_FP16_SEEDCHAIN_OUT=/path/seedchain.txt cargo test -p zk-pow --lib -- \ + //! api::fp16::plain_proof::seed_chain_dump::dump_seed_chain --ignored --exact --nocapture + //! ``` + use super::*; + use crate::api::fp16::commitment::commit_operand; + use crate::api::fp16::noise::{commitment_keys, key_a, key_b, noise_seeds, subkey}; + use crate::api::fp16::params::Fp16Device; + use crate::api::fp8::public_params::HashId; + use crate::api::layout::AxisPattern; + use crate::api::layout::DimType::{Blake, Fold}; + use crate::api::primitives::{IncompleteBlockHeader, Sides}; + + /// Deterministic u16 fill, byte-identical to the Python harness formula: + /// `((i * 2654435761 + 1013904223) (mod 2^64)) >> 13 & 0xFFFF`. + fn fill(n: usize, salt: u64) -> Vec { + (0..n) + .map(|i| { + let x = (i as u64) + .wrapping_add(salt) + .wrapping_mul(2654435761) + .wrapping_add(1013904223); + ((x >> 13) & 0xFFFF) as u16 + }) + .collect() + } + + #[test] + #[ignore = "dumps the FP16 miner seed-chain oracle vectors; run explicitly"] + fn dump_seed_chain() { + use std::fmt::Write as _; + + fn hx(b: &[u8]) -> String { + b.iter().map(|x| format!("{x:02x}")).collect() + } + + const M: usize = 8; + const N: usize = 128; + const K: usize = 256; + const R: u32 = 32; + const HASH: HashId = HashId::Blake3Chunk1024; + const NBITS: u32 = 0x207f_ffff; + + let header = IncompleteBlockHeader::new_for_test(NBITS); + // Depth-0 ancestor coincidence: the miner proposes at depth 0. + let ancestor = header; + + let a_full = fill(M * K, 0x1111); + let b_full = fill(N * K, 0x2222); + + let rp = AxisPattern::new(&[(4, Blake)]).unwrap(); // h = 4 + let cp = AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap(); // w = 64 + + let keys = commitment_keys(&header, &ancestor); + assert_eq!(keys.a, key_a(&header)); + assert_eq!(keys.b, key_b(&ancestor)); + + let tree_a = commit_operand(&a_full, M, K, HASH, keys.a).unwrap(); + let tree_b = commit_operand(&b_full, N, K, HASH, keys.b).unwrap(); + let root_a = tree_a.root(); + let root_b = tree_b.root(); + + let job = Fp16JobParams { + ancestor_header: ancestor, + device: Fp16Device::A100, + k: K as u32, + r: R, + operands: Sides { + a: Fp16OperandParams { num_rows: M as u32, hash_id: HASH, pattern: rp }, + b: Fp16OperandParams { num_rows: N as u32, hash_id: HASH, pattern: cp }, + }, + }; + let p_a = job.encode_p_a(); + let p_b = job.encode_p_b(); + + let roots = Sides { a: root_a, b: root_b }; + let p = Sides { a: p_a.clone(), b: p_b.clone() }; + let seeds = noise_seeds(&keys, &roots, &p); + let pow_key = subkey(b"pearl/v4/FP8/jackpot", Some(&seeds.a)); + + let mut out = String::new(); + writeln!(out, "m {M}").unwrap(); + writeln!(out, "n {N}").unwrap(); + writeln!(out, "k {K}").unwrap(); + writeln!(out, "r {R}").unwrap(); + writeln!(out, "nbits {NBITS:#010x}").unwrap(); + writeln!(out, "a_salt 0x1111").unwrap(); + writeln!(out, "b_salt 0x2222").unwrap(); + writeln!(out, "chunk_len {}", HASH.chunk_len()).unwrap(); + writeln!(out, "header {}", hx(&header.to_bytes())).unwrap(); + writeln!(out, "ancestor {}", hx(&ancestor.to_bytes())).unwrap(); + writeln!(out, "p_a_bytes {}", a_full.len()).unwrap(); + writeln!(out, "key_a {}", hx(&keys.a)).unwrap(); + writeln!(out, "key_b {}", hx(&keys.b)).unwrap(); + writeln!(out, "root_a {}", hx(&root_a)).unwrap(); + writeln!(out, "root_b {}", hx(&root_b)).unwrap(); + writeln!(out, "p_a {}", hx(&p_a)).unwrap(); + writeln!(out, "p_b {}", hx(&p_b)).unwrap(); + writeln!(out, "seed_a {}", hx(&seeds.a)).unwrap(); + writeln!(out, "seed_b {}", hx(&seeds.b)).unwrap(); + writeln!(out, "pow_key {}", hx(&pow_key)).unwrap(); + writeln!(out, "pattern_a {}", hx(&job.operands.a.pattern.to_bytes())).unwrap(); + writeln!(out, "pattern_b {}", hx(&job.operands.b.pattern.to_bytes())).unwrap(); + + let path = std::env::var("PEARL_FP16_SEEDCHAIN_OUT") + .unwrap_or_else(|_| "/tmp/fp16_seedchain.txt".to_string()); + std::fs::write(&path, &out).unwrap(); + println!("wrote FP16 seed-chain oracle to {path}"); + } +} diff --git a/zk-pow/src/api/fp16/policy.rs b/zk-pow/src/api/fp16/policy.rs new file mode 100644 index 000000000..6d97ebd25 --- /dev/null +++ b/zk-pow/src/api/fp16/policy.rs @@ -0,0 +1,523 @@ +//! The "unpredictable accumulation steps" jackpot policy for the FP16 scheme. +//! +//! During its bit-exact tile replay the verifier records, per cell and per +//! group of 8 products, a [`PolicyStep`]: whether the step was a *breakpoint* +//! (the accumulator alignment or the FP32 rounding discarded a nonzero bit) and +//! how many products were truncated. From these it derives two tile-global +//! quantities and accepts only when both clear their thresholds: +//! +//! * `f_bp` — the breakpoint density, the fraction of group steps that are +//! breakpoints. It lower-bounds how much of the accumulation is irrecoverable +//! from the exact sum alone. +//! * `rho` — the certified-work ratio, an attacker-favorable lower bound on the +//! cost of reconstructing the tile relative to honest work (Appendix "Certified +//! -work ratio" of the FP16 whitepaper). +//! +//! The thresholds `f_bp >= 0.30` and `rho >= 1.2` are the calibrated FP16 gate. +//! Honest and realistic FP16 workloads sit well above them; the construction is +//! what makes BF16 ineligible (its products rarely truncate), so these +//! thresholds apply only to the FP16 `Quant` value. + +use super::accumulate::{a100_dot, PolicyStep, GROUP}; +use super::dtype::fp16_to_f32; +use super::quantization::{BuiltRows16, DELTA}; +use crate::api::fp8::dtype::bf16_to_f32; + +/// Noise rank `r`, which is also the attacker's assumed per-cell cost to obtain +/// exact prefix sums over any `k`-range via the low-rank structure. The single +/// source of truth is [`super::params::NOISE_RANK`]; the policy numerator uses +/// it as the `r * N_runs` coefficient. +pub const NOISE_RANK: u64 = super::params::NOISE_RANK as u64; + +/// Minimum breakpoint density for an acceptable FP16 tile. +pub const MIN_FBP: f64 = 0.30; +/// Minimum certified-work ratio for an acceptable FP16 tile. +pub const MIN_RHO: f64 = 1.2; + +/// Liveness threshold (whitepaper "Shared checks"): entry `u` of row `i` is dead +/// iff `|X_iu| >= TAU_IDLE * DELTA * l2_i`. +pub const TAU_IDLE: f64 = 8.0; +/// Maximum fraction of dead entries permitted per tile side. +pub const EPS_IDLE: f64 = 0.015625; // 1/64 +/// Floor on every row's injected noise std `sigma_i = DELTA * alpha_i * l2_i`. +pub const SIGMA_MIN: f64 = 1.0; + +/// The FP8 entry-liveness and noise-floor "shared checks" (whitepaper +/// §"Shared checks"), carried over to bound degenerate operands. These gate the +/// tile *in addition to* the unpredictable-accumulation-steps policy +/// ([`evaluate`]): the density gate is a tail-concentrated safety net, while +/// these two rule out the degenerate-operand classes (noise-dominated or +/// spike-dominated rows) directly, mirroring [`crate::api::fp8::jackpot_policy`]. +/// +/// Both checks are "x-only": they depend only on the clean operand and the +/// floored per-row `l2`/`alpha` recorded at quantization, so they pass or fail +/// identically for every noise draw (grinding the noise gains nothing). +/// +/// `a_rows`/`b_rows` are the clean FP16 operands (`rows x k`, row-major); +/// `a_built`/`b_built` carry the per-row floored `l2` and scale `alpha`. Returns +/// `Err` naming the first failing side/row; `Ok(())` admits both sides. +pub fn check_shared_gates( + a_rows: &[u16], + a_built: &BuiltRows16, + b_rows: &[u16], + b_built: &BuiltRows16, + k: usize, +) -> anyhow::Result<()> { + for (name, rows, built) in [("A", a_rows, a_built), ("B", b_rows, b_built)] { + // Noise floor: sigma_i = DELTA * alpha_i * l2_i >= SIGMA_MIN for every row. + for (i, (&alpha, &l2)) in built.alpha.iter().zip(&built.l2).enumerate() { + let sigma = DELTA * bf16_to_f32(alpha) as f64 * bf16_to_f32(l2) as f64; + anyhow::ensure!( + sigma >= SIGMA_MIN, + "{name} side row {i}: injected noise std {sigma:.4} below floor {SIGMA_MIN}" + ); + } + // Entry liveness: the dead fraction over the side's tile entries is at + // most EPS_IDLE, with `|X_iu| >= TAU_IDLE * DELTA * l2_i` the dead test + // (alpha-free, since sigma_i = DELTA * alpha_i * l2_i and alpha_i > 0). + let dead: usize = rows + .chunks(k) + .zip(&built.l2) + .map(|(row, &l2)| { + let dead_bound = TAU_IDLE * DELTA * bf16_to_f32(l2) as f64; + row.iter().filter(|&&x| fp16_to_f32(x).abs() as f64 >= dead_bound).count() + }) + .sum(); + anyhow::ensure!( + dead as f64 <= EPS_IDLE * rows.len() as f64, + "{name} side: {dead} dead entries exceed the {EPS_IDLE} idle fraction of {}", + rows.len() + ); + } + Ok(()) +} + +/// The outcome of the policy over one opened tile. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct PolicyReport { + /// Breakpoint density over all group steps in the tile. + pub f_bp: f64, + /// Certified-work ratio (attacker-favorable cost lower bound / honest cost). + pub rho: f64, + /// `true` iff the tile clears both thresholds. + pub accept: bool, +} + +/// Evaluates the policy over a tile given each cell's per-group census and the +/// inner dimension `k`. `cells` is `|I_A| * |I_B|`. +/// +/// `rho = sum_cells[ G*N_bp + r*N_runs + N_pt ] / (cells * k)`, where `N_bp` is +/// the number of breakpoint steps, `N_runs` the number of maximal runs of +/// non-breakpoint steps, and `N_pt` the products truncated outside breakpoints. +pub fn evaluate(census: &[Vec], k: usize) -> PolicyReport { + let cells = census.len(); + assert!(cells > 0 && k > 0, "empty tile"); + let steps_per_cell = k.div_ceil(GROUP); + let total_steps = (cells * steps_per_cell) as f64; + + let mut breakpoints = 0u64; + let mut numerator = 0u64; + for cell in census { + let mut n_bp = 0u64; + let mut n_pt = 0u64; + let mut n_runs = 0u64; + let mut in_run = false; + for step in cell { + if step.breakpoint { + n_bp += 1; + in_run = false; + } else { + // Non-breakpoint step (empty no-ops included: they cost nothing + // but belong to the surrounding run). + n_pt += step.products_truncated as u64; + if !in_run { + n_runs += 1; + in_run = true; + } + } + } + breakpoints += n_bp; + numerator += GROUP as u64 * n_bp + NOISE_RANK * n_runs + n_pt; + } + + let f_bp = breakpoints as f64 / total_steps; + let rho = numerator as f64 / (cells * k) as f64; + PolicyReport { + f_bp, + rho, + accept: f_bp >= MIN_FBP && rho >= MIN_RHO, + } +} + +/// Replays an `m x n` tile against the A100 datapath, collecting each cell's +/// per-group census, and evaluates the policy. `a` is `m x k`, `b` is `n x k` +/// (row-major FP16 bit patterns). Convenience wrapper over [`a100_dot`] + +/// [`evaluate`]; also returns the recomputed tile for the ticket. +pub fn replay_and_evaluate( + a: &[u16], + b: &[u16], + m: usize, + n: usize, + k: usize, +) -> (Vec, PolicyReport) { + assert_eq!(a.len(), m * k); + assert_eq!(b.len(), n * k); + let mut tile = vec![0f32; m * n]; + let mut census = Vec::with_capacity(m * n); + for i in 0..m { + for j in 0..n { + let mut steps = Vec::with_capacity(k.div_ceil(GROUP)); + tile[i * n + j] = a100_dot( + &a[i * k..i * k + k], + &b[j * k..j * k + k], + 0.0, + Some(&mut steps), + ); + census.push(steps); + } + } + let report = evaluate(&census, k); + (tile, report) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn step(bp: bool, pt: u32) -> PolicyStep { + PolicyStep { nonempty: true, breakpoint: bp, products_truncated: pt } + } + + #[test] + fn rho_formula() { + // One cell, k = 40 (5 group steps): bp, nonbp(2), nonbp(1), bp, nonbp. + let cell = vec![ + step(true, 0), + step(false, 2), + step(false, 1), + step(true, 0), + step(false, 0), + ]; + let r = evaluate(&[cell], 40); + // N_bp=2, N_runs=2 (steps 1-2, step 4), N_pt=3. + // numerator = 8*2 + 32*2 + 3 = 83; rho = 83/40 = 2.075; f_bp = 2/5 = 0.4. + assert!((r.f_bp - 0.4).abs() < 1e-12); + assert!((r.rho - 83.0 / 40.0).abs() < 1e-12); + assert!(r.accept); + } + + // --- Shared entry-liveness + noise-floor gates --- + + mod shared_gates { + use super::super::{check_shared_gates, EPS_IDLE}; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::fp16::quantization::{noisy_quantize, row_norms, BuiltRows16}; + + const K: usize = 64; + const R: usize = 32; + + /// Build one side (clean rows + the quantization record) with real + /// noise, mirroring the honest regime. + fn build(rows: &[u16]) -> (Vec, BuiltRows16) { + let num_rows = rows.len() / K; + // Deterministic +-scale noise lines (near NOISE_TARGET_NORM / sqrt(r)). + let noise_val = f32_to_fp16(45.0).unwrap(); + let neg = f32_to_fp16(-45.0).unwrap(); + let e: Vec = (0..num_rows * R).map(|i| if i % 3 == 0 { neg } else { noise_val }).collect(); + let f: Vec = (0..K * R).map(|i| if i % 5 == 0 { neg } else { noise_val }).collect(); + let norms: Vec<(u16, u16)> = rows.chunks(K).map(|row| row_norms(row).unwrap()).collect(); + let built = noisy_quantize(rows, &e, &f, &norms, R).unwrap(); + (rows.to_vec(), built) + } + + /// Well-conditioned clean rows (spread magnitudes, no spikes). + fn honest_rows(num_rows: usize) -> Vec { + (0..num_rows * K) + .map(|i| f32_to_fp16(((i * 37 % 97) as f32 - 48.0) * 0.5).unwrap()) + .collect() + } + + #[test] + fn admits_honest_rows() { + let (a, ab) = build(&honest_rows(4)); + let (b, bb) = build(&honest_rows(16)); + check_shared_gates(&a, &ab, &b, &bb, K).expect("honest rows must pass the shared gates"); + } + + /// The noise floor `sigma_i = DELTA*alpha_i*l2_i >= SIGMA_MIN` is + /// UNCONDITIONALLY satisfied by honestly-DERIVED scales, for every finite + /// FP16 row and every k in the whitepaper envelope. Reason: the scale + /// derivation sets `alpha = Q / (linf + DELTA*sqrt(r)*l2)` with + /// `linf = max|x| <= sqrt(k)*rms ~ sqrt(k)*l2`, so + /// `sigma = DELTA*Q*l2 / (linf + DELTA*sqrt(r)*l2) >= DELTA*Q / (sqrt(k) + + /// DELTA*sqrt(r))`, which for k <= 2^22 (`sqrt(k) <= 2048`) is `>= ~16`. + /// Flooring l2 only raises sigma. So the noise-floor check can only fail + /// on an INCONSISTENT (alpha, l2) pair -- which neither the plaintext + /// verifier (it derives both) nor the FP16 ZK circuit (row_scale_stark + /// *constrains* alpha = f(l2, linf)) can present. This test is the + /// machine-checked witness that the floor is implied on the derived path; + /// it is why the ZK circuit needs NO explicit noise-floor constraint. + #[test] + fn noise_floor_is_implied_by_honest_derivation() { + use crate::api::fp16::quantization::DELTA; + use crate::api::fp8::dtype::bf16_to_f32; + + // An adversarial corpus of single rows: spikes, near-zero, flat, + // wide-magnitude, across several k (incl. the small/large extremes the + // envelope allows for a tile; the bound is monotone decreasing in k). + let mut worst = f64::INFINITY; + for k in [8usize, 16, 64, 256, 1024, 2048] { + let mut cases: Vec> = Vec::new(); + // flat ones; single spike + zeros; two spikes; geometric spread; + // all (near) zero; alternating tiny/huge. + let one = f32_to_fp16(1.0).unwrap(); + let max = f32_to_fp16(60000.0).unwrap(); + let tiny = f32_to_fp16(6e-5).unwrap(); + cases.push(vec![one; k]); + cases.push({ let mut r = vec![f32_to_fp16(0.0).unwrap(); k]; r[0] = max; r }); + cases.push({ let mut r = vec![f32_to_fp16(0.0).unwrap(); k]; r[0] = max; r[1] = max; r }); + cases.push((0..k).map(|j| f32_to_fp16(2f32.powi((j % 20) as i32 - 10)).unwrap()).collect()); + cases.push(vec![tiny; k]); + cases.push((0..k).map(|j| if j % 2 == 0 { max } else { tiny }).collect()); + for row in &cases { + let norms = [row_norms(row).unwrap()]; + let built = noisy_quantize(row, &vec![0u16; R], &vec![0u16; k * R], &norms, R).unwrap(); + let sigma = DELTA * bf16_to_f32(built.alpha[0]) as f64 * bf16_to_f32(built.l2[0]) as f64; + worst = worst.min(sigma); + assert!(sigma >= 1.0, "noise floor violated by a DERIVED scale (k={k}): sigma={sigma}"); + } + } + // The observed minimum is well above 1 (the derived floor has large margin). + assert!(worst > 2.0, "derived sigma minimum {worst} unexpectedly close to the floor"); + } + + #[test] + fn noise_floor_rejects_vanishing_sigma() { + let (a, mut ab) = build(&honest_rows(4)); + let (b, bb) = build(&honest_rows(16)); + // Force row 0's floored l2 to 2^-32, so sigma = DELTA*alpha*l2 << 1. + ab.l2[0] = 0x2F80; // bf16 code for 2^-32 + let err = check_shared_gates(&a, &ab, &b, &bb, K).expect_err("sub-floor sigma must reject"); + assert!(format!("{err:#}").contains("below floor"), "got: {err:#}"); + } + + #[test] + fn liveness_rejects_spike_dominated_rows() { + // Each A row: two unit spikes, the rest zero. Per row l2 = sqrt(2/K), + // so each spike hits the dead bound TAU_IDLE*DELTA*l2 = 4*sqrt(2/K) < 1, + // i.e. two dead entries per row -> dead fraction 2/K > EPS_IDLE = 1/64. + let spikes = 2usize; + let mut a_rows = vec![0u16; 4 * K]; + for r in 0..4 { + for s in 0..spikes { + a_rows[r * K + s] = f32_to_fp16(1.0).unwrap(); + } + } + let (a, ab) = build(&a_rows); + let (b, bb) = build(&honest_rows(16)); + assert!(spikes as f64 / K as f64 > EPS_IDLE, "test geometry must exceed the idle fraction"); + let err = check_shared_gates(&a, &ab, &b, &bb, K).expect_err("spike-dominated rows must reject"); + assert!(format!("{err:#}").contains("dead entries"), "got: {err:#}"); + } + } + + #[test] + fn flat_tile_is_rejected() { + // No breakpoints, no truncation (the BF16-weak / flat-input regime): + // one long run, rho = 32/80 = 0.4, f_bp = 0. + let cell: Vec = (0..10).map(|_| step(false, 0)).collect(); + let r = evaluate(&[cell], 80); + assert_eq!(r.f_bp, 0.0); + assert!(r.rho < MIN_RHO); + assert!(!r.accept); + } + + // ---------------------------------------------------------------------- + // Oracle dump for the sm_80 `fp16_policy` miner kernel (additive, ignored). + // + // Emits, for many random shapes (varied k incl. non-multiples of 8, varied + // magnitudes that exercise breakpoints and product truncations), the exact + // per-cell integer census (`n_bp`, `n_runs`, `n_pt`), the `(breakpoints, + // numerator)` tile totals, the `f_bp`/`rho` f64 bit patterns, `accept`, and + // the recomputed tile (u32 bits). The GA100 kernel is asserted bit-exact + // against this. Run with: + // PEARL_POLICY_DUMP=/path/vectors.txt cargo test -p zk-pow --lib \ + // api::fp16::policy::tests::dump_policy_vectors -- --ignored --nocapture + // ---------------------------------------------------------------------- + + /// Per-cell run count mirroring `evaluate`'s inner loop (so the dump carries + /// the exact integer census the fused in-kernel reduction must reproduce). + fn cell_counts(steps: &[PolicyStep]) -> (u64, u64, u64) { + let (mut n_bp, mut n_pt, mut n_runs) = (0u64, 0u64, 0u64); + let mut in_run = false; + for s in steps { + if s.breakpoint { + n_bp += 1; + in_run = false; + } else { + n_pt += s.products_truncated as u64; + if !in_run { + n_runs += 1; + in_run = true; + } + } + } + (n_bp, n_runs, n_pt) + } + + #[test] + #[ignore = "oracle dump for the sm_80 fp16_policy kernel; writes PEARL_POLICY_DUMP"] + fn dump_policy_vectors() { + use super::super::dtype::decompose_fp16; + use std::io::Write; + + // Tiny deterministic SplitMix64 PRNG (no external dep). + let mut state: u64 = 0x9E37_79B9_7F4A_7C15; + let mut next = || { + state = state.wrapping_add(0x9E37_79B9_7F4A_7C15); + let mut z = state; + z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + z ^ (z >> 31) + }; + + // A finite FP16 bit pattern with a bounded exponent (keeps dot products + // well inside the finite range) and a ~12% chance of exact zero. The + // magnitude spread across a row is what makes products truncate and + // group steps hit breakpoints. + let mut gen_fp16 = |exp_lo: i32, exp_hi: i32| -> u16 { + if (next() % 100) < 12 { + return if next() & 1 == 1 { 0x8000 } else { 0x0000 }; + } + let sign = ((next() & 1) as u16) << 15; + let span = (exp_hi - exp_lo + 1) as u64; + let exp = (exp_lo + (next() % span) as i32) as u16; // 1..=30 field + let man = (next() % 0x400) as u16; + let bits = sign | (exp << 10) | man; + // decompose_fp16 would reject 0x1F; our exp range stays < 0x1F. + debug_assert!((bits >> 10) & 0x1F != 0x1F); + let _ = decompose_fp16(bits); + bits + }; + + // (m, n, k) shapes: varied k including non-multiples of 8, a 1xk, and + // mixed exponent windows (narrow => flat/rejected, wide => breakpoints). + let shapes: &[(usize, usize, usize, i32, i32)] = &[ + (1, 1, 7, 1, 20), + (2, 3, 8, 1, 24), + (3, 2, 9, 1, 24), + (4, 4, 16, 1, 26), + (2, 2, 31, 1, 28), + (5, 3, 33, 1, 28), + (4, 6, 64, 1, 28), + (3, 3, 100, 1, 28), + (6, 5, 127, 1, 28), + (2, 4, 256, 1, 28), + (8, 8, 40, 10, 12), // narrow window: near-flat + (7, 7, 48, 1, 29), // wide window: heavy breakpoints + (1, 16, 72, 1, 27), + (16, 1, 72, 1, 27), + // Flat single-exponent windows: near-zero breakpoint density and low + // rho -> the rejected regime (validates the accept=false path and + // f_bp/rho near the 0.30/1.2 thresholds bit-exactly). + (6, 6, 64, 15, 15), + (4, 5, 80, 20, 20), + (8, 8, 128, 1, 29), // large tile, widest window: heavy breakpoints + (10, 7, 200, 1, 28), + ]; + + let path = std::env::var("PEARL_POLICY_DUMP") + .unwrap_or_else(|_| "/tmp/pearl_policy_vectors.txt".to_string()); + let mut out = String::new(); + out.push_str(&format!("{}\n", shapes.len())); + for &(m, n, k, elo, ehi) in shapes { + let a: Vec = (0..m * k).map(|_| gen_fp16(elo, ehi)).collect(); + let b: Vec = (0..n * k).map(|_| gen_fp16(elo, ehi)).collect(); + let (tile, report) = replay_and_evaluate(&a, &b, m, n, k); + + // Recompute the per-cell census and integer totals for the dump. + let mut percell: Vec<(u64, u64, u64)> = Vec::with_capacity(m * n); + let mut breakpoints = 0u64; + let mut numerator = 0u64; + for i in 0..m { + for j in 0..n { + let mut steps = Vec::new(); + let _ = a100_dot(&a[i * k..i * k + k], &b[j * k..j * k + k], 0.0, Some(&mut steps)); + let (nb, nr, npt) = cell_counts(&steps); + breakpoints += nb; + numerator += GROUP as u64 * nb + NOISE_RANK * nr + npt; + percell.push((nb, nr, npt)); + } + } + + out.push_str(&format!("SHAPE {m} {n} {k}\n")); + // a bits, b bits. + out.push_str("A"); + for &x in &a { + out.push_str(&format!(" {x}")); + } + out.push('\n'); + out.push_str("B"); + for &x in &b { + out.push_str(&format!(" {x}")); + } + out.push('\n'); + // tile u32 bits. + out.push_str("TILE"); + for &v in &tile { + out.push_str(&format!(" {}", v.to_bits())); + } + out.push('\n'); + // per-cell (n_bp n_runs n_pt) triples, row-major. + out.push_str("CENSUS"); + for (nb, nr, npt) in &percell { + out.push_str(&format!(" {nb} {nr} {npt}")); + } + out.push('\n'); + // totals + f_bp/rho f64 bits + accept. + out.push_str(&format!( + "EVAL {} {} {} {} {}\n", + breakpoints, + numerator, + report.f_bp.to_bits(), + report.rho.to_bits(), + report.accept as u8 + )); + } + let mut f = std::fs::File::create(&path).expect("create dump"); + f.write_all(out.as_bytes()).expect("write dump"); + eprintln!("wrote {} shapes to {path}", shapes.len()); + } + + #[test] + fn honest_spread_operands_pass() { + // Drive the policy from the embedded reference vectors: the ones with + // large k and heavy truncation model honest/realistic FP16 workloads. + // Their aggregate breakpoint density and work ratio clear the gate. + const VECTORS: &str = include_str!("testdata/a100_dot_vectors.txt"); + let mut census: Vec> = Vec::new(); + let mut k_used = 0; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k < 256 { + continue; // use the large-k (realistic chain) vectors + } + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let mut steps = Vec::new(); + let _ = a100_dot(&a, &b, 0.0, Some(&mut steps)); + census.push(steps); + k_used = k; + } + assert!(census.len() >= 10, "need several large-k vectors"); + let r = evaluate(&census, k_used); + assert!(r.f_bp >= MIN_FBP, "f_bp {} below {MIN_FBP}", r.f_bp); + assert!(r.rho >= MIN_RHO, "rho {} below {MIN_RHO}", r.rho); + assert!(r.accept); + } +} diff --git a/zk-pow/src/api/fp16/quantization.rs b/zk-pow/src/api/fp16/quantization.rs new file mode 100644 index 000000000..5c62a7bf9 --- /dev/null +++ b/zk-pow/src/api/fp16/quantization.rs @@ -0,0 +1,289 @@ +//! FP16 per-row fused noisy quantization for the A100 scheme. +//! +//! Mirrors the FP8 scheme ([`crate::api::fp8::quantization`]) with two +//! deliberate differences: +//! +//! 1. The quantization target is FP16 (ceiling `Q = 65504`) rather than FP8. +//! 2. The noised-value FMA `alpha*X + beta*(E@F)` is evaluated in **f32** and +//! rounded once to FP16, not in BF16. BF16 carries only 8 significand bits — +//! coarser than FP16 — so computing the FMA in BF16 (as the FP8 path does, +//! where the FP8 target is coarser than BF16 anyway) would throw away the +//! precision this scheme exists to keep. The per-row scales are still derived +//! in BF16 (they are scalars; see the FP8 rationale) and applied in f32. +//! +//! The scale derivation is unchanged: pick `alpha`, `beta` so each row's noised +//! value fits `[-Q, Q]` without saturation and the noise carries relative +//! Euclidean weight `delta`. With the noise `E@F` built on the A100 FP16 +//! datapath and its lines renormalized to `NOISE_TARGET_NORM`, +//! `alpha = Q / (linf + delta*sqrt(r) * l2)`, +//! `beta = alpha * l2 * (delta*sqrt(r) / NOISE_TARGET_NORM^2)`. + +use anyhow::{Context, Result}; + +use super::accumulate::a100_matmul; +use super::dtype::{f32_to_fp16, fp16_to_f32}; +use crate::api::fp8::compute::{bf16_div, bf16_fma, bf16_max, bf16_mul}; +use crate::api::fp8::dtype::{bf16_to_f32, f32_to_bf16}; +use crate::api::fp8::prequant::round_l2_to_grid; +use crate::api::fp8::quantization::NOISE_TARGET_NORM; + +/// Largest finite FP16 magnitude (the quant grid ceiling). +pub const MAX_FP16: f32 = 65504.0; +/// Per-row relative noise weight `delta` for the A100 scheme. +pub const DELTA: f64 = 0.5; +/// Norm floor applied to `l2`/`linf` before scale derivation (`2^-32`, exact in +/// BF16); guards the division and keeps `beta > 0` on a (near-)zero row. +pub const NORM_FLOOR: f32 = 1.0 / 4_294_967_296.0; + +/// One side's rebuilt FP16 operand plus the per-row scales (reused by the +/// jackpot policy and by noise peeling). +pub struct BuiltRows16 { + /// `rows x k` FP16 values (bit patterns), row-major. + pub noised_part: Vec, + /// Per-row `alpha` (BF16): scale on the clean operand. + pub alpha: Vec, + /// Per-row `beta` (BF16): scale on the `E@F` noise. + pub beta: Vec, + /// Per-row `l2` (BF16): the floored, grid-rounded rms the scales derive from. + pub l2: Vec, +} + +/// `delta * sqrt(r)` as BF16. +fn delta_r_bf16(r: usize) -> Result { + f32_to_bf16((DELTA * (r as f64).sqrt()) as f32) +} + +/// `delta * sqrt(r) / NOISE_TARGET_NORM^2` as BF16. +fn delta_over_std_bf16(r: usize) -> Result { + f32_to_bf16((DELTA * (r as f64).sqrt() / (NOISE_TARGET_NORM * NOISE_TARGET_NORM)) as f32) +} + +/// Per-row `(l2, linf)` from an FP16 operand row (decoded exactly to f32): +/// `l2 = grid4(rms(X))`, `linf = ||X||_inf`. +pub fn row_norms(row: &[u16]) -> Result<(u16, u16)> { + let k = row.len(); + anyhow::ensure!(k > 0, "row must be non-empty"); + let sumsq: f32 = row + .iter() + .map(|&x| { + let v = fp16_to_f32(x); + v * v + }) + .sum(); + anyhow::ensure!(sumsq.is_finite(), "row sum of squares overflows f32"); + let l2 = round_l2_to_grid(f32_to_bf16((sumsq / k as f32).sqrt())?); + let abs_max = row.iter().map(|&x| fp16_to_f32(x).abs()).fold(0.0f32, f32::max); + let linf = f32_to_bf16(abs_max)?; + Ok((l2, linf)) +} + +/// Derive `(alpha, beta)` (BF16) from the floored norms, exactly as the FP8 +/// scheme but with the FP16 ceiling. +pub fn derive_row_scales(l2: u16, linf: u16, r: usize) -> Result<(u16, u16)> { + let max_fp16 = f32_to_bf16(MAX_FP16)?; + let delta_r = delta_r_bf16(r)?; + let delta_over_std = delta_over_std_bf16(r)?; + let noised_bound = bf16_fma(delta_r, l2, linf).context("noised bound")?; + let alpha = bf16_div(max_fp16, noised_bound).context("alpha scale")?; + let beta = bf16_mul(bf16_mul(alpha, l2)?, delta_over_std).context("beta scale")?; + Ok((alpha, beta)) +} + +/// Fused per-row noisy quantization of an FP16 operand. +/// +/// `rows` is `num_rows x k` FP16 bit patterns; `e` is `num_rows x r` and `f` is +/// `k x r` FP16 noise lines (so `N = E @ F^T` is `num_rows x k`), both computed +/// on the A100 datapath; `norms` is the per-row `(l2, linf)` from [`row_norms`]. +/// Returns the noised FP16 operand and the scales. The FMA runs in f32. +pub fn noisy_quantize( + rows: &[u16], + e: &[u16], + f: &[u16], + norms: &[(u16, u16)], + r: usize, +) -> Result { + let num_rows = norms.len(); + anyhow::ensure!(num_rows > 0 && rows.len() % num_rows == 0, "rows must be num_rows x k"); + let k = rows.len() / num_rows; + anyhow::ensure!(e.len() == num_rows * r && f.len() == k * r, "noise shape mismatch"); + + // N = E @ F^T on the committed A100 FP16 datapath (bit-exact). + let noise = a100_matmul(e, f, None, num_rows, k, r); + + let floor = f32_to_bf16(NORM_FLOOR)?; + let mut noised_part = Vec::with_capacity(num_rows * k); + let mut alphas = Vec::with_capacity(num_rows); + let mut betas = Vec::with_capacity(num_rows); + let mut l2s = Vec::with_capacity(num_rows); + for i in 0..num_rows { + let l2 = bf16_max(norms[i].0, floor); + let linf = bf16_max(norms[i].1, floor); + let (alpha, beta) = derive_row_scales(l2, linf, r).with_context(|| format!("row {i}"))?; + let af = bf16_to_f32(alpha); + let bf = bf16_to_f32(beta); + for j in 0..k { + // Single-rounding FMA in f32, then round once to FP16. + let noised = af.mul_add(fp16_to_f32(rows[i * k + j]), bf * noise[i * k + j]); + let clamped = noised.clamp(-MAX_FP16, MAX_FP16); + noised_part.push(f32_to_fp16(clamped).context("FP16 cast")?); + } + alphas.push(alpha); + betas.push(beta); + l2s.push(l2); + } + Ok(BuiltRows16 { noised_part, alpha: alphas, beta: betas, l2: l2s }) +} + +#[cfg(test)] +mod tests { + use super::*; + + const R: usize = 32; + + #[test] + fn unit_row_alpha_matches_formula() { + // For l2 = linf = 1, alpha = Q / (1 + delta*sqrt(r)). + let one = f32_to_bf16(1.0).unwrap(); + let (alpha, _beta) = derive_row_scales(one, one, R).unwrap(); + let delta_r = bf16_to_f32(delta_r_bf16(R).unwrap()); + let expect = bf16_div(f32_to_bf16(MAX_FP16).unwrap(), f32_to_bf16(1.0 + delta_r).unwrap()).unwrap(); + assert_eq!(alpha, expect); + } + + #[test] + fn output_is_valid_fp16_in_range() { + let k = 64; + let rows: Vec = (0..k).map(|j| f32_to_fp16((j as f32 - 32.0) * 0.1).unwrap()).collect(); + let e: Vec = (0..R).map(|t| f32_to_fp16(((t % 5) as f32 - 2.0) * 16.0).unwrap()).collect(); + let f: Vec = (0..k * R).map(|t| f32_to_fp16(((t % 7) as f32 - 3.0) * 16.0).unwrap()).collect(); + let norms = [row_norms(&rows).unwrap()]; + let built = noisy_quantize(&rows, &e, &f, &norms, R).unwrap(); + assert_eq!(built.noised_part.len(), k); + for &b in &built.noised_part { + let v = fp16_to_f32(b); + assert!(v.is_finite() && v.abs() <= MAX_FP16, "out-of-range {v}"); + } + } + + #[test] + fn zero_noise_dequantizes_to_fp16_accuracy() { + // With zero noise, A' = RNE_fp16(alpha * A); dividing alpha back out + // recovers A to FP16 rounding accuracy (not the coarser BF16 the FP8 + // path would give). + let k = 48; + let rows: Vec = (0..k).map(|j| f32_to_fp16(1.0 + (j as f32) * 0.03).unwrap()).collect(); + let e = vec![0u16; R]; + let f = vec![0u16; k * R]; + let norms = [row_norms(&rows).unwrap()]; + let built = noisy_quantize(&rows, &e, &f, &norms, R).unwrap(); + let af = bf16_to_f32(built.alpha[0]); + let mut max_rel = 0f32; + for j in 0..k { + let orig = fp16_to_f32(rows[j]); + let recovered = fp16_to_f32(built.noised_part[j]) / af; + let rel = (recovered - orig).abs() / orig.abs(); + max_rel = max_rel.max(rel); + } + // FP16 has 10 mantissa bits; one rounding plus the scale ulp stays below 2^-9. + assert!(max_rel < 2f32.powi(-9), "max relative error {max_rel} exceeds FP16 accuracy"); + } + + /// Dumps `noisy_quantize` oracle vectors (inputs, pre-floor norms, scales, + /// final codes) for the sm_80 miner-kernel bit-exactness harness. Writes to + /// `$FP16_NQ_DUMP` (default `/tmp/fp16_noisy_quant_vectors.txt`). Run with: + /// `cargo test --lib api::fp16::quantization::tests::dump_noisy_quant_vectors -- --ignored --nocapture`. + #[test] + #[ignore] + fn dump_noisy_quant_vectors() { + use std::fmt::Write as _; + + // Deterministic xorshift64* -> fp16 at a magnitude scale, with ~10% zeros. + fn rng(state: &mut u64) -> f32 { + *state ^= *state << 13; + *state ^= *state >> 7; + *state ^= *state << 17; + // uniform in [-1, 1) + ((*state >> 11) as f32 / (1u64 << 53) as f32) * 2.0 - 1.0 + } + fn gen_fp16(state: &mut u64, n: usize, scale: f32) -> Vec { + (0..n) + .map(|_| { + let z = rng(state); + let v = if rng(state) < -0.8 { 0.0 } else { z * scale }; + f32_to_fp16(v).unwrap() + }) + .collect() + } + + // (num_rows, k, r, scale): gemm-friendly (num_rows%16, k%8, r%16) so the + // whole pipeline (incl. the E@F^T noise) runs on the sm_80 kernels. + let cases = [ + (16usize, 8usize, 16usize, 0.25f32), + (16, 16, 16, 2.0), + (32, 8, 32, 8.0), + (16, 64, 16, 1.0), + (32, 24, 48, 4.0), + (48, 40, 16, 16.0), + ]; + let mut state = 0x9E3779B97F4A7C15u64; + let mut out = String::new(); + for (ci, &(num_rows, k, r, scale)) in cases.iter().enumerate() { + state = state.wrapping_mul(6364136223846793005).wrapping_add(ci as u64 + 1); + let rows = gen_fp16(&mut state, num_rows * k, scale); + let e = gen_fp16(&mut state, num_rows * r, scale); + let f = gen_fp16(&mut state, k * r, scale); + let norms: Vec<(u16, u16)> = + rows.chunks_exact(k).map(|row| row_norms(row).unwrap()).collect(); + let built = noisy_quantize(&rows, &e, &f, &norms, r).unwrap(); + + writeln!(out, "CASE {num_rows} {k} {r}").unwrap(); + let line = |v: &[u16]| v.iter().map(|x| x.to_string()).collect::>().join(" "); + writeln!(out, "rows {}", line(&rows)).unwrap(); + writeln!(out, "e {}", line(&e)).unwrap(); + writeln!(out, "f {}", line(&f)).unwrap(); + let l2raw: Vec = norms.iter().map(|x| x.0).collect(); + let linfraw: Vec = norms.iter().map(|x| x.1).collect(); + writeln!(out, "l2raw {}", line(&l2raw)).unwrap(); + writeln!(out, "linfraw {}", line(&linfraw)).unwrap(); + writeln!(out, "alpha {}", line(&built.alpha)).unwrap(); + writeln!(out, "beta {}", line(&built.beta)).unwrap(); + writeln!(out, "l2 {}", line(&built.l2)).unwrap(); + writeln!(out, "noised {}", line(&built.noised_part)).unwrap(); + } + let path = std::env::var("FP16_NQ_DUMP") + .unwrap_or_else(|_| "/tmp/fp16_noisy_quant_vectors.txt".to_string()); + std::fs::write(&path, out).unwrap(); + eprintln!("wrote noisy-quant vectors to {path}"); + } + + #[test] + fn noise_carries_relative_weight_near_delta() { + // Build normalized FP16 noise lines; the per-row rms of beta*N should be + // ~delta times the rms of alpha*X. Checked within a factor of 2 (the + // scale derivation targets delta = 0.5). + let k = 256; + let rows: Vec = (0..k).map(|j| f32_to_fp16(((j * 37 % 97) as f32 - 48.0) * 0.5).unwrap()).collect(); + // Noise lines: random +-scale signs so E@F entries cancel randomly, giving + // rms ~ NOISE_TARGET_NORM^2 / sqrt(r) as the scale derivation assumes. + // A small xorshift keeps the test deterministic. + let scale = (NOISE_TARGET_NORM as f32) / (R as f32).sqrt(); + let mut state = 0x2545F491_4F6CDD1Du64; + let mut sign = || { + state ^= state << 13; + state ^= state >> 7; + state ^= state << 17; + if state & 1 == 0 { scale } else { -scale } + }; + let e: Vec = (0..R).map(|_| f32_to_fp16(sign()).unwrap()).collect(); + let f: Vec = (0..k * R).map(|_| f32_to_fp16(sign()).unwrap()).collect(); + let norms = [row_norms(&rows).unwrap()]; + let built = noisy_quantize(&rows, &e, &f, &norms, R).unwrap(); + let af = bf16_to_f32(built.alpha[0]); + let noise = a100_matmul(&e, &f, None, 1, k, R); + let bf = bf16_to_f32(built.beta[0]); + let sig_rms = (rows.iter().map(|&x| (af * fp16_to_f32(x)).powi(2)).sum::() / k as f32).sqrt(); + let noise_rms = (noise.iter().map(|&n| (bf * n).powi(2)).sum::() / k as f32).sqrt(); + let ratio = noise_rms / sig_rms; + assert!((0.2..1.2).contains(&ratio), "noise/signal rms ratio {ratio} not near delta=0.5"); + } +} diff --git a/zk-pow/src/api/fp16/testdata/a100_dot_vectors.txt b/zk-pow/src/api/fp16/testdata/a100_dot_vectors.txt new file mode 100644 index 000000000..66aa11dd9 --- /dev/null +++ b/zk-pow/src/api/fp16/testdata/a100_dot_vectors.txt @@ -0,0 +1,240 @@ +# A100 FP16 dot-product reference vectors (from GPU-validated emu3.py). +# format: k a_bits[k] b_bits[k] c_bits(u32 f32) d_bits(u32 f32) +64 44675 44372 13474 13024 12642 51287 13980 21449 0 17744 50396 16522 48049 17396 53526 21040 10843 32852 44357 50106 52744 18024 12258 19941 20569 18067 19556 15606 14077 17667 50295 49645 53447 563 48500 46078 14886 21172 43551 13030 15371 19714 15969 44910 13418 33354 43959 19489 44746 51253 10525 11356 10742 53547 45789 319 50802 51951 47805 50376 43976 0 15455 44886 49322 13108 53890 12126 17035 44915 44626 18869 15219 44393 50249 0 21495 15875 49705 16002 15110 16689 17532 386 48217 19349 45165 888 48137 46667 47602 50883 44207 11274 15471 15057 48696 43544 20695 13550 21447 13076 0 44310 48315 51956 21112 0 47099 0 19855 52744 48524 13675 47479 47588 48367 19835 21286 0 14265 193 19124 11975 48313 45275 48982 0 3223044287 3288897865 +16 46394 32771 58493 0 24252 332 0 8925 53099 21252 38696 47613 23908 13349 0 16675 44598 47816 6697 19129 53755 16215 5331 40261 43780 45731 9427 47980 38358 13435 51539 22325 0 3332301647 +48 22305 47119 21018 9853 9072 11403 22460 56425 52538 39422 15722 23647 16979 19515 24462 39109 53014 48657 44614 24021 49747 12915 24891 10517 23337 43519 0 47152 19803 57412 44208 0 43639 26439 55867 58872 11650 48292 15853 41956 42062 50485 45928 42212 53518 11369 53562 26330 40774 42644 0 20793 41201 54505 0 56274 0 33258 43941 0 54223 42421 54451 55331 41196 5305 20578 22031 45658 43588 49831 10934 11412 0 23373 6454 52417 669 13272 8795 21096 51747 9554 42088 44801 6369 17236 23279 54571 18401 42634 13066 22729 17874 9579 38756 0 1192664905 +16 44170 45625 56057 12384 57068 21322 53522 6461 13844 25817 8363 21961 55099 22659 38951 9983 0 50585 678 40717 12569 12945 0 45094 20293 48300 41325 0 5756 23270 21662 57974 0 1189945302 +48 10574 12086 19474 14364 19545 51921 52135 16996 13934 14057 17436 15475 13176 46618 52489 53117 21262 13631 44196 18720 33192 13056 52586 46047 14902 15681 48586 16698 45996 13996 52512 53182 12110 47665 48781 12158 10271 51442 16121 18290 18882 46064 48197 54076 50096 49578 10492 50601 52559 0 18609 43523 50438 19461 13695 20673 50010 954 53061 49769 46402 44708 51484 18706 53274 54149 45750 49184 44000 51900 11360 53608 46603 12475 47939 44272 0 17470 20518 52909 20606 47266 48777 47488 53935 20349 19192 51010 50909 13204 20098 47165 45282 17045 51448 49885 1057879810 3306487627 +48 0 14436 3312 52960 38462 12931 30664 36595 0 34204 56573 40489 39169 63102 2527 42518 40619 11534 42670 64329 4952 31635 41719 33294 20760 5919 37283 16493 0 46979 42526 48039 38297 22233 29759 47313 26835 20438 57435 8680 0 53217 35049 48826 21441 9474 28000 10180 9195 12818 2027 13031 5693 27996 22016 22113 22943 43131 61908 11304 57056 63306 164 0 3003 0 704 4896 33211 52317 34383 53045 3731 7589 60111 0 35527 39820 18038 41969 30784 1871 9485 0 14652 26688 48922 34109 49874 7746 12360 44967 39392 61288 18450 13438 3241180424 1312731660 +64 41253 15827 57444 44938 34046 27121 35301 33315 3632 34197 40448 57223 58642 27448 2829 40420 45403 59129 9688 1268 33879 34264 27430 37270 26333 8005 24688 18529 58740 42838 471 53243 0 1401 61647 6224 30748 55524 28556 18558 2910 16388 0 55337 433 42822 28287 19508 20670 47913 55775 15597 56526 10334 15872 54596 0 20421 43975 8238 23176 34261 15318 56257 34477 0 50619 54949 47141 1527 0 22352 43870 44865 18919 23721 28770 13776 38595 28984 64072 15172 54094 45226 23093 4882 47900 55816 42156 41780 20393 46496 19364 786 472 38528 53758 62680 41543 4165 46022 16165 9756 49990 59508 7224 27553 60114 58400 25945 46008 49421 18136 33537 29383 35819 0 1772 14260 25829 2449 20352 50538 14263 15103 25796 4300 22376 0 3411462779 +8 51754 53034 48324 35987 52835 5668 57251 46395 49464 55169 0 20593 30956 26841 2162 12706 0 3380256987 +8 13964 0 16626 352 15362 17133 17095 0 49208 15413 19251 13414 51991 49530 48072 16183 3146131811 1089993538 +64 15619 47494 16941 0 45757 15650 48818 19251 17006 12373 15917 13468 49089 16328 46291 51424 14349 50647 33379 14733 51354 14837 16000 16435 46795 51951 48501 0 15354 17630 48102 0 46460 49939 46982 50659 48389 19004 15291 48344 33102 48379 18029 16771 13383 13186 51244 45498 49394 51129 13940 49601 12774 17431 46830 14944 16577 47901 18305 16357 196 14749 49325 15241 16383 45063 14128 47926 48704 17768 12570 48672 14384 14094 12639 0 12714 14718 16371 14230 18019 33443 48215 15496 51174 33620 49705 12750 15152 15436 47550 48617 15611 47979 51401 48840 0 47498 17731 14191 13292 13195 12843 15569 49345 47734 13520 46856 48906 51247 45353 48772 15406 52134 47850 16272 0 0 47682 17170 14747 0 14403 0 50822 13987 45064 48589 3205023372 1126659504 +8 47367 4367 35571 63840 26223 16296 51459 6221 3864 62423 43425 0 14289 30820 50437 0 1010965861 1200102657 +48 0 17157 51206 45765 18181 0 45237 49442 47404 49117 0 32835 51681 14203 46596 33060 0 50269 52166 14301 45400 45787 14242 0 13769 45641 0 50921 0 19092 51484 14958 48824 47815 15438 51716 14514 959 0 49488 17348 13430 17307 13604 0 49659 14772 18321 416 50505 47852 49288 18411 47955 48265 15098 50110 50103 45660 52130 13890 12648 47084 0 47544 51377 49913 0 46979 13166 48720 12650 0 13089 0 14629 15486 49583 45875 18982 46840 15845 46668 46084 32878 46891 47634 16346 18922 49994 0 48163 13242 18592 45486 12301 1043384114 1124029595 +48 15616 54577 970 0 47089 11394 56470 30035 42374 13103 16585 61245 62593 54674 1743 63086 51658 61875 24373 18564 41681 53487 56580 46280 6806 36785 24852 20593 60495 45814 63040 25223 12332 38638 28244 14602 60934 20366 2110 58038 48879 35949 26307 58928 3326 872 53858 0 9286 6033 40213 3800 17349 25648 6276 44896 33859 33610 22609 42320 11964 43909 33705 44886 21303 37215 39450 33272 690 0 46234 61769 50995 22367 9167 0 14043 10084 11042 3461 102 21296 41925 47280 7770 0 6787 0 35749 6629 53008 23751 43810 55791 6035 24992 3172959885 3372389585 +8 46482 59480 3941 37785 10991 42801 29327 29855 26797 17862 0 8647 46455 94 58266 13887 3180335202 3410461860 +8 14984 18952 837 43550 50176 44495 19130 10240 51183 44124 44396 0 17403 48472 14513 45739 3147289820 3245615616 +64 46385 16571 46380 14734 48828 15038 0 48738 49319 0 48814 52189 0 222 47706 50187 17033 18310 13178 48364 17836 0 12743 46388 48975 16647 15216 47295 14830 52072 50496 12599 19300 46092 18527 17771 51353 52160 50936 242 14531 48825 0 17150 15167 0 46481 0 50262 14158 19430 13796 13593 15475 46106 45204 45874 284 14582 46409 19240 14114 45333 13045 47030 45707 13476 14636 49238 47818 14740 46486 48935 14798 51653 0 17093 47090 16245 51917 47414 47308 47731 14554 17649 14744 16273 13984 15279 19172 16903 14721 19090 48893 18627 47931 47306 50394 13690 48894 49301 15106 49435 48262 51021 51324 18189 15663 51425 50965 12810 0 18270 14474 12952 14777 14817 47727 51433 33719 17484 33096 14357 18408 606 49624 15532 51624 3217016424 1120978784 +64 4187 28405 55969 15855 26653 0 27936 41341 49131 54498 63983 33161 38677 27888 34637 57289 17140 27639 0 61739 2623 38053 1636 28872 24633 20125 1949 5086 896 55783 22364 4411 50123 43343 54892 0 39031 15073 12374 54944 30605 0 0 1555 59914 17062 26791 22460 57148 41710 24573 13246 63143 8499 52211 37035 54680 20322 49838 56589 15924 35427 14483 58226 9149 18008 28942 64080 3644 1938 63070 20862 26461 25188 15442 47294 33704 42997 29009 29164 9419 6642 11629 12042 24422 53010 50469 13516 4494 51675 30315 21137 21175 39889 0 0 9778 61987 20111 57747 13385 25611 54310 41182 56349 28458 2034 7104 45865 13722 64402 62722 47600 49085 42528 44737 0 30835 0 41871 20844 23726 21897 60699 41763 12112 10321 24365 0 3448779343 +8 52993 16600 18145 16071 44550 49667 16030 0 44848 48102 52993 20334 48660 52207 48950 48557 3198730821 3267504698 +24 45786 25897 57889 49724 58943 39729 40939 19961 20419 7224 55928 14260 48360 11575 56096 18214 0 8930 8233 46967 40489 24135 8727 54871 0 39252 47228 8644 7439 49187 629 47554 14482 17019 6944 0 21901 32857 47288 7126 53875 138 20682 56681 41106 49527 48825 55863 3202691791 1184486818 +32 48558 40347 13938 53654 51807 0 40283 26087 40178 14571 17660 0 974 8054 9430 0 0 33704 47457 47641 57336 57437 51189 51442 0 20178 6435 19123 42687 50931 7603 24286 7780 33520 22457 40053 54904 26576 42343 23019 10101 44157 33134 6092 23384 7109 10706 13269 0 0 9158 12111 5942 40757 19423 23039 46713 49728 41429 0 6596 26456 19492 51494 3154846490 1216529763 +48 14190 33555 46194 0 51018 46789 51441 0 14564 13478 13024 50325 51028 0 15857 45271 46189 751 51006 17337 17210 16345 50640 45715 0 45548 0 47295 12374 16608 16352 15051 50956 50367 0 49440 49460 12987 46109 51984 51475 48921 50332 51110 12769 49875 19161 14752 32973 13200 33209 46151 18302 0 51967 16330 12984 50470 46075 17401 12632 18601 47579 52024 14767 51674 47565 47435 12577 19092 12713 47685 47641 13936 0 47717 47146 52210 18739 45194 13195 827 48027 18977 50290 49341 0 0 14422 47054 47958 4 0 17563 48374 51079 3158097051 1096191970 +8 6818 54705 44845 62630 24866 34876 33944 9807 2176 59135 14693 36801 27798 28043 23685 548 0 1246118869 +32 45122 15248 18660 16270 16277 13005 17194 48959 45275 51564 15070 45688 49549 13582 48111 13950 15549 15444 14062 48482 18040 51880 13162 15115 13703 50223 14955 46677 49865 50351 233 49841 18433 15090 0 46519 50184 15929 51838 19008 50505 52169 16826 51408 50749 49572 45326 17745 15882 13348 45826 48238 48361 18171 50824 50356 49468 14305 47668 0 15634 442 50583 49737 0 1097824762 +24 15151 16514 51822 57309 21765 19390 9076 18914 19630 22181 41217 37934 25206 56629 10135 5195 50507 43682 33226 40771 59113 5229 25807 48175 33691 52462 46226 9268 48417 7529 33379 46497 6080 33718 52785 44631 47858 57096 56291 24773 39017 23617 13258 47399 43722 48408 48921 51378 3278988623 1208962671 +32 54832 57710 25885 50342 39519 12042 263 57258 49460 15174 24925 22099 50951 6327 20947 15052 51 5821 54759 43761 509 57670 16050 53377 15573 7804 10657 17990 5865 25057 18886 0 19629 33005 52947 22809 51510 48638 10722 45958 11842 22961 5794 17124 54752 45 25147 41169 50807 42863 25240 20081 47330 7065 48595 22761 22151 53663 10035 42844 18802 14833 19522 51053 3246536604 3349469209 +64 29202 0 12844 0 52539 0 61766 35898 33265 1728 0 39933 33075 52088 6567 53771 52302 47271 593 15620 1854 53151 37718 12454 29772 0 21648 36604 52343 24310 60837 59655 4578 59129 4461 482 32856 31323 19698 27947 7762 17352 7878 13465 58401 47519 31546 40882 33440 27725 0 25498 0 49622 49234 52821 16162 26936 52261 28880 54960 55346 46291 60154 56498 2802 31283 13272 50704 12893 28752 44019 0 0 18119 63147 0 699 8376 31445 50217 3800 21871 28919 45483 4464 16989 52904 2252 16914 52597 38086 0 42589 40127 15719 1522 7922 43736 6308 44334 57092 16356 48618 55244 64407 47509 28091 62844 20326 0 25669 16303 25136 37481 35572 16352 5180 62332 45975 5075 41316 35084 0 59037 4466 25637 10484 1096898659 3434800550 +8 55559 11956 41677 16920 42028 18487 27991 39585 0 53901 56831 37181 10663 0 16390 33071 1069385013 1177281705 +64 0 13262 53991 57886 17091 43924 42080 42414 15557 41475 49578 53493 56337 16860 49656 17675 46806 51568 40015 40602 46787 15411 9219 6985 48379 49196 19118 20258 19027 15711 7895 33280 25958 16365 47086 26546 340 13744 13681 16794 12659 23554 0 0 49433 45929 32885 42980 12686 17434 52351 8296 26584 9536 52002 7817 42336 0 56224 16649 37888 12615 41488 39334 5681 25866 25943 54755 13960 49224 5247 17327 19985 17425 41646 16601 21901 14873 43808 50438 0 9304 47419 0 5216 58715 48539 43570 50280 57037 18161 0 16270 55742 22436 51201 686 49150 0 0 25446 24194 41064 10018 24753 15054 21874 56391 40071 0 58693 6590 45443 51216 42489 14514 5893 39154 42685 18729 9635 0 25925 7432 46701 57075 47776 16504 1064825667 3366773467 +16 56613 32776 46017 35295 16495 23171 20593 9865 21773 26807 6711 28552 17359 24038 44356 25181 36094 31720 45203 47112 36073 59214 22129 63345 46877 5298 42868 33638 17203 60359 31120 33113 0 3387370423 +32 26111 12406 42952 23822 42451 26212 59212 42690 5107 30839 48073 58277 56403 16573 48200 7821 51272 37856 44284 43668 0 6667 33595 45655 14637 23118 22932 36780 59910 27111 29943 14237 26840 34584 16612 53048 771 16995 11645 640 46513 36548 33248 42502 46411 60747 431 35468 34472 13322 54240 22554 44876 49263 0 15974 18458 37669 5625 430 34391 4470 30640 52120 1096641392 1310298767 +64 58395 244 32856 52982 38055 7501 44112 33029 42110 22977 59875 0 33300 33964 38982 30357 25629 35506 0 18365 43793 23839 31675 26426 3820 9404 48979 0 49080 5255 19199 64297 35326 27084 13483 27529 11268 26443 428 16578 38905 21655 0 20179 38142 48480 0 41932 0 0 564 63315 34590 17546 4889 0 50181 55715 23569 33691 50725 7651 55339 0 33383 49581 58756 27847 33018 42513 27284 7662 20600 54277 35346 57613 50052 63353 60909 54171 50620 20569 17108 9588 21540 26294 41371 56759 22799 59245 22823 59852 24191 9940 2886 39509 34303 672 56334 21746 5108 23026 49464 55835 15492 21970 0 0 34756 55563 64045 51409 22895 12133 56078 33393 58029 34260 46849 20226 22776 31475 30620 3307 0 62719 49638 51373 3274077391 3394210371 +8 18059 24037 8864 48512 16897 9219 39245 50922 53546 51569 40224 22312 12870 55451 40804 45884 3213427933 3314398235 +24 0 13013 46418 16409 17824 51649 13710 48581 50632 0 33127 45456 0 16904 12703 15542 45761 45340 17532 50572 0 50504 18791 17164 49332 50445 18334 48148 50597 18155 18923 49191 15371 12587 12658 14706 0 13671 46570 14542 50088 46112 48349 19159 49777 51579 13398 51277 1037444132 3273924817 +32 0 0 942 11811 46704 45451 47828 51681 43425 46727 50460 21133 11468 0 17485 19007 43489 50626 0 45742 0 52656 14266 43118 17030 52291 12516 12501 20671 15376 18526 19310 51269 48418 50247 51102 12410 51773 0 33035 0 267 44214 0 14889 20168 48302 10660 51298 50059 18571 11673 15923 0 44158 44827 0 20186 12052 48919 21376 46859 12590 0 1045175191 1155852257 +48 45852 0 39854 17003 38609 6834 20964 53766 13547 0 44792 23046 52946 42578 19153 18768 43110 21680 49867 380 40439 52934 43299 43006 17749 17812 41726 55975 46746 48280 58849 9942 21335 54453 11312 26031 42774 0 47189 50452 22401 24489 58270 43945 26061 38699 0 56245 50472 46427 14603 7874 15100 19597 53201 16731 38558 40256 57610 6171 43869 40600 14409 54947 32866 42516 18477 0 21953 6481 43111 0 14533 48531 51089 25771 13900 58222 18966 33193 13844 38321 20441 15756 52796 58598 24640 17876 5760 0 24891 47224 55323 8339 8711 54432 3267633530 3381038662 +64 48987 0 47210 0 50642 0 15799 47360 14395 45523 48275 17887 16558 15575 46698 338 15035 18572 17588 45215 46314 17425 47205 45836 46788 17935 49684 50478 47821 0 47399 45940 48483 50101 52193 14766 51839 15832 19236 16412 13748 18520 48888 13048 46764 14743 50802 47469 16204 49656 17693 48870 16060 16229 0 48480 48616 16036 51035 15556 13385 12747 15464 32873 48241 15652 32871 14606 46855 12589 49107 19438 48410 597 13783 46530 51794 14244 52214 46690 150 0 48087 52181 16881 49430 17290 18531 17440 15455 14459 48834 51190 47672 19188 50182 48068 16399 51357 50405 48229 33313 16759 32879 19404 87 19429 51529 15256 14981 15476 19050 50222 0 13860 13800 48633 14975 51911 19342 49685 15132 13636 14693 14548 13659 13398 18800 0 1118455822 +24 46408 17850 14550 47721 48838 50920 14787 45328 13196 32858 17978 16169 12313 0 14524 45801 16147 16923 14413 50060 15443 12935 14921 18877 18386 15784 15703 14123 14459 49860 17718 15088 33070 18432 14677 47635 12981 15226 47961 0 14551 381 0 766 51759 47622 46741 12411 0 1102629498 +32 0 23242 62891 27675 48547 34351 29606 12248 4294 60029 9406 21308 26794 25907 15542 4450 51627 0 26192 57420 0 24511 19592 29082 17957 7561 24473 34258 64343 49768 62574 38983 3357 0 9223 46960 48850 59206 49988 24246 0 22016 38804 23508 20925 20000 36517 41777 33139 15947 36593 26026 37750 0 21848 44298 48095 2674 50112 30871 61929 27733 15784 0 1010924013 1311589386 +32 18025 9264 53803 46907 39546 0 38125 54886 42101 16897 23880 0 52374 15078 41562 24797 37943 33591 46863 10715 42148 20882 33069 55575 16205 5998 0 32909 32902 13094 13505 18917 51449 42615 0 46770 53714 26331 44341 17464 20277 24623 8933 23116 55923 41473 47682 415 38523 13008 12167 9550 38316 33667 15106 58963 33541 20101 57222 26173 25101 13632 0 47349 0 1216554412 +32 53493 53640 49484 16802 17631 11804 0 0 46772 13668 13539 49243 14909 49403 46531 44013 52751 54139 45096 48799 47225 16784 44255 16604 44353 33526 44830 46134 33011 13475 52898 0 51460 47301 0 51373 54037 0 48302 11379 12935 20797 15792 47843 15388 0 46550 0 49345 13011 50476 49901 49927 43534 44075 51817 12305 49421 16383 19555 11462 53005 18083 44954 3274400216 3276237048 +16 50423 19325 0 0 19391 46576 0 48268 45329 32898 17031 51571 14765 0 18899 51044 47890 50779 45162 18128 17745 16508 15143 18641 12876 14089 13978 18871 49621 17805 18378 0 1024939423 3260747897 +32 13056 19380 45829 48848 14107 12353 0 49526 17990 47371 12512 46620 15692 14745 33332 15829 14349 17516 50483 51508 51951 17601 46068 47342 13469 50042 47510 48054 14123 14467 17831 33529 18916 49025 18552 47536 19316 15744 0 12580 15456 13903 14075 12467 17785 46774 12943 51053 47709 16998 45439 46575 46111 15163 17479 16372 12775 50765 49744 335 49961 48836 49802 13743 1100885716 1106594401 +48 50652 46975 12791 0 18991 48857 50138 13994 12353 0 13491 15653 49008 47563 0 13125 49637 45817 17858 17725 14679 50030 51915 17906 13307 0 934 15705 12873 45412 46863 50573 16141 15880 15060 14037 13374 17620 50529 45979 48863 51982 46329 45346 50261 48804 17316 51494 18806 46419 46928 45847 14898 49360 13287 49270 48222 17832 47344 19322 16136 19123 0 39 12634 45434 14530 19111 14916 50398 15885 17969 46801 16409 49662 46596 46667 13389 45529 51803 50675 0 18163 50936 17094 50680 49687 46968 50920 50903 18566 48777 48343 46677 48014 50081 0 1132582118 +8 51617 15005 17649 2068 17356 0 60087 31689 57584 0 7815 0 33120 57339 60204 46158 0 1262516884 +64 0 50070 48926 57441 35405 35631 22570 0 53392 0 17820 61820 36060 57597 42780 28988 13127 24652 50698 26976 14745 61585 19762 14487 0 36471 58082 15251 42592 53390 7944 54688 41339 26060 15260 12920 48196 35115 44656 27119 8018 49497 41653 18826 44395 44623 0 17613 33141 27073 42038 47183 56485 4558 7088 39857 0 4181 0 26431 25045 24894 9591 52485 17474 45691 11375 54366 53896 6876 20688 49241 36692 14403 30183 35863 17399 3156 63402 55885 23994 0 62644 25466 44153 45383 43938 0 56868 32827 19817 411 33145 2783 0 39511 5785 28162 36168 57068 12427 2020 17345 556 46133 26706 48893 41796 8787 2111 48694 4610 46873 53225 24839 27643 48979 19553 14270 16045 0 30986 19156 45743 39118 16857 17438 51011 0 1259684937 +32 14159 21442 11357 0 10827 11732 0 51151 261 46297 47630 51750 52914 13027 50564 16953 17607 21412 48403 13965 52997 44123 18166 49571 47713 44192 49009 48393 0 10398 16311 44103 48589 10568 20948 10642 17150 49301 11646 13583 45278 20798 11030 12070 21319 45466 49099 20075 12191 45888 17574 20135 12286 13290 16870 14341 45345 33780 20296 12211 14675 13968 52443 16495 1039327276 3301150814 +64 20255 24941 9538 820 14449 46928 0 13617 18405 58656 49472 7246 9132 52635 39716 58145 40043 49259 53878 47174 48831 49305 48611 23771 40858 50323 40040 15718 43833 39721 10052 13980 33416 40608 6582 22975 15344 15114 6984 52719 24952 33277 17949 13437 44783 53899 6968 13008 41264 10536 51487 42125 0 10613 53375 58375 10355 56986 0 51435 50239 21194 46439 45619 56460 17675 52984 14272 10636 49039 40599 66 38763 40865 53935 0 40645 13054 55161 10742 44760 0 10100 55059 13247 12264 52164 25689 54549 10552 23793 53682 22921 40506 47885 16922 57353 39134 12459 23262 5915 51636 0 43394 57942 8108 10392 55226 51707 33109 24263 11230 54827 15698 42406 55313 50154 55639 554 33197 50909 8393 118 0 54973 47915 20498 57972 3154587378 3358932502 +64 33238 50144 15753 13336 0 21232 13895 0 0 13448 19161 51899 51104 19418 15366 51408 11324 19898 10445 52866 48389 51438 10754 14313 13881 11580 20726 51610 0 45874 18244 13004 17303 51059 19334 48328 14769 19744 50647 17554 11504 19563 654 19584 53509 50432 20656 19393 44449 16536 19032 20979 18080 19918 45413 52897 14024 0 0 12461 49521 21472 44812 12266 52485 51339 49198 929 54265 15353 19678 19219 49836 51639 47328 18417 20525 14451 48574 51830 11303 16302 0 0 46821 50961 11141 43606 13897 16778 14382 46594 14683 33328 533 18374 14305 45988 14018 15731 32868 51010 50446 19890 20184 21486 43846 0 13458 0 21181 14084 0 833 953 47366 54126 53356 21286 16737 44571 18929 47493 15539 17490 51026 12669 47880 1058158131 1151748607 +24 0 47991 16483 23801 7037 0 39699 7023 0 22897 41332 41059 23093 38782 42786 12692 54018 33042 0 16009 11800 19340 26011 43803 9064 40722 0 12468 18296 41274 10479 22026 6370 38695 10988 50473 54760 20253 54005 15730 44820 22992 59236 20003 0 20814 20996 16939 3182718386 1195856007 +8 45967 18828 47512 52178 48778 15578 17663 15205 14892 18017 15421 51109 15514 14757 12786 51611 0 1127412470 +8 34321 39361 36407 1336 22324 28052 42214 749 23991 52527 42121 0 45170 51230 3315 35626 1088620862 3342320548 +24 47362 16219 14458 0 46280 14713 46470 552 43071 44532 0 14468 46836 43541 54191 15384 48425 52583 10586 15423 15618 49889 47494 14074 10970 20476 44569 49726 20460 19656 18304 52117 14336 15834 17047 45735 13310 21280 16988 45363 52993 52076 18027 10249 43411 21426 49076 47703 3267742643 3266778328 +48 0 19737 48194 14001 0 17175 53856 33487 0 53980 12856 13231 19888 48289 46096 43842 16237 186 48846 18564 10618 52378 49342 18151 19890 44936 12886 48609 44413 43201 53161 44615 32980 53924 44289 19815 0 12375 14374 19208 46994 11004 18933 49779 52327 11536 17244 49514 47655 45789 0 0 16110 20718 46106 17206 19640 50444 44690 0 10727 15521 13061 0 16272 47519 13098 14381 19528 19275 17151 45617 53466 0 46322 48337 50033 16007 49752 53843 0 50395 0 33201 50192 18923 18484 49271 53908 17141 53072 46470 47334 10723 18449 12598 1097907477 3290742308 +48 43636 19231 61653 31315 52812 14600 14923 199 61383 61336 1865 0 27813 62088 52864 45598 8815 30366 11270 47327 33124 2172 1138 2009 0 11019 3388 60853 29743 36267 38985 14668 55067 19959 62743 43041 23719 37817 28585 49169 46531 50480 48213 31473 46024 7892 0 5396 29809 34868 2464 15347 10947 2373 10550 21125 4973 61791 56890 50649 18544 5084 36994 50112 42034 62276 0 62709 7666 26090 0 3959 3674 53997 4234 12073 40543 53936 28218 57770 9738 27593 37550 55744 61286 26967 19368 0 23725 35154 37089 56064 18703 33960 50305 62066 3196621954 3449718211 +8 38902 5456 53091 25408 43738 5229 50582 33318 0 19676 26434 49167 39450 12026 25885 51989 1023629032 3346685239 +48 49461 10884 784 38752 15648 58828 0 6065 38348 8734 46988 0 0 44083 26440 30979 52416 0 0 44119 5015 37873 0 21256 4133 28811 19584 30014 34976 979 0 48351 14982 33707 17412 5453 0 55648 55210 0 57064 53902 36000 28133 30387 15032 38319 0 55955 0 35112 31371 18260 57857 17477 48830 61727 13976 50542 60058 45863 25486 32824 0 10786 18304 15197 11143 0 0 25626 34406 24453 381 0 44130 44059 16394 16319 22940 0 56587 60914 63751 13690 27890 55495 36889 0 62673 62219 64036 27158 63368 901 51909 1083594883 3444494479 +16 3760 29509 27551 30524 5875 9298 0 10217 11354 52533 12795 0 31618 62935 16002 17845 7014 19265 14434 0 8136 20856 15343 0 15483 12199 49555 21091 0 39118 59769 44954 1004388629 1213242916 +24 54120 47515 53888 46946 14124 52659 6787 8971 56967 37939 46492 15183 48376 19460 38444 42982 41798 25884 59163 46222 54549 52447 15662 0 21746 58075 56001 39462 42304 0 38630 10311 44847 26228 12566 44928 19608 0 0 52273 23249 0 57741 17279 21815 15480 23267 24861 3175295173 1235081266 +64 47539 12911 12459 0 50128 49499 45402 46287 12614 48175 49007 50445 17540 15767 15835 14776 15348 0 0 17792 51182 14091 14422 15098 14157 16334 50104 46464 14411 17192 45066 13917 467 17870 15767 13414 13140 46903 45085 16347 47878 0 49466 18670 49625 19172 18872 16626 49652 48607 15654 46802 0 12747 18111 16550 18720 750 51740 14827 32955 13984 51975 19215 18177 193 15132 16276 49577 50573 19284 45970 51379 51210 50773 14159 48364 0 48873 49042 17466 51986 49321 18537 13369 0 46114 17139 45217 14692 14666 12460 19116 13319 0 18935 48346 13355 0 50987 14476 48576 49765 16117 50203 33750 17885 0 49221 13033 17023 16215 12510 16579 45280 0 14371 17758 19027 46886 50156 49230 17302 50501 0 52165 13036 16776 0 1125760374 +24 17753 48114 0 33558 48814 45304 15092 15113 45191 45852 974 50381 15151 12741 49953 13755 50298 46039 51900 45458 48606 19302 45137 0 46635 18883 0 33256 16507 52064 16575 19107 48304 17050 18457 46109 0 45664 48099 17591 49118 50499 45741 47405 15815 46707 51096 49856 1083983278 1098334127 +32 15281 54955 47703 11155 0 0 55280 55785 24908 45099 58145 56341 48906 0 56264 0 0 57209 49507 52748 39471 44611 22753 54873 44976 26324 51022 48707 23423 14276 21868 49856 33152 32876 57668 16750 0 11946 912 48524 70 53606 19976 434 20266 56393 40061 6575 57371 22832 56499 0 55732 46561 20810 13762 55767 57517 46911 22636 11407 50870 38785 13064 3147057530 3381337467 +8 52115 0 10772 54138 10395 49316 12140 19788 46937 11709 19685 10886 54033 45790 0 46252 1076791040 3189865536 +16 3871 36046 6719 29676 61220 62240 31684 53876 16789 19700 383 49902 37327 34134 56199 0 12655 47724 36793 22078 52427 64355 20615 9444 54682 10838 0 51016 61816 50645 35259 30281 1089994181 1314094481 +16 63547 13036 60401 14171 55190 23405 313 50147 54998 35014 339 36985 25245 45975 0 48591 25361 15941 27478 19816 60615 33236 33693 12469 13493 0 17992 31021 16199 42211 2871 27235 1056008467 3425670389 +24 3777 18513 58542 13880 37883 40488 39830 0 22514 19810 25190 4290 11951 49119 35177 7246 27291 59397 21073 11201 27472 10264 36058 45610 45436 33907 40322 19747 32915 32959 7500 51039 52467 49209 30424 18417 53267 8666 0 50232 45649 46314 34831 18256 13248 46294 12562 48264 1061194234 1269769464 +16 52174 14794 0 33708 58711 42521 0 20898 45600 14476 12710 52191 16709 24845 0 11343 11025 23390 49614 14098 38052 17676 5698 52133 0 45039 46770 8105 13286 0 44936 0 1125426557 3283640825 +24 59210 44942 17387 0 7270 27984 23904 34621 39110 19037 49000 32794 3749 23331 55299 58994 12367 22539 6835 36361 40500 38146 9343 33298 29975 0 11770 46922 3327 39605 12708 59798 60882 8954 22771 61104 29448 55314 44166 10298 21521 4098 38404 6158 33226 16605 13405 15890 3226482771 3423896552 +16 14049 14726 47346 14809 48491 33202 0 15098 17776 0 404 15886 47506 15402 12463 15000 33590 17626 505 15714 16676 48013 492 47674 12445 12972 19217 601 46638 49883 814 46603 1034972008 3223604359 +64 10128 46592 39314 47962 58287 52950 21525 25124 8820 5526 18052 57563 20737 12197 14556 51920 0 57695 0 47794 40008 21381 25473 32833 40954 47041 42930 53361 10807 56046 18573 23319 12224 54475 0 48108 41121 50460 38699 44890 0 44823 17195 0 17959 38697 45916 43348 45911 44481 50118 55976 22942 47622 53981 7791 0 13474 26611 56693 25627 46336 40850 22406 47532 47871 54133 20861 8425 22657 41360 54299 42929 47421 58107 54225 53796 43113 8985 6828 41638 54514 42756 53813 21562 9240 26569 58829 56184 24401 40854 20353 49701 58881 51019 19598 16916 50058 25903 47754 19865 22807 53255 54210 22092 16810 45982 40717 23252 49424 10621 38761 57651 51681 12797 8979 9895 51893 46654 0 52910 58555 39416 43603 12666 11387 770 32907 3231176959 1242279798 +32 48238 24992 0 19590 23457 19386 58645 53554 56745 22716 55220 15070 39029 17877 40944 22734 38246 46941 13431 59043 57621 682 11209 15534 808 15049 41429 41713 23722 33230 40257 33580 19628 8765 56974 48989 0 10081 58913 16043 54781 42629 21643 38651 57464 50301 50320 44088 25050 17608 24896 43019 55829 13408 12573 23204 44807 8388 0 0 22394 40118 14948 53124 0 1242044030 +16 12494 15721 47751 51267 48099 12808 50555 15356 46537 33357 18648 51557 14225 13697 48130 48185 16644 14204 45381 0 45415 52217 12967 51729 15327 32919 13432 0 47221 15015 16552 45750 0 3245009788 +64 40584 39312 59227 60733 42756 2797 21502 26450 35421 60521 16437 8160 23683 0 8636 22360 64198 51364 55536 6884 27701 48521 57702 0 17445 56413 7687 53591 12445 14207 46595 62525 57037 57343 42025 47343 50126 50359 13224 55484 0 44942 12783 3844 31538 50228 64059 46266 41932 0 54651 23745 64319 0 15603 9417 59159 43987 0 9246 7270 63278 64307 49237 40479 16731 34425 28567 27448 34564 58694 0 34190 56864 9798 33394 51826 26072 40836 28570 8370 61266 45844 13064 33223 7792 10847 8759 0 0 0 0 26008 5106 17164 45451 25962 56862 36418 36510 52799 1597 61067 57072 48966 27518 50308 33743 8242 48062 25339 1073 11996 48797 15898 1541 53995 60535 43997 43638 48747 10004 23772 20437 22103 43420 27591 55898 1076809297 3449220406 +16 21231 20711 42174 7186 6435 33363 42388 22453 54123 51128 33490 38345 676 45846 58654 19302 56564 9661 12716 22445 16378 38871 52390 20112 20256 6546 24682 0 59275 19197 13197 25828 1099033399 1158223614 +64 47117 45136 16436 16393 47586 18180 14641 13484 51918 17891 18501 12576 47819 51033 17017 13175 0 51299 49827 16772 17693 17529 50396 19043 14012 13891 45161 598 50195 51841 16583 47089 19274 16604 18320 18193 45622 52089 19022 51418 32808 13440 51586 50792 17431 15239 13144 32778 49629 14899 0 15813 47691 47977 17527 50887 15681 45468 13523 45131 47733 15873 46860 13717 12718 18704 46639 51465 13885 0 48659 46990 47533 49689 51517 51050 0 51229 51722 47580 0 12498 12950 18516 33018 18034 47112 46709 17298 18997 17322 17995 0 33310 0 52055 47826 45474 50200 45532 13771 14213 17416 13711 33567 0 13520 45151 47967 51925 17463 13190 13082 50734 50564 0 14325 48336 49848 12360 51169 14876 12430 46569 668 13393 48648 15519 1090727614 3265885354 +64 47417 18529 10763 51213 53024 42646 41293 5597 38267 6990 59375 44483 14906 11351 864 46366 48637 39626 16666 0 41995 25088 11284 19041 11600 43743 26595 0 14690 11740 21058 9535 17650 9124 58271 52432 16924 58283 49937 12763 8573 8015 8135 56734 14702 52701 72 55541 26365 370 6 51254 17069 20873 37942 51115 11229 17651 21654 0 54225 12433 26401 21645 20737 44752 24701 10369 42437 52358 11842 26575 5536 7454 40205 13710 24434 22739 57583 15241 23135 51414 0 55078 25811 7686 49763 0 12688 19299 24217 6253 10160 54307 37957 9639 55939 33309 40127 42664 44457 9487 58897 47120 38847 52129 8875 48090 46281 38094 11230 0 53721 26058 42508 24473 50093 46827 5847 10331 8078 47728 55873 7613 7602 9170 53151 47183 1066224515 1227535442 +8 50401 7252 49630 25809 58539 0 22458 47028 15232 17543 43867 46749 21497 48268 25681 32917 3227718311 1198120311 +64 304 50990 6219 10093 52816 45397 26268 11077 43842 20713 32865 48935 32907 12940 19259 0 22378 11312 5874 9110 44879 13088 14883 19177 0 50612 43994 50557 58868 57531 7285 21445 45971 49951 46678 57297 6477 0 44001 24453 0 13817 12834 5540 32812 23562 11222 17181 26130 41878 0 10448 0 17375 53866 7663 54254 0 6813 48788 8107 10603 26174 0 50662 42334 33302 11047 40275 10239 47645 11313 1010 43817 14478 50088 48901 6352 0 487 23147 6369 58210 47808 26490 0 47453 57215 14321 40443 9200 45191 41087 845 43637 20359 49969 0 13533 22843 23624 332 40202 16734 10889 23198 44843 0 51162 38316 14626 10816 14293 42640 5195 20695 33113 48697 51066 6254 875 732 17566 58704 46518 9920 25336 50256 0 1235653119 +24 49640 27735 63745 0 58630 38185 59461 11350 3499 24098 58922 51918 49436 62919 47421 33685 35666 55867 9553 8097 17165 36708 52868 11266 0 57899 17141 51964 53228 63635 8415 3473 52625 59426 35952 53032 14060 44997 52236 45678 62391 64399 28588 13300 51259 22025 17392 29318 0 1257331103 +24 43942 37865 570 50508 23881 33076 25714 31518 16718 29094 2287 39830 59405 18807 54287 35631 38242 23871 5790 9698 21402 49884 33449 1319 21007 57668 43521 3455 0 30129 22336 43725 22411 64417 40234 0 24603 8964 60247 41840 59111 41939 29692 20688 49307 44823 33837 49903 3180341005 3459025239 +16 53344 0 49259 12559 0 13343 0 11709 51984 44195 43094 15998 20001 50386 53147 48048 46879 0 11532 44986 14616 21077 20875 45591 21265 0 50155 13031 47845 18046 48380 0 1079790649 3292736338 +24 47254 51936 23230 6216 53067 0 38355 58020 0 44589 43151 57728 22968 22106 1018 0 37969 33421 33658 11380 0 0 12419 39781 11377 43750 15330 52148 5368 578 17547 26536 41908 14748 25860 33630 51455 10479 53014 33245 6478 50533 0 10544 47973 12084 20238 44934 0 3385561641 +8 18056 42841 0 9936 26121 40303 13254 18102 11848 11623 40624 6352 19075 41966 43580 43458 3238015011 1184703244 +48 15696 17025 45433 50564 0 49694 17076 51638 17228 0 51031 16345 48713 47603 13666 47469 46750 13952 47665 48918 50088 12456 16681 51154 15744 15908 16993 46522 45079 14758 0 48741 46014 17713 15507 48989 46313 0 17725 0 17821 47278 49538 48780 47919 0 14061 49756 0 17374 49176 47109 15977 16721 48888 33450 13512 16210 12824 46530 51450 51812 18256 18227 48114 49883 14492 16756 19265 47813 16128 14137 15667 13741 13937 51110 47248 47191 46362 50208 17949 51354 46231 0 51669 33263 51488 17980 51178 13670 14432 18334 45117 50663 15637 14124 1066750496 3275130491 +32 0 40366 43224 58146 38797 0 59713 23297 37274 23056 40039 46641 53410 48384 19774 6191 51046 56662 58315 43286 30431 29203 57649 52468 21202 50534 57289 34819 23808 21513 50027 25076 30159 2596 61405 54333 41206 18056 14856 0 40517 62402 30558 61733 43311 51377 7831 12322 20637 59005 45216 38927 21878 52296 17037 43189 39627 60466 42719 46049 20891 6105 28813 58954 1052231718 3383668259 +16 13715 42105 665 17015 12227 18217 35881 62237 51695 9140 31536 35346 27313 50017 207 21812 54029 26780 46918 51762 9675 9476 14501 18147 55106 13439 5048 0 4863 9527 4763 26830 1062862049 1204725471 +24 49673 12662 13921 18458 15796 12579 17281 48159 14638 47966 457 47655 48143 15081 46846 51156 16298 15058 15587 47797 19039 17826 16877 18007 19211 46367 17271 18753 33319 18989 49991 13048 0 14989 46574 51998 18015 16405 33591 0 15398 13496 48554 18940 48791 18497 18313 0 0 1117579272 +24 13478 52814 15462 47430 45457 50814 18664 47889 12754 15901 51239 47826 17156 44768 46966 20083 15758 51681 48481 48594 48011 18200 15577 45200 0 52545 50394 0 47169 47705 49951 52958 11468 21452 54033 48026 15798 50665 11539 33015 12264 0 47466 33741 15931 13925 54145 50435 3265174760 1147888570 +32 54111 10686 44132 47440 52075 0 49730 20207 33636 15961 44625 44240 44374 51773 10546 0 16093 20557 46407 16973 47213 14444 13562 312 49898 19719 794 15695 15591 43131 49595 45565 54036 14944 214 44723 53013 11406 47925 44426 0 18110 18734 50460 44980 46276 17046 934 13680 0 192 18403 10859 48127 21377 53446 11062 13914 49273 50266 0 53976 11030 18914 3235785866 1164853126 +32 45734 25884 9069 43539 62024 662 39092 8642 0 3676 7763 55829 36803 31190 2663 974 13584 47682 3975 21242 27792 16085 0 16814 4329 0 24307 19380 15046 44325 12438 46745 27447 55705 40481 2431 49049 20563 41314 0 18748 63396 60545 62958 675 30833 57405 11160 39933 39252 0 9803 50482 57979 26403 40399 35455 5513 23113 42837 14287 5592 6953 64414 0 1322248254 +24 53493 17800 51836 11498 50781 15455 0 12750 17932 49867 12569 0 17287 17353 319 12239 48085 0 46342 53472 20292 15992 11249 16835 19284 13437 20314 51713 33669 48333 53929 16153 18099 18537 21361 43062 11844 14266 47440 20025 33005 17569 0 17538 318 48718 14369 662 0 3297476076 +48 16900 13068 10324 11582 19187 53168 20460 47084 45105 11699 43856 51844 49041 48495 49289 46177 19147 0 14390 16117 0 12321 12830 19147 15747 52309 53336 0 187 0 0 43941 53132 49193 33679 48620 11348 0 51473 0 14238 50539 0 53792 43718 47453 10956 18371 46155 49174 33478 879 48210 13034 16975 0 47589 15287 18088 47925 14422 11986 21040 53467 49028 50387 47939 51210 52233 45683 51845 15290 46473 20063 13101 16055 49165 20954 20508 17078 49537 0 33362 45357 49769 10596 44446 33333 48224 21351 49646 20492 15767 19233 51177 20004 3232208229 3305497055 +32 0 55409 56515 60219 6053 0 54459 43405 9733 25199 11618 46002 32836 52589 29196 22029 15120 36066 49646 7092 5783 22319 24542 39506 58278 33608 41758 6004 53605 55040 18144 19401 850 13734 26755 35495 53838 13191 21794 6849 39305 0 43407 30571 47418 37922 13966 37670 8000 28487 8664 48530 49517 0 48317 20623 18973 0 8637 44573 44529 30606 53242 61498 1007882391 3397649151 +48 63720 20029 0 6132 0 57004 64475 41102 6011 62033 32912 46210 51329 27119 18061 15511 0 11760 29749 37566 22125 64299 17558 34824 57596 18798 16282 29985 63182 33913 13877 19393 35359 372 55389 0 6539 16345 61508 62983 57164 4827 0 0 0 33109 19187 4041 39522 13999 22145 42548 29080 2337 61044 14392 57945 34089 60362 56547 15834 62910 15222 5895 24634 37108 6018 43159 23688 63693 46594 57557 6585 38159 15396 27158 25106 32800 28633 18419 27604 903 63705 45963 24142 29634 25907 6560 27873 15384 2363 54089 5293 27570 7340 6041 3216803291 1327552771 +8 25306 48891 21297 14666 0 18579 51896 42457 0 38260 16298 39796 7169 49316 43488 10602 0 1119042830 +64 59521 28174 8686 50461 13781 26226 64467 24353 5184 63700 25682 53286 45597 58528 45184 7613 24593 22546 26889 2845 7874 18886 2715 12812 2276 15692 54270 54547 33536 34376 31537 56039 24328 33706 0 54626 11379 15594 13668 6969 19319 0 50537 26799 34157 52240 63448 17353 49790 1179 22371 6019 5388 30052 62723 29499 44051 34340 41373 36690 53016 20347 39064 49930 38892 58743 36372 25093 29734 22549 54159 18828 40023 41178 50686 22159 6078 28077 44910 36087 57302 47038 58835 29233 51086 25602 0 9245 48879 59200 59211 13763 26009 43857 23286 9581 37815 45084 22731 38755 59365 30184 54722 25069 24590 13739 51855 52984 58347 5673 0 38145 33056 53635 51876 59934 8939 56817 47480 56052 0 58431 38582 14357 46338 33803 2655 1556 0 3411413747 +64 48334 45675 50579 50679 18989 14503 46187 49470 47726 48101 51522 49942 50967 17118 47110 33723 51072 48671 12448 16211 18218 45717 14540 46331 49681 13716 46437 51756 47190 15831 46540 14037 33493 33508 46100 250 644 48368 13110 45350 0 14557 49426 48502 19012 45751 17352 49350 46134 16437 13699 0 14083 48816 18130 15194 17513 51873 48443 48311 51628 48315 16832 47389 33624 49895 17369 48816 18656 14864 49798 18668 50435 51565 18180 47841 51014 49407 12701 17000 0 49776 13754 49509 14836 50847 45064 13836 47111 19093 50159 13822 16725 17602 16802 47397 45542 12609 17589 0 18276 49118 50264 16202 46151 746 13431 46876 48653 50226 12626 18961 51143 33677 19391 51503 18877 47186 47156 564 0 49638 17471 48380 15248 15719 15768 14617 3172045472 1117090232 +32 16195 0 11949 49244 53324 46527 49961 0 19475 821 52758 13508 45475 19651 48253 13622 19298 18935 13793 11761 49636 17941 20924 50740 11692 45944 11855 18264 21366 44038 33396 47302 567 17120 54271 51317 17459 12744 15406 10658 11589 0 12663 54020 0 51981 47913 723 43611 13037 20029 14696 44367 53266 47451 53671 43239 50704 52270 15188 48039 51335 45330 50847 0 3284845624 +8 18153 48423 52376 0 0 21112 48993 0 46184 14117 20072 45839 17606 10917 48032 11374 3222620264 3286998235 +48 38462 42496 17010 13395 17758 35288 43223 61430 20067 4771 60535 18387 15069 45422 36349 17475 33942 17901 29621 21401 56453 9981 53627 57641 20311 45748 6372 0 26066 38255 38246 33133 58760 51099 55258 59314 9562 2851 60222 28980 33205 42405 64368 0 49308 51060 47104 63070 1038 45265 59844 24590 3252 166 13406 22818 46680 40566 51622 0 37512 8915 3818 33738 46193 11234 3787 27357 48649 18208 0 2889 14839 1575 32925 54879 0 3469 21256 57907 38918 46344 66 7332 54517 32952 36788 6909 33283 38687 45396 58348 0 49768 24990 33897 0 3380802862 +16 18201 53993 52850 13429 49002 18837 0 48703 46370 52252 392 44366 47544 50145 10835 14168 10901 20382 14406 45940 50853 46852 19519 49814 15937 54022 10620 33511 69 49533 18494 50097 1011637232 3292278001 +16 18862 24016 35976 63997 63614 61054 34033 59835 275 3411 0 12999 678 50099 2352 37329 62176 42717 28321 48325 62641 29996 55449 14027 15291 31517 45654 12700 22445 10304 50313 33379 1044110539 1309081347 +48 15613 51376 15335 51334 48965 51134 18400 12977 45332 15834 13031 14677 49457 153 49504 50802 48060 15076 51457 47036 49602 52182 49178 18372 45748 15631 16475 48344 50664 508 0 46417 48179 17694 46864 15266 47497 0 51057 0 49211 16942 51808 0 45151 46788 14573 17791 18036 48461 52000 12678 18560 49854 45275 17797 16471 19440 51662 14083 49828 16829 46851 47486 49079 15517 445 18201 16092 235 16757 13568 12588 48404 15129 46367 14599 14799 48390 48969 47899 50213 16849 49822 14180 49278 0 17605 33096 46085 46712 45975 14100 49357 0 45477 0 1099771036 +64 50248 25994 52581 11447 55034 58443 56100 46206 45235 47357 0 41366 48221 48060 13972 33588 39928 57575 7994 14664 11389 23617 20601 58846 22331 58551 14576 21382 52276 54945 48000 775 33789 0 55111 5888 26500 25882 48838 17775 52706 55697 33104 25688 23499 7260 16094 50464 53069 14419 48730 24244 8134 10953 15025 174 40992 25562 336 39331 17808 53635 59058 33262 43285 41672 26324 9796 56062 50662 9695 45918 33070 55746 0 23589 14496 0 0 20717 11160 11783 38094 0 37902 56358 48247 14151 8301 24038 44318 39861 11002 26281 50327 45766 57515 13909 23064 0 6776 44174 46803 44553 41806 32889 57966 50831 55603 49814 11507 41622 45193 55169 40041 41212 25412 51734 39167 33000 21796 44281 11105 39289 24860 706 40656 6432 1126885962 3376369461 +32 59859 38040 33235 22419 8680 56134 14919 27518 17397 29251 505 45796 11769 17874 2845 45403 14931 64400 20947 37267 0 37029 47308 20127 53035 31429 37587 25978 19455 4188 28404 57526 18021 0 49349 36674 43790 17329 60730 35309 52042 41362 37356 42577 7753 5019 50232 6124 9015 53276 0 29358 3608 24528 4059 23139 0 4288 45378 52798 17495 54310 29123 34657 1102920788 1285818269 +48 6480 23503 41294 47772 45616 47803 50718 19808 10159 19161 14571 7848 11436 7195 5892 51199 57195 17987 58442 52173 45036 9574 911 17907 25270 10728 11413 58786 42807 0 0 17887 38989 19041 16734 58388 7071 40673 38532 40795 47948 56470 48718 0 44484 14138 48103 25444 44458 15122 24768 7828 47764 32837 0 24011 53780 24122 44123 0 0 47198 13140 5920 548 26500 26053 23633 33152 0 55333 15859 24217 20782 54083 45024 49197 0 43581 14474 7362 32874 56695 54272 45433 0 12810 11091 0 9786 22398 44924 6175 18855 52305 20102 3206370489 3381397046 +32 16540 14516 48959 51642 14206 53239 11019 0 10273 52221 44741 43381 369 408 0 13667 16068 10593 51578 16699 47058 20545 250 33092 48874 10468 0 44233 49410 16695 0 52566 15067 14202 53304 48925 0 51064 50354 15210 44454 12991 16572 18669 46706 11898 10245 16164 46895 0 51306 45768 53729 44641 33631 17812 0 15058 50297 10545 49505 16579 47138 33115 1116214458 1140883403 +16 16379 53076 19111 18087 58829 45172 63108 6595 44030 57017 24978 1077 24257 34187 11765 48486 54212 21293 22242 56966 17555 27516 44070 5004 0 8401 18405 35237 45624 3233 8072 21951 3174078910 3310232740 +64 44978 47118 0 49733 46256 0 47094 13156 0 21222 52910 0 50903 48864 47241 43692 45197 48605 12783 20967 50194 48839 53213 45626 50371 11318 20838 13360 52986 15463 0 15822 0 0 13973 44382 14112 46635 0 18850 10472 44554 20630 0 14736 54050 17834 50859 47814 11774 14776 46370 52999 51801 48358 46919 20049 47180 52346 50076 46419 53289 51341 46252 47356 45732 20060 48315 47018 33038 44564 43748 20603 44399 17238 51216 15684 44454 48147 48198 50723 14791 33050 0 21421 45765 18061 51092 15074 20007 45601 44350 44318 50689 13906 49865 44490 0 50119 51805 17872 16145 52534 43854 19313 12571 0 0 11603 45893 16521 51451 43174 13318 53353 13537 44608 50622 16156 44767 20523 20663 562 53692 16455 44032 19349 45144 3183506450 1137855618 +64 54693 44392 33655 4637 59644 54352 33694 58384 29665 30975 39996 63451 37083 29798 42974 1888 10413 0 26951 17982 0 7322 48461 47472 324 10043 0 15923 37919 19206 40622 6757 27047 0 31519 53487 61041 34229 0 8271 35305 49865 57421 28451 1263 27536 33265 19979 30985 6194 45144 31005 23931 29304 59447 58643 26222 19769 40974 22727 45822 59668 62909 25332 6018 28570 50429 55975 0 34348 59354 33187 840 14012 9859 38078 10708 24332 4029 58421 15641 51537 6934 12730 53056 6714 0 23215 52619 47873 63250 43314 0 15042 27894 2979 34600 39707 27193 54588 26083 62557 46553 24911 58147 8773 12860 4771 43264 37921 10973 40729 38900 53544 38762 15021 26138 32798 7928 22741 26267 21686 35335 9887 584 2390 47244 6012 3236941451 1295159733 +48 0 27800 43150 29677 57439 52065 47465 52458 25109 51852 16366 0 36699 2274 59997 0 52329 36659 1553 2174 25691 16941 44205 10749 39 0 2683 24382 356 64335 57898 0 22815 36586 17738 25242 21685 42799 28513 26591 58078 53897 30745 9406 60133 24921 7669 15370 15264 57965 28152 20399 20571 54365 7217 62421 63436 43113 20109 9501 36562 23399 34394 916 11668 16750 39173 9305 53785 53369 55888 33435 24374 0 55188 50693 59501 22901 8708 55897 6391 9102 41440 426 33850 25647 9871 22414 0 28107 42302 0 53822 20460 13998 56015 0 3423742820 +24 0 52816 5941 0 55130 14999 14667 43753 47414 43065 54779 6744 55289 43253 16052 8599 39287 23066 17404 13597 5504 43861 26104 11405 22907 0 0 0 836 59386 38786 45549 56095 58811 11047 21400 32961 17082 0 39425 0 0 44466 15899 6893 25687 25890 16981 1075627267 1240786693 +48 45795 16508 0 33636 316 709 13002 19012 15969 15661 15912 45247 47627 47265 49423 49732 13249 48422 14689 47606 17801 46192 16871 50655 16198 46645 46357 16868 48434 14117 32941 0 18484 51146 50474 12470 47307 14725 47311 566 18746 49950 49719 47182 0 14758 13353 33025 45159 627 46385 0 16879 13777 0 33447 46948 14003 49135 49443 47031 13506 16564 15422 17853 18181 16278 46976 0 52092 49343 13670 47686 0 49366 48386 51471 18228 16068 50421 0 17405 13024 16300 15507 14541 47649 14843 51202 14466 16824 46250 17081 13329 14462 18922 0 3272127382 +32 63852 18052 63541 2813 55555 40625 25855 244 11775 0 15657 39995 35810 19158 58619 5546 57543 16674 17349 10317 30270 52355 23640 39806 5078 62896 42874 28421 44991 54141 40182 40187 8372 127 29320 35755 39257 7093 43751 39904 62869 27426 31208 0 39321 24292 0 37750 44951 27672 59394 14072 31158 64034 29764 62099 21773 15277 57086 43240 6084 38112 54846 0 1092621704 1311812253 +16 50576 12788 0 17679 44642 0 50446 0 49332 16213 15224 53686 12133 51770 46654 50661 48908 43482 48279 18417 0 19958 46938 47442 20349 45396 20109 44903 43226 21383 0 48157 1094099427 3291761026 +64 41295 56911 56900 38215 56386 17580 33470 33147 42674 45040 52291 0 25636 0 50456 42231 54337 8401 58827 56505 50445 20103 46660 47050 52371 44514 49526 41578 26371 20726 20088 20737 57899 14415 55485 19823 43687 56248 8620 52591 56092 14937 59114 13347 52309 15 11857 16381 18363 44107 12869 38708 21604 48699 0 45050 0 44946 17669 19434 14154 0 10483 20562 41420 41932 995 51540 21671 6352 40724 45672 49504 6967 46097 7043 40394 48161 15189 57822 20702 21594 51923 19005 53880 16195 26199 18384 6608 13392 56347 21240 50051 54597 42326 50243 53327 26618 5147 16612 6919 42571 49517 979 10709 5498 15016 6179 0 0 58607 11890 39438 0 90 47636 10362 51504 0 22833 42726 44397 54735 50519 18646 8702 0 38261 1057726979 1176147412 +64 47225 19328 15412 49789 13058 47923 17430 14187 18015 46001 17884 400 0 312 15045 18917 49802 13467 47582 13127 174 15015 14179 47181 18071 47012 48810 14221 13842 14681 0 32840 16843 45834 18781 32913 17243 32900 488 51005 548 47704 18817 51660 13604 19374 51531 47858 15649 45057 675 52115 32953 48905 0 46053 46713 33403 14776 19019 47132 45784 18915 45565 14018 16456 46854 48193 48065 50182 47622 0 46122 13467 353 47762 50344 15027 45441 48751 16715 46797 46533 47714 48923 12992 46482 0 12402 0 46864 18526 18558 50203 17078 48514 47612 49307 47188 14801 46145 0 16103 16347 19215 17113 45263 14282 46207 13395 0 12818 50368 18108 45769 46010 46578 0 49053 49778 50984 14532 12802 14002 48927 52001 16816 49877 1006909199 1104807928 +24 48313 47148 50539 16259 48961 14127 17619 18812 46723 48470 51544 18094 48157 49728 16255 19196 642 47861 15348 13833 18332 46325 12616 12460 50295 986 50959 50810 46135 15564 49324 17382 45623 46714 49779 45656 18849 51362 46053 12489 17339 16113 17335 50745 0 0 268 15468 3172894086 1122668560 +8 18055 46011 21107 16750 16333 53502 50344 33455 54123 53229 33251 13447 53093 10800 16845 53062 0 3286369863 +32 9395 64364 7184 2789 0 17954 52905 35948 15615 497 5544 52409 42976 55594 15090 63830 5333 4114 27833 3919 0 60990 59589 18310 43875 0 9865 12188 51779 25824 14369 50915 34103 23726 61551 20118 43345 19457 22200 5868 42116 58991 19426 26648 64174 17218 37074 51243 0 51824 25120 62448 54969 35890 58882 28815 47957 35795 50865 59173 15533 33604 25443 1299 3238019785 3407655070 +48 16295 22437 38784 11395 11066 7429 25720 50063 17313 52603 10907 18132 25081 0 47919 46127 25125 16071 38017 0 54943 12789 51307 0 14344 59006 47034 22365 18345 41346 16853 0 45253 16874 38876 14821 38976 0 0 43255 39313 44000 8078 21558 14994 50591 15779 10799 43012 46903 19009 50579 41750 50571 41267 0 41022 53375 24069 19256 46036 14788 21605 58558 49451 0 0 43167 15873 58390 38875 21160 24377 44454 14954 18653 55756 0 58938 43610 25118 46750 49718 39922 15345 55826 55125 15498 54367 0 21654 9925 46022 59382 38937 20322 3214561263 1168517766 +8 54055 25624 23424 6110 10302 23807 59156 15645 44330 13050 14606 45181 38405 25295 12691 19879 1094349361 1216880248 +8 25501 42193 30122 47266 58826 58102 9264 15770 36480 0 38934 38231 26188 63331 30403 9416 3211813687 1270575959 +64 18731 13632 14700 17251 33773 18870 15898 17614 12960 19094 15820 13455 51895 14984 15254 50455 46082 16601 45830 18049 50291 13404 51440 13368 45396 45135 14976 49955 50431 51970 48330 13151 50520 0 17712 48372 0 46868 50963 15612 14420 18366 17006 13520 46876 48434 18598 19454 18850 19190 15882 51685 17313 50569 19151 45064 15172 14080 45188 12411 13667 18919 48183 50562 17869 48089 49817 50165 18551 19104 462 48713 13210 16791 14402 48703 51920 19390 47962 16062 47496 0 48908 51288 46530 15111 18603 51336 46075 19067 45506 52062 13929 45812 51742 17693 12717 33418 16104 45931 15644 51357 48265 18092 15645 46617 17083 15845 12613 48333 0 12422 47559 45455 19425 49569 15761 16137 0 50835 16753 15033 13357 0 46503 0 47569 16331 3155008863 1137369260 +64 41891 36165 681 51653 50101 11889 7146 25900 21755 55536 299 51489 331 5531 42685 33958 33164 2733 18184 41418 35253 23990 46885 23872 50218 62644 9084 7881 55587 56141 11500 62848 28246 24778 36484 27325 38289 37473 60848 41757 23486 62954 39107 33312 28986 36357 25179 0 0 62738 17242 22849 46468 48511 32967 44668 20494 2462 49356 3418 52962 19254 24016 39016 16806 28703 28889 53562 5282 23365 27869 0 35282 16775 49179 37111 0 63408 53643 1982 28116 38 17377 56844 58906 21100 58677 41057 19544 0 6075 54665 57543 193 60522 4670 59280 13078 10187 0 0 30682 54181 18242 19112 31012 56209 27502 40962 50106 28434 58984 13470 8446 6348 10056 13250 40289 43546 42098 10969 47380 57281 56024 58403 51645 29330 33594 1039644365 3463675347 +32 49476 49676 18383 18230 50580 14137 17128 13710 46769 17795 16903 50418 14830 17958 46631 16586 15160 17719 19305 48146 15909 0 46218 17485 48470 12680 17221 15807 50047 17084 45272 50444 14502 50286 15137 15653 18474 14276 45765 16072 17943 15681 18875 14817 48192 46334 13270 16085 33476 0 49373 12491 13467 32837 18458 14038 12347 48908 14098 46712 12636 46956 18772 51262 3235032587 1098221240 +32 52539 709 46212 15223 49824 49618 0 43819 43833 15862 51985 47618 11462 12525 0 47060 435 13719 0 48475 45861 18590 13552 18938 11132 12710 19085 50038 15136 48491 0 46461 51493 16206 21250 48501 0 33446 16030 16123 0 21248 10309 21347 46934 52989 43911 17785 17151 18644 50627 52714 11897 12692 0 50219 16883 16260 13284 11153 43022 48747 43551 18588 1115181212 1133283019 +48 10764 43431 861 14601 16918 48235 47600 45917 21465 44096 11170 0 52091 45487 0 20288 0 0 10837 0 47779 52002 12209 48190 52217 46598 51140 49173 11448 11706 51763 52288 52513 53853 53595 12005 13239 16619 17633 43900 52523 19620 15994 49286 0 47132 10333 11435 18524 10303 51835 11112 14946 50251 51622 45580 12940 0 179 12385 53736 52102 19295 0 12937 17999 20616 19313 45941 15951 0 49464 49345 44847 0 16144 48595 19554 53102 13299 21396 13124 11998 12659 18444 52553 0 11531 13332 15437 17717 13717 11173 50305 15972 10569 1010605388 3273946376 +16 0 19352 15766 16372 45096 45165 0 50262 17845 33320 49911 13434 49326 0 50244 13367 12965 13565 15434 18666 13985 19308 33233 16821 18663 52052 51076 13509 13244 45647 0 47312 0 1119457392 +24 428 51136 18752 55148 41750 46792 14646 40533 9479 17037 12198 55536 58722 56271 51865 53787 10845 7500 53634 23737 14541 0 58937 23090 5834 52659 13479 37952 23454 8930 46168 0 884 0 13637 21299 41054 51220 50402 42154 47091 23668 14360 44200 54288 19632 41673 23272 3234603732 1192249735 +16 17261 49247 50796 47260 12821 48822 13825 50242 13063 50060 14250 451 13181 14899 49018 47423 17304 48533 16227 0 48666 33366 0 47800 12545 46829 12932 13059 51280 15141 18859 47716 1033296097 3241754262 +8 19986 47656 21650 0 59379 52496 10833 48084 10452 57797 18075 12646 5544 52005 45760 40771 0 1151817969 +24 49043 11375 7791 32992 18231 58425 22174 17353 8630 26389 8536 19880 49292 43204 50906 49648 58862 15210 16023 41456 50645 0 8034 46112 17811 58523 17962 58844 0 45073 22885 45702 17281 22524 0 0 55173 42637 10151 40517 54569 6435 19563 21340 38399 54688 8450 24882 3130159443 1219972097 +32 23642 13812 11617 16191 21614 55923 25310 0 21528 7424 16809 19356 57683 44491 25166 0 15170 41144 24470 10888 21893 25460 47200 52371 54241 39204 7089 13396 53312 51093 50877 56988 54445 7978 49538 50092 17407 24118 48536 21207 57423 0 33276 23367 14492 38628 39803 7838 11505 22571 22612 58721 15035 33769 19117 50079 59097 40508 48923 57403 5473 10223 45007 51538 1082930392 1194406666 +16 7591 32957 53762 39104 9720 20676 12620 46731 0 15623 0 18376 0 0 11071 59347 54867 49379 19806 59187 44424 16896 6060 7588 46081 43008 24321 23324 57229 33451 26490 334 0 1148268581 +64 49695 43681 17695 0 0 23142 48667 0 19597 44690 51315 9090 18030 7949 23023 22558 12920 0 43569 12556 13433 539 55716 40461 14305 56438 46086 19659 12799 54323 49104 37918 43720 759 16516 0 6235 53090 14903 8215 53982 8927 8174 44478 8889 38663 0 13979 0 8488 0 13708 17156 40923 54578 17546 23790 11473 52545 14086 19673 5197 22521 5226 52262 47641 49101 41430 25391 14995 40695 9648 57892 17727 25131 55274 9017 11167 12823 54254 0 15625 47290 42249 22891 57824 16333 16236 41468 54797 52740 5498 889 24008 10713 23021 48394 0 25530 43051 19503 24099 15877 38444 48566 8096 23277 38248 42637 10445 10973 42294 12545 11588 58985 47384 26177 0 51218 16726 7346 48878 42463 6833 50257 21844 10793 57524 3179724192 3337259465 +24 49188 0 49734 33652 51210 52873 46504 17480 16383 53937 47005 52484 20460 46341 53599 53512 44084 46231 20824 45586 114 13357 17283 10651 620 49867 44025 53778 47206 54003 48872 13926 12370 13093 16354 50062 33642 51840 19711 16956 0 0 51356 51595 48342 20639 18825 46208 0 1128956072 +32 38984 45462 47586 21672 54678 24903 17028 29179 31187 23343 52919 30814 46025 43515 46009 63401 40971 56785 0 35841 51267 38024 32827 0 13888 27157 50460 24764 8378 25084 52421 0 8409 63395 24389 36995 27040 21734 33625 32960 28847 39804 17328 7353 31660 48839 63458 14539 58337 31004 26283 42676 51184 36215 47386 26384 48031 24754 0 62462 3340 44374 784 24936 1084965799 1305401869 +24 45245 16101 704 18589 14732 49350 13792 49052 46938 18424 45860 52148 49955 50719 0 16113 17262 19104 46566 12971 17650 14944 45557 18210 47519 49367 51491 52021 51148 0 52194 46329 46815 14487 50085 15636 14173 13243 49072 51879 13728 16023 50227 50295 15338 46588 45151 48540 0 3274272915 +24 15531 49934 9946 3575 48198 1339 22302 31091 36016 36455 40382 3064 0 0 48958 0 24883 0 56352 29796 36328 20172 1183 31245 41766 9871 524 12698 24792 35246 37029 30425 45528 3082 48663 61106 58372 31335 28888 33754 12118 58421 58880 1025 7133 23294 38690 56909 3149051432 1318251500 +64 13842 22961 34806 28736 14584 42358 61100 50292 500 14168 40799 49661 1595 49129 34350 16401 15280 38916 4535 33747 36674 26778 30102 44347 45190 11418 17620 0 45793 0 52494 14870 21452 33596 163 41533 0 39405 0 8519 50657 5349 13666 24094 2360 33132 40673 55762 25335 6058 30031 42738 13393 55527 45247 0 39889 46782 48068 47516 10336 46993 37924 61956 50187 14859 62828 7543 1530 55990 58822 28966 32831 54901 21822 62638 51747 33492 49832 43567 50674 53860 11776 29089 12003 43006 45255 4290 59238 16417 44546 58946 36530 21388 17964 0 47355 24778 16376 57732 2826 18779 56561 25301 2393 59725 4908 22927 47221 34089 13252 28474 9745 53155 42486 33786 23415 0 33344 44546 0 0 51336 2380 61321 457 60220 50801 0 1258777564 +24 16053 10820 50094 46574 17291 48539 44563 49640 45725 20289 14543 14447 18758 33463 16585 44301 51323 17457 33093 43262 43187 16381 21185 754 14324 16354 49884 0 11149 49962 46750 21470 47891 43245 33508 51445 52337 15195 53748 0 17416 52138 21051 0 237 49367 12092 12978 0 3289339074 +48 21117 12325 44229 48036 0 48205 12304 52251 33329 50574 19735 18618 10763 50261 10259 16907 44967 13122 44660 44639 18603 20797 44215 50859 17852 12543 48323 0 53176 48890 51253 49797 50517 10888 13160 52099 21374 49168 14179 45977 12198 0 49149 48128 0 48906 12325 14990 44180 0 32988 18202 51974 603 16744 13219 14447 20548 19270 11654 44061 50067 47216 51433 50921 46358 52577 15585 21032 19217 11857 17980 13987 20548 15023 20019 12395 44634 14479 10816 19112 51663 46747 46201 14105 21169 327 43200 21437 0 20122 15978 18038 17614 12683 816 0 1146978755 +8 28842 35536 13256 46298 26487 18146 49176 49069 29818 62209 14675 57036 30047 38268 0 38762 1016875842 1297031249 +16 7901 54644 22288 19556 49263 52446 11004 23797 12272 14538 51379 0 9496 43130 26329 6125 52701 54007 0 54931 33275 11421 38913 0 44628 6608 14944 18254 25164 11783 17318 220 1036279321 1175974943 +24 0 0 16714 14592 14415 52028 49359 18825 15123 15506 52123 18954 48092 18687 47894 49652 18366 16593 0 12431 14656 16024 0 51199 18556 49799 46848 236 14221 14631 51129 51997 33450 0 45644 45270 12349 18104 49852 46011 18579 45709 14083 15011 14711 19385 12766 15448 1063779225 1093994020 +16 14420 10348 18622 46955 50610 46787 5360 15151 23126 47172 59390 0 9000 18022 40705 455 47002 41673 23175 15583 7271 18610 48621 9628 54857 24550 0 24202 19087 23008 19598 54343 3154981112 3330838208 +48 20575 5141 15937 44461 48320 24715 45754 52510 22041 33240 51524 26428 23048 56386 51687 24683 15724 25457 22680 42911 58169 11839 23519 42011 5629 45807 50555 48473 25311 49381 6898 13141 48823 0 0 13214 46656 14473 13420 53518 7033 11271 957 0 9048 19046 55333 14706 44226 0 46116 53889 45478 39215 45881 10098 52109 43242 57947 54552 9415 32892 52273 32806 41485 14880 44979 23749 20911 49841 54111 11858 24802 46862 17575 57399 23746 0 42095 58766 0 10554 20086 15910 38948 20361 57374 39415 9828 25164 16676 49285 18123 12276 12502 40104 0 1199918806 +48 40580 5414 10621 6055 22215 43688 58007 16880 7366 42273 41375 16854 37949 38788 10660 57113 14719 46050 5333 32955 57202 45904 23438 39122 0 6857 15206 15222 17636 48980 11640 40416 52029 54385 57018 8597 50953 56643 20805 57894 13041 41971 42342 26113 21628 41906 50506 56591 50125 8935 227 37953 5329 0 40164 11298 45889 17171 18747 14255 46098 6031 58296 10200 23600 0 23650 6618 46745 52795 12455 11761 0 50980 54213 49156 21096 20632 55129 50611 13540 46196 51164 51816 57559 8698 53739 25647 54643 51472 8370 38209 14777 11849 24836 45676 1093019324 3377270617 +16 19380 17442 33098 14710 17661 17847 50540 17423 52083 50101 46032 0 49669 49836 0 14077 47080 16704 18917 12457 51172 0 49347 16526 0 15745 47802 0 15440 47412 14233 16317 1052285858 3247880775 +24 45870 23957 0 20276 0 44014 0 47289 0 24105 45774 18578 0 55499 43790 56339 20479 41960 38369 46171 26573 51477 43172 58550 43010 48533 0 0 53143 52184 18665 43938 46593 15099 59042 24209 473 19999 38780 23206 8391 40271 480 22206 53403 45744 14481 7284 3166927422 3355151124 +16 55307 8815 25633 7245 19611 11674 10150 48767 26362 8728 14007 25758 41426 25984 15537 11248 0 58149 23691 0 58097 42513 37990 26203 49425 33081 0 0 0 53793 51268 42725 3193358207 1213313705 +48 17676 0 11833 49995 45461 53705 14430 21377 49635 48302 20062 52619 44419 16223 10821 44764 51300 17756 53135 17993 16790 515 51619 48834 18497 46476 19438 47500 18466 478 52211 11359 47351 48930 47001 15936 18422 20588 16969 17097 44016 33138 44981 0 46395 54040 14626 0 18021 386 18823 51639 44035 44481 51570 43150 0 49239 52016 13580 17332 14908 14576 18461 15181 0 43069 47091 50683 20600 20310 0 47490 10772 21282 49400 13228 52537 10357 46588 0 47518 52817 49226 17320 14824 14929 13499 45556 13194 11062 44592 19592 0 53302 15516 0 1133504927 +24 14738 15962 18062 49052 49751 0 46668 48041 46593 45170 15513 0 15940 46136 45639 17520 50756 48145 50541 12833 48691 50098 17459 13126 18499 18348 18224 14910 52107 45933 438 45694 17631 12553 16860 12338 47454 16041 18610 52129 18189 15782 14303 52093 49249 49801 13146 13415 0 1090604224 +64 28942 42702 60196 24733 34632 18786 61706 16174 35939 54668 30959 15124 36258 28957 0 57022 55424 30962 49871 48158 13419 459 6736 39550 2519 12271 36739 35470 33473 49114 21054 30369 29069 39819 63243 20497 22441 42640 34873 49640 11576 5539 35455 18823 29886 33756 16448 33559 34349 19563 29755 54030 57626 3777 22173 10645 59628 24145 4783 37992 14919 0 23883 6575 14326 63024 26452 36938 21707 11498 12089 5762 49427 37146 21524 52153 19913 16162 20639 42849 5352 61615 44420 18979 58210 36112 873 40094 63287 46849 34151 59987 8514 41311 0 5324 34070 12418 542 45406 60233 31055 57995 62312 37367 60876 18143 13018 13705 57414 16631 10903 12260 61350 46922 29998 17219 47482 8310 1835 48178 3078 28188 62041 49862 56882 60160 36405 0 3451696583 +64 14512 50210 14917 52845 46869 13684 33634 52328 48476 15788 48104 53432 0 0 46363 11791 18932 13228 14849 43893 339 21012 49040 12636 47152 14583 43505 50672 20362 15074 51028 48316 46592 43111 45809 51905 53460 17127 12023 13484 17260 13163 43457 11024 19810 46621 49292 0 12633 16253 14767 53791 51423 20177 33752 47258 48000 51010 19559 14976 14999 16482 33456 51589 16514 17001 17618 0 52675 49116 15130 16030 15884 53130 47605 13483 43449 17454 44485 11492 14557 14337 51903 47625 44719 43222 15456 50532 46076 33252 0 44812 20333 19225 865 44577 18764 47221 14112 46267 10751 10545 12660 17258 51375 45874 47181 20807 51888 0 52928 19738 50292 19661 51784 50733 50259 13476 48652 44158 52991 13363 12998 44305 33127 13204 827 15677 3229249083 1147990015 +16 24723 18542 49835 8116 25767 54360 45116 0 55216 6453 51442 0 17863 39586 7271 9851 38867 12869 39163 55785 8835 16700 18494 44150 44277 47359 15789 8106 41073 24928 50821 24664 3131508960 3273746613 +64 43220 14861 48572 11191 47557 18964 50911 33428 18053 15807 13685 11177 48361 43898 19449 10809 50308 16025 52894 0 48190 12578 20068 43724 0 12027 50633 14480 11212 44206 14771 12287 43024 11375 0 20675 11934 52279 52332 45392 20834 10430 49768 14905 0 46616 44368 14161 15920 49053 18602 45247 48099 51934 12516 46697 12706 11650 53612 47862 48742 49912 203 13500 50703 44806 20773 48371 16821 51645 47029 12144 53105 10497 49626 836 43705 33514 0 47692 10607 16097 51151 11377 52684 46001 44113 11486 49196 10992 44831 19945 20299 43664 19527 43083 16496 21431 0 11970 18221 44010 12076 52094 48989 13575 19939 52251 11799 17102 0 52221 47171 0 50806 20782 16929 20672 12438 0 50806 13577 18728 15518 53275 365 32984 20880 0 3298765302 +48 15432 50865 51332 46708 15190 13658 12981 49041 45542 49126 46456 49415 45797 51522 12777 14456 51231 49673 49072 17919 16611 0 16333 46965 49397 18284 17864 15557 15713 46052 47807 12571 15078 0 51566 33410 49486 48973 13191 48596 12315 0 48885 0 12662 48980 33152 45418 15697 19395 13431 18387 47727 323 0 32859 33462 19209 51289 47334 46098 51779 18672 19163 18946 48659 17469 46017 52095 14276 46864 47118 16697 15961 13706 46014 17206 46490 17185 14319 17923 15158 46648 18474 0 0 15866 0 50263 16579 51528 12309 15617 48723 48337 19412 0 3267252253 +24 36059 25601 1080 22054 49904 3515 20668 29581 13991 0 35105 62549 47399 64313 49590 41936 55875 0 39666 6071 53486 7361 36953 40763 34162 2349 4395 50362 371 36409 1553 50809 18908 14454 58576 45073 34337 52976 12818 34290 12596 3000 26964 11019 34701 52891 4521 51630 0 1237085339 +64 52147 12560 9527 55285 18005 13193 58765 13620 33515 38171 39027 10412 41653 44164 0 15921 15341 0 12219 43279 15523 47190 969 44323 56471 15545 46484 33692 12884 8150 23935 23425 32826 19631 47572 8547 9349 6084 51896 58932 10633 24412 11145 57952 23173 21436 43683 56160 45845 0 0 38363 44954 50031 11055 0 54180 56511 45162 22917 47771 23451 55531 42346 57374 11438 39583 22826 11161 25029 8643 54437 0 40373 18803 42571 10163 12431 26000 53978 14081 33747 21015 45174 9502 17708 52470 47305 6558 32997 45521 42442 47332 49438 20303 23659 16754 0 55871 45495 14482 17702 13064 55939 12231 45856 19319 0 15714 10046 17634 55485 13332 58888 20047 40577 51616 0 13801 59126 24132 5614 0 16936 22991 5141 23752 38292 1040009051 1219480657 +48 50367 45950 48375 43771 45366 43593 52309 12516 50834 0 51453 784 50400 50054 45160 49745 20405 11808 46756 32788 14376 52927 19604 33541 0 49226 33562 47088 43824 46604 53914 17105 0 20575 15013 19708 33046 19718 15578 18407 48575 13286 12448 52515 48912 20807 19989 12096 11000 18241 51831 19341 43181 44118 11514 18849 20066 12756 11884 18907 52385 45184 33056 45777 21208 46936 13670 53806 11367 53603 0 287 44850 0 53801 43128 18529 48183 0 10666 18356 20878 15929 12200 43064 17798 13204 20755 14282 43124 50522 54256 47784 15315 21337 53640 983319280 1173085563 +8 0 56250 43698 37995 23708 0 6363 0 56180 26152 21822 57037 23309 11205 10872 39504 3172222412 3365782738 +8 921 0 17977 14376 15521 51997 14160 46520 14359 13852 14296 15583 48892 16281 12698 50561 3201119067 3250435162 +64 47611 50664 45271 13465 13833 16254 187 15547 50848 16562 15544 50197 16907 14670 51760 14146 13928 18311 19287 18134 45355 45203 825 46481 15226 14492 33370 13931 15300 46294 12912 15312 47221 45910 12372 18475 46163 46981 16281 49579 18439 45437 15940 12640 18194 50035 48057 18374 14099 16444 0 15141 13330 13342 15988 17973 51180 14874 16519 0 14214 16181 15980 12573 52148 46939 45904 19065 45618 45205 13603 46379 0 49461 13725 15224 14443 17244 45553 48319 45096 16666 16028 12515 17912 51237 15543 48784 46539 49158 16684 45240 13840 18238 14920 17049 15754 0 50792 52188 47484 684 47349 47978 14374 18181 47692 49874 17502 16632 17194 49412 32769 17621 0 17071 15802 17782 18086 19333 16535 16035 45153 49981 17463 19077 33391 46217 3201027423 1113203563 +16 40305 5281 64412 2609 50965 28340 45063 55147 46686 16881 178 56424 61318 23831 16951 54265 48176 25329 33198 15183 34505 2164 42237 45582 12507 8385 34099 7154 48900 33561 6955 42860 1122720912 1180000760 +16 30937 21033 27959 24573 28174 33959 25891 13164 0 8667 63918 25118 7470 25254 13298 11711 0 26714 28894 44351 52866 52496 9024 59615 62632 40262 587 0 430 61303 1429 0 0 1278347778 +8 49675 33478 13622 19716 18072 54066 45676 0 49496 43753 13671 0 13139 10686 52073 0 0 1092704353 +32 15259 45015 13658 43113 13437 48295 15611 51968 15145 14531 44756 19056 52941 44390 17727 0 11698 46480 47937 14074 16373 13143 18709 19311 49607 44810 14196 43929 15389 53418 17332 16958 47332 33521 19016 51221 49585 16353 45452 53151 10622 15141 21278 11013 54139 127 16609 50700 51544 17176 0 16284 16778 13589 46439 53393 32816 43308 43317 52922 32887 50214 17386 51273 1045937554 1154499104 +24 55715 22612 11664 44622 48102 10599 10911 930 39160 640 43276 33118 56301 38506 51539 52590 13089 20617 9580 0 17595 33651 49552 10918 46892 14318 13731 15759 15825 21892 0 5991 0 43239 8244 10028 38020 0 46693 26519 51098 46297 50603 22063 52729 32819 8738 52196 3232494801 3341074269 +16 990 59173 50981 24007 14849 0 16420 14182 27715 39284 3177 20314 773 0 41385 61275 40072 16036 1453 47709 14151 7706 47084 15182 10020 19414 60420 970 4858 31338 21530 35453 3239894809 3309908995 +8 12742 16273 18688 49314 13262 47605 14112 48219 48839 0 50086 18419 45680 14462 13868 16724 3153184686 3262163216 +24 50862 12677 0 17486 43265 19799 19905 51859 14787 19362 11876 17706 12069 14355 33669 14309 18450 16827 50079 0 18302 49538 49491 13050 19771 12749 20710 47584 16538 17515 11959 0 45063 10943 10726 50121 11389 19261 0 11929 50959 13149 52805 0 47698 11987 44501 0 3180195759 3251331971 +32 52090 55397 14674 26742 41707 27839 33904 19705 36013 2659 28058 58806 51271 11481 38518 21745 35535 38458 4885 24678 57686 31265 20 30222 23603 59506 18896 36014 3325 26274 8648 63735 6673 45069 427 51897 64430 57412 55484 50923 8061 17413 0 45153 1816 15809 26234 7108 28960 37521 0 23869 21064 35966 2641 46007 12459 41839 0 40720 813 30387 38359 16398 0 1277673764 +32 56580 44393 44637 9779 49685 50146 11011 18017 15427 15864 18358 25073 41331 54600 59347 40468 39602 471 20655 6305 25092 39106 0 0 9732 58669 17770 5244 11577 21096 42956 49805 6623 22388 24082 45398 13638 0 26129 10132 21877 53467 56126 55945 7020 22664 43892 6850 0 16097 56799 26608 40656 5388 0 23033 22814 9084 32841 18594 7465 44657 12881 19475 1000639353 3359025549 +8 5390 46090 48079 0 63076 40125 55941 23041 15765 59776 34968 49806 16929 59653 39051 45504 0 3348845365 +8 39 13537 45969 0 12754 16197 50646 47280 47371 18293 47765 32786 12548 14257 46140 18882 0 3219819488 +48 49381 20956 46378 53213 0 15660 605 17698 18736 16538 53708 14290 13109 20232 53817 11299 17604 16225 14033 32904 52962 44732 19149 43008 52887 33045 44725 45217 0 0 46708 45012 12714 17581 0 0 11807 47750 15148 19056 52831 53448 12660 49372 17513 0 19022 45890 10737 11513 44022 13553 52177 47977 49517 50826 50410 53989 51430 52426 10333 21059 45201 44365 20620 17662 20560 11507 46114 623 50319 12294 50052 53415 46111 13390 13363 11203 43512 18252 16461 46242 19761 11790 14067 0 46162 12846 12546 51345 51360 0 16223 46734 53515 15925 0 1154996794 +8 46944 53773 16332 13004 47691 50013 18044 44076 0 19593 18109 47038 0 838 13228 49019 0 3294091865 +24 817 876 44148 0 10498 36181 56624 42966 28601 16069 49270 19934 49199 17904 33364 10477 10379 0 56300 2913 61697 50541 36066 21596 6717 0 44710 0 23917 52906 23460 51001 33445 17955 61161 20510 49367 34182 60710 30825 33563 45704 21606 38798 21162 0 23226 4715 1124823084 3373867742 +24 36805 40225 59276 47328 1133 37693 31508 61929 4933 34822 36067 41409 19231 57585 53931 63369 29793 0 4823 28443 0 13510 21186 748 0 30194 27961 64171 32970 2340 10510 40675 41381 29504 3796 55331 26069 22145 57848 0 0 52748 43904 14023 44262 23765 1838 34808 3207092489 3407683668 +16 16752 19400 19038 46651 14679 49569 18540 33697 51228 50899 45073 46460 12941 49162 16224 12699 48288 51383 50286 45551 48119 0 14233 16744 16017 50380 18204 49686 49661 47899 49335 0 3220331093 3275513648 +64 17320 575 45171 46414 51908 50343 48407 16185 12879 51317 45679 13301 15682 13947 17371 0 12335 0 13152 49498 14058 15402 51649 45894 47303 19290 12703 48163 33301 14893 14375 15964 18405 822 15630 13275 14365 14575 15051 14047 134 45168 49636 47575 33748 13234 17901 18216 13489 50201 48987 19292 17267 14575 50649 14591 17707 49053 13229 48081 15914 17415 51690 49077 49560 51714 17082 47373 48859 50929 15817 48529 709 47641 0 12354 18001 18378 50599 14169 51803 50394 45593 0 18559 0 0 45578 12630 0 47268 49190 46906 0 18820 51198 16211 49285 46021 47486 19444 51853 17782 0 50763 48269 15646 48283 51885 47030 48409 18722 48108 18080 47412 51714 47458 52188 47366 45390 50043 33600 32876 48097 15266 0 48618 51446 0 3264851660 +32 15448 14338 19202 16826 15565 12915 18833 52169 45803 47735 47608 15910 14913 12713 51179 12837 48321 16345 17889 32868 14581 16373 16305 15520 45479 18392 49774 0 18532 45457 50149 19024 790 14450 50525 13629 15382 48025 50628 46182 47829 0 45181 16027 51726 45879 45557 48282 51456 18237 0 51370 49662 15235 18752 50050 14677 16298 15885 46471 51100 0 13221 51149 1031085621 3279712778 +16 45137 31440 7265 44052 6339 55114 51104 0 44372 2354 60754 249 28730 28355 41576 25675 45565 19335 47747 60904 4237 13779 33420 26293 29490 63626 30873 11037 44904 15444 0 27718 1047616175 3443411826 +32 19457 15633 21473 33441 46197 53885 47924 19345 159 10523 17288 11958 10749 53654 49916 254 14600 19744 46345 182 17193 0 49370 48409 14669 54083 51469 44461 14310 19594 52242 15420 17786 51338 53707 45848 21314 18154 52212 17757 19184 0 48211 43774 50837 10978 32880 14625 16281 44198 44789 45109 48532 18347 43694 14845 12669 33451 43790 51913 46694 47436 17237 16775 0 3309848319 +24 53948 11357 50481 44636 49353 51902 51003 11250 44164 11094 46036 0 12529 19069 51191 17563 19426 53352 13129 17845 49168 17094 32815 19940 0 0 16713 43937 14573 53485 33729 45034 13874 43909 10267 14242 46630 44127 19443 16506 47042 49692 20561 14239 49318 49520 48546 20878 1069484706 1153577361 +32 1298 38548 38156 33789 0 46180 42780 31486 25048 834 27722 58621 57323 47698 0 46730 25393 23478 0 29455 61086 52067 3165 50422 42844 40821 54748 43265 16528 43053 26576 59598 1483 30451 49975 30426 47225 179 3444 62491 7568 17828 43355 39387 63751 44873 52422 47083 51064 32939 34635 58013 12801 58667 33265 37166 11984 45280 16007 9821 39890 59597 30491 33510 0 3461723642 +24 12904 49203 33509 0 46947 46536 18765 47817 18408 48037 51056 45130 18051 13209 0 0 16059 245 0 51451 14201 17118 18576 16420 48103 46179 19423 15330 13467 47391 15221 14843 17195 13572 46999 48464 46842 49100 48401 48667 16520 12748 965 16688 49742 19153 18886 49591 3211246254 1126172029 +8 53738 13958 20138 45305 18238 920 44523 50861 0 0 48522 12561 16912 47486 21224 50641 1011568466 1100348483 +8 13298 17351 13216 46948 0 12427 12998 16553 49441 13445 50000 0 14768 776 33027 17657 0 1093850544 +8 0 18835 60015 45101 0 38562 23681 23151 46336 30908 44701 62192 38060 48475 40045 29799 0 1249713025 +8 46226 53986 45312 50227 18009 44432 17963 44282 10577 16590 0 19719 48714 15102 0 19017 0 3278095528 +48 13848 18834 16535 896 48194 50384 19024 49812 18428 49163 52070 32876 18847 13024 48356 18036 49176 46520 48288 47465 12726 47534 14962 12880 19126 12413 51682 17321 49615 45718 47706 347 0 33274 14252 12823 50790 12391 518 52153 15550 48675 426 12875 33600 14114 0 18390 15512 12431 46920 50832 13432 46930 46971 45555 0 48116 18485 18222 13232 49003 45666 45769 17120 49387 47277 0 49187 46776 50165 0 15466 18310 15691 50802 49452 49896 12960 46741 12632 13603 19196 0 45842 16195 47083 50935 13962 14860 19124 47010 12386 13362 0 13977 0 3253886326 +48 703 22393 6788 55000 58833 21647 0 12322 13818 17513 40031 23265 33073 52458 48021 58305 49133 18366 20955 42769 38021 20914 9414 43530 49047 12554 46823 12606 15122 45434 39747 6784 40181 12965 53710 18660 53818 8509 13874 22205 6124 41644 13181 11834 48259 47424 16995 41927 715 0 24083 38475 0 38104 11371 818 0 7052 19901 18464 49415 52818 376 0 24997 10040 9395 44002 0 55697 13803 48982 0 21286 21661 25265 51225 33699 57248 46999 13180 11124 38267 58946 11151 24970 13371 19676 46370 16530 6569 48385 0 22607 0 56718 3238880607 3332529980 +32 52157 36238 34490 60144 9156 3896 20987 21020 34792 7400 36592 33220 34979 0 28670 0 29901 12964 63405 6091 29197 21423 1375 34182 15609 0 24268 62620 40887 54338 34695 24029 51918 32801 47738 1148 39056 3989 26705 56151 9566 30868 4607 11818 12332 0 54436 13280 27335 14878 56693 20275 8438 0 39694 51553 37540 33900 51748 60323 6057 44773 0 39494 1022751636 1292989340 +24 46615 50773 51193 16819 15949 45554 48543 47942 0 49368 17330 15798 14439 33022 0 49179 18974 14660 50197 48200 16171 47863 13864 18403 15526 48788 19137 14077 347 33618 16894 0 50931 14263 15493 18223 14373 19080 48802 47846 50538 50589 45745 15828 48915 13651 46190 12632 1031599902 3273524640 +24 55176 19344 26104 21127 16425 15882 40648 15009 44260 41092 19055 41148 16249 47048 46637 49699 47020 40712 51365 57818 6518 55770 14322 39337 54534 41427 51102 23853 40559 7219 23951 0 38206 45916 0 0 8819 11774 48326 26334 13603 7573 38915 0 9587 0 54655 26102 0 1176153390 +32 29875 56377 12264 40730 16318 38448 29529 37862 0 0 37168 13090 13607 23272 0 27785 231 6848 50216 2114 11032 28363 56818 39732 27478 35437 15303 3197 526 31135 43719 3638 23260 47902 636 28517 55191 26125 8371 61400 43320 57476 4814 22422 50087 5647 0 37070 35817 18595 0 38264 16576 30099 3179 46794 57223 2494 56185 9614 13508 23410 0 4738 3256508209 1294219877 +64 45714 19327 48873 17891 48877 46413 14222 51347 50641 49600 45451 16013 18901 51224 46369 32857 50703 51148 0 0 47394 33425 16937 49283 51396 0 13975 12829 17161 15649 47115 46247 49679 17986 46896 51399 45943 0 14864 15861 18788 14831 17695 16231 46922 16553 15723 51658 5 49395 14993 15795 48330 49828 49189 13070 47447 51148 12988 33067 33121 16644 50189 16005 49177 52102 19365 13868 50077 17765 15393 673 15078 51035 49228 48797 52044 16532 47971 18579 17716 13704 0 0 47527 47355 14058 48971 45426 50955 47937 49528 14834 48874 862 47482 46204 51059 18717 45502 47407 12315 16466 16206 12482 50678 51406 51269 12663 18279 46988 12382 33027 14618 46306 48434 17623 0 48099 47312 45575 52052 50358 33544 47482 0 51584 0 3193200135 3284425437 +48 11788 21368 50251 10284 15217 13881 52748 43729 10328 14617 44340 48376 20172 12999 11724 51709 53538 52581 45009 21309 0 13208 0 10660 13180 21109 52388 18247 20460 19702 53972 50962 19903 47839 20128 47991 46060 44444 11553 18298 45318 45096 14487 20058 54029 11942 45412 53970 47156 11699 45730 46736 15231 21308 0 0 18283 53614 16208 11698 49105 11165 47356 53782 44489 51328 45724 0 0 991 20407 13448 11195 21153 609 15014 46897 12889 953 53276 19683 17799 18750 19527 15337 50936 10503 14242 19593 43681 0 44995 47763 43049 13730 53870 0 1172485274 +16 53132 823 9097 19337 51610 10035 46548 58091 0 50950 6790 0 669 8306 40544 9990 542 11945 16434 39531 48142 0 504 15820 57048 38174 57884 0 11315 0 38644 55346 3256194446 3299110957 +32 59754 9793 57751 43738 60902 40597 24202 19722 58029 36910 5246 48408 40805 57333 24063 51521 0 43517 57119 34199 64396 40421 5053 0 17941 372 11992 31655 45645 11975 0 39754 22491 21866 36830 35734 39527 16902 5214 39681 49152 2701 12816 30030 31216 26157 10129 0 52314 6398 60261 34407 3707 50509 10243 450 6922 394 33104 17676 51770 2975 1663 59647 1035103009 1230140587 +8 50159 46245 20375 0 17566 52218 11181 48733 49245 979 49835 52789 49563 12674 16694 48186 3234037481 3269528418 +8 6958 7219 55861 52427 9116 0 10944 56644 21557 4244 0 14116 30309 0 18525 8033 3210950684 1136462760 +32 7794 63747 6918 49156 21376 0 43528 0 24653 5049 16580 17903 20094 27420 25234 34927 20354 40497 61856 39836 59634 15346 4837 4726 33650 15688 0 27541 31383 27443 53995 27081 2497 41688 37312 39401 31727 23139 35044 52944 8290 48078 41249 57918 35646 45172 63507 43299 7185 1814 21551 50100 38754 10231 48044 61238 63315 3598 23513 23928 4942 24559 10706 38017 1093041316 3416632442 +32 33020 44369 36924 17409 9243 0 40939 22699 63561 16698 60922 51036 50544 27814 4781 20720 6612 2851 50330 11702 353 6115 10229 33165 10861 41376 54849 27110 45724 19725 23729 386 35409 2943 31652 3847 19922 59923 11344 23939 33432 26028 6006 48766 22469 18178 18114 58828 33777 27534 7933 15225 3394 0 57497 60859 59192 40216 27952 22881 18502 0 25187 61757 3150620590 1216412282 +48 45705 15799 25236 15834 11544 21213 33394 18999 9878 26269 5481 26005 821 25681 948 25753 23761 48441 14374 24647 38207 18657 57395 0 43140 40163 53291 44180 0 6246 20737 0 56279 55652 6714 59124 39656 15124 8969 45727 47217 54052 9694 0 5630 45243 5129 46588 0 0 57736 56305 23956 13048 5874 11507 0 8820 548 47334 39436 16512 837 0 0 0 11138 25856 10978 0 346 55679 25309 47632 0 0 21848 0 37909 13632 7420 58773 39009 25196 46081 48538 52767 50195 19567 19414 42687 51607 11623 6868 26299 7574 1057499999 3381113432 +32 50409 20484 33696 52896 51533 18893 14313 17354 19072 46212 18993 15169 54007 10296 49788 48285 52889 12095 52738 49736 45581 17061 18062 10958 54026 10500 18332 44683 17222 52245 13123 46379 47007 50006 20624 46729 53069 19252 54168 12758 49566 11683 19147 50268 48696 33011 10978 51294 20397 21015 20541 48560 20989 50602 48812 47842 52910 46580 12118 48883 52374 0 51184 45680 1047058920 1135557408 +16 14506 51092 19112 17502 17571 45969 0 15572 46627 48042 46736 46063 13612 16627 18934 52223 47612 32774 12886 0 47660 50020 49324 17194 52017 18100 13343 48908 15598 33384 17404 14141 1017204762 1110448139 +48 12627 49421 49316 44271 12589 45287 49111 0 17594 20603 43426 48056 18926 44964 48164 11890 16237 48219 51564 44190 46912 44962 18243 18222 44795 610 16458 16296 13584 19788 0 0 11576 44603 50536 48038 16535 20790 14222 53686 50506 51585 47186 20595 17470 44235 45686 49967 50912 44263 18622 15825 45274 21448 53007 44781 15654 20041 0 11140 17140 14663 13956 0 44008 17207 45605 33216 19416 0 51141 53528 50229 47464 49370 11103 12424 52815 11367 15829 12741 20727 43836 20994 49917 50228 17446 47001 15979 51868 50070 0 51791 46303 48319 10329 3261088278 3268694632 +8 20370 8733 30390 39600 45389 14677 33391 24705 61488 42284 14012 85 18209 36355 6199 46861 0 3362950756 +8 0 7205 41072 40393 45080 25231 54315 14343 16170 33233 9465 19263 14706 17560 0 9566 1015895599 1165034749 +8 51051 33464 49869 10671 47273 45140 19636 0 49175 16329 47905 979 48185 50970 43988 45173 3242926518 1086174643 +16 56350 23521 50225 10220 43262 48976 15153 49194 47140 8319 0 59013 15393 18586 0 18598 26074 46703 43390 13449 0 21432 21699 56167 15633 52318 7515 40454 8993 21716 44567 0 0 3368040174 +64 40699 39321 25387 0 54876 20345 46337 16946 13343 14933 8958 57653 16216 8536 5678 42560 50675 26274 53323 51211 52880 42843 18830 38960 43252 8564 56571 21581 56086 57548 52704 40711 48843 58624 54437 57225 50981 53188 286 41801 13671 38760 12073 0 16681 49407 19587 6063 17361 16829 11548 38266 38340 0 50688 21253 53754 12884 25685 18168 19574 42041 22206 47557 38228 19276 48485 16273 42215 46766 0 55165 59345 49957 41037 51282 58722 48076 57124 15331 6136 18495 0 15561 16389 6193 16283 9035 47114 50241 54442 47986 40071 45565 47684 6920 8645 0 19383 39729 6117 47126 20882 54647 55263 18788 59232 38563 1000 0 51296 52475 40855 11879 41396 7868 23143 57078 43707 47570 13261 21461 24513 42234 6694 25750 41611 50919 1104939468 1225757758 +24 13464 48984 52400 19759 13015 53423 47637 0 43362 0 46312 10942 52957 45717 16819 33160 15391 52593 48937 50512 0 50630 52280 0 14592 19405 19996 21083 0 47008 52071 12605 50915 21444 10879 52519 52711 12209 12630 46557 10779 45975 11810 43388 45485 53119 46780 20233 1014752807 1152564807 +16 57592 45749 804 38340 14865 59832 51366 0 55929 51632 25784 29116 28168 42568 53036 11835 56534 0 59203 40153 27311 54953 0 3823 26039 32858 0 36210 53851 62597 41221 18301 1056893155 3352122790 +48 52126 12000 1428 27401 42358 58441 0 23502 28929 3674 64273 31347 45731 0 38735 20155 55458 15207 57419 45229 28177 59399 54217 40602 60947 25274 43 46715 37710 0 2769 21306 47492 23448 56109 5945 43883 58916 25785 22520 48050 44535 17042 13742 25272 5081 36350 0 40966 7213 40684 8884 1000 63957 43839 0 48800 59358 22242 0 58894 50652 51811 3008 55032 58960 14330 57266 55181 752 28851 33406 34549 42419 48716 19705 2084 52039 24347 30863 27804 33248 34238 38833 59082 29903 39814 33489 13 13934 63373 48776 56883 0 11150 0 3243794481 1265337125 +16 45834 48089 7435 5231 39376 6525 17179 39808 19396 16552 406 12185 0 20451 20253 17422 39622 14301 21157 55312 25904 57783 17968 0 11743 23930 56875 13422 40558 50193 52994 14728 3250374942 3269631028 +64 33473 14746 47656 51820 17739 33596 18460 12547 12521 0 13689 46439 16400 12912 47365 49548 47301 17102 15202 49249 17954 48458 15623 49808 51307 45966 12674 13095 45493 46115 14744 51270 15960 51700 15684 50188 0 0 19329 17988 46389 48795 49689 48567 51295 47378 12907 0 14104 17447 50763 12295 17816 49242 46401 48078 14411 45719 45895 13236 33519 0 18933 13126 47203 46248 14037 17068 49013 45439 16073 52027 16250 51397 0 16741 12663 48819 14469 0 17553 13207 46891 51041 46399 18167 19420 48661 51181 47882 19305 13867 51117 0 48663 45769 14040 50178 14931 49572 47718 13595 49068 48036 33040 47476 50977 52159 14614 19369 49843 15606 18125 18139 16097 17067 46020 48646 12820 49365 17633 45283 48250 315 14646 46573 45947 51742 1050563293 1124721213 +256 46552 57494 55429 24888 0 20489 60926 13719 62009 58386 46088 50924 39207 18009 22680 27948 17675 55132 48209 31556 14570 61646 27833 46552 45231 14924 26297 9963 10705 8822 38809 37032 49781 22161 51382 51580 6024 0 585 4869 0 20336 7379 60858 29250 49575 6244 0 29261 48132 35510 44722 30852 28652 58998 62496 0 50186 58224 49928 26621 21577 22030 21145 23749 60281 21695 29472 43999 42743 41826 4474 23671 40466 57648 49210 4547 51122 49224 570 14007 4160 0 0 21172 472 37212 11779 0 35753 63306 44705 20288 10980 4138 53060 64254 46851 46717 19780 13809 64065 14269 53082 42752 28853 19157 63424 46541 64189 0 28746 23051 52236 6199 2228 8147 60451 45074 42520 48454 48567 36198 0 0 15008 40244 20396 8182 0 3938 18358 62374 51197 0 15925 9765 20864 2836 21649 33297 34517 43553 15410 48979 28181 12248 45530 50947 20297 51571 49775 30638 0 8342 63720 52861 53461 33552 0 694 31020 54248 52893 10164 30092 37966 48156 46147 0 21036 27777 10155 32807 23258 40649 2663 10161 9252 16151 19789 0 22777 36427 134 27696 7513 26590 6422 0 32789 11631 21791 28843 12143 43743 25124 16879 32798 954 996 57478 31540 49432 10574 10044 26275 26679 15186 9713 28838 8088 18133 37688 31162 53094 4743 29092 36494 18964 11030 36043 0 14556 1791 14012 60027 27691 60591 0 19134 829 53708 31131 56227 18252 5221 24797 47615 50727 37702 14738 9961 2393 7166 59885 14974 59265 44198 44524 38283 7891 52204 48586 46807 28647 0 42129 7042 40371 34117 38309 4719 11033 36430 0 2569 39125 43242 2125 38710 10327 36337 12651 34450 3016 7369 41783 8032 12995 37518 8422 34462 39147 1469 40833 12664 45314 36282 12539 6256 0 6552 40667 36068 0 37344 1451 39325 3238 0 36242 40090 913 3377 6946 10013 7981 43397 0 43160 40291 37699 38927 9104 11535 796 4971 7239 34374 7340 38220 44571 37453 8441 724 807 6130 4741 4643 41989 34833 9463 41747 33681 35892 45425 41771 43797 0 0 3207 35978 413 2470 4082 39755 11898 42589 0 10557 40651 43077 13169 12957 37687 39465 45785 5636 12196 34361 9196 39762 34849 4793 4105 36027 5886 42096 46063 4746 33685 10633 44856 35087 34683 3589 9943 2683 712 9377 9533 40058 34194 44396 1222 4691 6820 1128 913 42759 33808 40009 33743 11874 45312 44894 37396 41333 4747 41991 2303 36744 45880 0 7318 12799 36800 1011 41734 5932 44793 5320 2535 39852 35329 12892 40830 8088 11438 33143 3470 0 42131 8689 32845 1115 4582 0 8444 38859 10319 0 37844 2879 39184 43799 44066 35000 38781 5995 33792 9963 0 43749 39826 42717 6048 65 7823 10308 5630 8627 34044 0 5694 3100 35761 11766 34610 11436 34648 5663 37145 44379 8160 35238 6398 3266 11388 740 392 6584 10828 11214 38496 40523 38049 39171 42557 45275 35613 1061 39894 6083 0 36418 4279 40507 1498 8714 9809 45431 1587 34795 5587 36007 43968 5381 34010 8862 38077 35949 1517 44037 35744 12020 8116 0 870 4671 13248 0 1187022852 +256 0 63910 55418 8688 37344 11923 29953 32888 0 44244 5038 63846 31229 25081 55894 30329 44323 0 7730 30833 8645 62492 35443 13 62964 7900 6805 6051 51810 24555 0 14651 53770 54158 58993 42335 46311 367 16455 50679 5872 45010 24212 55333 33573 55903 18991 15357 58700 0 46474 30018 23348 54720 0 31538 59317 36100 8520 40824 57071 39126 56559 40224 53155 51911 2492 8065 53089 606 1473 11450 51069 45324 50610 27208 63503 49502 23856 47974 29416 26264 51734 13526 50906 13186 10165 20389 48028 58005 59718 1507 20452 12105 177 593 42340 50965 52136 18226 9180 19431 33345 226 6545 6530 492 53940 9571 21872 31211 23897 1164 46326 30386 11024 13053 0 20338 35544 43038 29744 26064 30507 59685 0 55512 5581 56336 29971 49823 0 44636 11521 59094 64496 37148 15502 1529 25225 15434 0 0 43266 47881 7608 0 44813 11610 18298 54435 42462 16426 23928 36771 59252 55995 51579 16598 46694 44978 37197 35261 20490 33780 53456 43178 0 45242 6962 3886 30560 51873 3455 5140 9621 11484 1692 9530 22134 57473 0 46343 41925 6637 4700 0 9293 63600 7978 28964 37890 3396 16409 50087 44900 45720 18518 36500 28631 63321 53227 39772 31719 39724 42199 645 35537 4701 35718 93 43818 26548 45147 33018 1391 10009 19002 26277 0 40967 60649 11783 18239 0 38124 64506 38950 386 56898 52863 52025 18846 35151 0 40026 24507 21427 49708 26808 52289 0 7830 14653 42284 54001 23973 49136 50296 50519 0 12876 60455 56767 61264 5225 44189 41041 0 5870 5166 34177 12095 45657 38844 1705 0 2054 34481 1728 11566 32853 438 41188 3857 2106 11743 10313 0 39014 36035 35856 34664 5741 42905 36162 3067 1725 3709 7166 40280 8314 33733 45853 42737 3353 33081 35038 44279 6227 7028 12346 0 3683 12308 9517 3451 35180 38258 12778 36364 44794 38162 5608 900 40482 8982 5277 37200 16 36597 3637 11422 3945 8938 5879 0 35367 9391 40398 35310 45026 1476 13023 5009 37544 37203 676 5507 45503 37750 1483 36826 12790 39904 250 5582 32840 2021 45203 12569 42355 11370 10547 41715 6123 11676 6805 11464 38152 0 3117 2322 41965 38500 41701 3914 35586 7817 42891 4822 0 6714 5419 6942 44052 34213 34837 41502 6538 4101 39203 786 35476 9941 39080 35969 34619 44897 44459 33126 13100 433 39491 37672 0 37027 42369 4298 8402 44292 12673 39984 11894 2360 3483 3570 13170 5718 36066 36784 1673 40193 36171 10405 38721 9262 39074 43032 2364 142 2849 41498 7266 3964 0 954 40279 4531 0 36213 0 42763 8083 8957 41105 11633 36288 12212 7784 45598 39006 3479 32798 6324 8002 33470 44985 44909 6633 39666 8234 36289 2559 2748 39779 0 11897 599 38423 37924 8633 1024 3224 44174 1461 42183 3359 34428 6967 43273 8692 45756 10676 8636 35105 38124 3748 3833 40447 0 9957 5491 40791 44023 0 45229 35534 12532 39900 35051 6023 44448 32793 0 33923 4690 45657 11699 10967 37512 9298 0 3837 41527 2807 0 0 0 40455 36265 319 0 3332127192 +256 36480 55677 14039 40963 34651 12780 1269 51146 47308 40883 0 10882 37944 1869 47929 14375 59327 0 39347 11922 55080 21373 30438 10885 54001 23570 52293 61984 9151 45780 13690 22961 45051 21861 5522 20630 25417 19533 38409 57017 54969 36795 2805 44610 48431 46006 41820 52794 11838 22672 50055 45134 11486 0 1844 53896 0 39495 35137 0 25306 59724 47957 37409 18388 23911 15900 63824 16743 0 53635 5156 29310 54584 9304 0 33105 24516 50216 50678 21138 21456 6374 22007 38293 39376 27426 24247 20822 49023 41583 25845 55005 61989 52086 0 30837 59773 42018 56530 61820 11907 29705 1481 11077 27551 20076 49188 19646 0 35161 40250 29356 22091 28155 20189 43966 9414 0 22007 9045 56636 8955 59663 43804 26520 32944 440 42647 0 24356 42089 36113 3973 0 5998 12150 38770 12580 63604 37670 23372 58606 55101 15942 27125 15936 26447 61141 61721 47692 64284 35287 47396 49162 13299 24618 16767 13905 29148 0 42163 42373 42982 39563 2534 1537 52910 40788 24184 6369 43318 0 25176 55717 63263 21353 48981 6331 62950 0 39071 7643 2596 0 46219 20054 7799 0 6296 44478 36672 0 16624 56539 44218 35202 22866 996 0 58884 15949 527 53387 10674 22037 43535 1362 10173 39885 46837 63000 63036 56054 26363 10643 63612 4033 54334 23841 22973 908 53781 33360 46083 61523 47962 48537 17654 3372 30826 21785 17180 21346 63872 36655 15378 18944 36514 0 28930 7532 30227 22098 40744 0 33419 51470 17181 28646 52665 60259 2180 1550 44188 50445 42292 7291 33715 36447 36432 12821 40323 4255 6696 34605 0 3150 39736 38107 43849 36885 5145 34652 670 9825 2669 1314 2511 8809 6086 0 41261 2180 33298 5887 6049 40999 36962 39954 39667 34928 12723 39661 0 43528 42028 3040 37242 2425 8561 1696 5078 1689 4542 7451 0 43295 4350 42214 33827 0 9352 43700 38043 11131 0 4568 12192 37818 42839 42630 7932 1480 0 3375 35641 41279 42441 33699 10519 0 0 7415 34135 35386 9890 43531 43073 35653 45674 9472 34236 6487 35268 0 41950 40419 6148 36078 0 4970 11235 398 32876 5069 164 41838 6422 155 42044 37517 1454 43979 3303 0 5671 42898 3070 612 39393 0 45103 34475 45546 4143 41846 4770 8627 1560 45801 186 2700 6011 46001 1831 39496 9436 36869 34120 7042 10343 7572 11402 12071 7863 4822 8049 4323 1437 40290 8677 12049 8164 37861 33770 44833 43794 3615 45777 9868 5507 8311 39041 3135 7945 0 7327 44281 43529 7925 33175 4329 45509 0 41391 1980 8696 0 44687 40873 41965 0 43838 37178 46064 4880 11976 34996 9275 0 42878 5805 13101 2877 10594 11996 11732 2057 6193 35886 43472 39417 37900 44571 12858 3951 12857 3475 10695 4021 45463 6963 32954 41012 3047 3703 11010 35954 2835 37384 42430 3830 0 34009 0 0 4082 43831 41837 3916 42969 42524 45147 43486 5353 36207 12021 2920 34732 4739 36417 38953 6034 0 42772 40457 2644 0 8337 44103 12253 0 1188 13195 11831 5018 37258 329 543 3309 5070 0 1177481259 +256 12277 9869 16595 60809 3766 191 41421 24552 47335 48207 5331 16402 28645 38317 35512 7634 54061 12619 56449 49441 50555 40841 40082 10773 47886 46494 17087 24709 5376 0 56192 20238 14365 223 61318 49649 34987 22796 14379 39354 48822 2182 55415 22793 36317 7003 33332 43677 25318 22395 45791 34274 19765 51923 54112 39571 0 28600 57391 27527 53646 40927 0 0 63790 54368 58251 41863 64317 54412 53702 22604 223 0 15470 5111 8496 16533 41060 35227 48434 36439 23249 556 10401 53347 5944 6583 31574 53159 937 25020 17662 60381 63444 21561 36175 6931 55641 10139 0 27990 21668 25195 0 7113 20474 36235 60362 11068 17656 42106 17897 25988 3156 23352 50345 17548 18516 56618 59116 29611 41345 60948 15334 57537 2618 11976 31217 35338 39117 59088 15237 0 0 4375 43362 59465 24388 54276 11490 27127 22804 43491 1374 0 11581 15014 30216 24112 37167 21660 51031 61436 0 52786 0 0 53629 0 49760 57437 3749 52173 26020 0 39229 62694 21432 44595 55288 28092 0 29193 38229 46613 51852 52440 0 34527 28404 24329 12740 44475 47206 45591 18193 59203 39428 57134 37265 33002 0 21865 17551 22431 7298 0 17374 30824 57952 61097 46920 24258 5106 20337 52908 1117 17816 22526 27719 8921 64240 16783 55246 37294 60151 18023 21437 55086 7234 60528 0 880 60124 27255 13663 52199 19677 949 13059 14708 2750 2385 7584 52106 35356 49650 63282 49642 33539 49584 64048 0 31254 30757 59456 44125 62436 30062 0 22529 52541 31626 43012 47518 41184 10257 8489 4169 40024 4266 39160 41408 6960 41612 45246 43106 38377 45747 41944 0 36347 4877 39556 12832 0 2431 35492 4785 4302 10342 1150 11770 12224 36643 12186 5452 6084 1602 9513 34292 8648 10115 37368 45548 35384 3478 43666 45081 41051 0 39958 0 34042 36695 911 12695 7659 9467 4887 40742 33411 42527 12906 45175 0 1428 5813 6971 11124 37735 11863 42726 1837 1905 596 44057 41328 45367 1885 40430 40001 42201 45488 11372 13119 36465 42890 42471 41845 4671 35994 42834 10294 38249 35254 5649 2660 7290 12470 40739 35156 38718 39929 45364 34151 37947 34035 35047 9182 12740 7965 39327 1046 34019 41644 36924 34064 12346 37212 35354 38222 10637 11398 12735 0 3743 397 0 33577 45097 4356 34182 34335 35540 42044 39974 41375 41606 37112 8160 1685 36461 5099 9526 1581 41788 39370 43238 5357 5198 45989 4276 11406 7829 38398 4558 32789 45405 9136 40185 35750 37194 9267 45154 40487 41036 0 11471 232 39146 8478 3782 12421 39794 33927 42041 41706 44520 36542 43850 44696 10169 40667 5811 3511 37023 34405 11517 2761 0 9046 43300 44403 1991 1981 34124 8673 7963 4665 0 11793 41947 6211 13028 10211 3309 38227 9804 43232 36293 9534 3478 35497 790 38873 12068 0 1903 41126 33434 44583 11221 9136 1501 2220 45904 43178 35106 10206 38928 34888 5779 4880 41266 8080 36619 1342 40674 12826 45950 11526 5035 62 41491 13177 3080 1524 34027 8896 12250 34307 1308 9430 36631 4854 44603 7234 0 11274 2916 0 1175551439 +256 26639 48855 54929 32907 63260 51572 46554 554 48040 48852 17841 55405 21230 30737 58439 24687 11496 12340 61839 54704 28927 50469 49939 2454 54750 24173 33325 56649 48035 13329 42794 58101 60176 21743 10204 60735 0 34684 22987 15096 32970 2152 40836 33156 43118 2348 33370 17816 9926 18433 12935 16615 42690 33454 13012 30586 34904 61523 448 32935 37072 44065 0 17596 35363 1374 55087 24665 18956 24428 62167 58602 61079 50085 29091 9069 50997 30180 15092 35119 45107 26154 48173 5717 28823 23518 35892 47265 812 36581 7432 6186 39064 3701 35874 14779 9581 33517 31009 61875 41458 7387 22882 22303 24291 62936 39441 692 0 0 5293 62532 49469 55009 277 49790 18934 48448 0 54828 1702 46692 49227 37742 0 2478 41500 60450 21892 34149 41242 58146 9682 34997 51264 7010 6190 36886 10297 58858 60390 0 49068 0 0 55801 39170 60047 58086 47657 7098 39695 6914 45477 52004 19555 64505 54009 464 20087 41658 54027 55938 24542 23076 24507 38454 0 11305 24157 8538 0 61081 3863 18693 62499 34728 39875 51564 61372 33094 57706 7483 57939 38992 29661 55091 25382 51377 26323 41771 20859 37099 24380 21500 49068 15608 63549 14084 5904 31693 58106 45654 30703 33503 950 9314 57331 7902 459 11805 25900 20440 40834 30258 11059 16333 27926 43300 22038 12603 23267 52802 0 40637 29637 24426 45326 22163 44252 8230 867 2881 1696 48216 9779 21263 42975 40406 33301 19828 28769 8588 55202 39155 64477 43250 28761 1554 53786 27238 46271 23424 19638 8242 37676 39154 35906 6573 41621 0 13063 8704 1071 9690 38742 40657 12986 34522 38423 8339 8475 12464 9623 34725 44111 3579 12067 38943 34422 43510 6867 8347 43810 974 44011 3300 34289 3741 33329 39838 44855 11484 6118 36598 12654 11283 384 9414 41842 42877 42152 0 7037 10500 36029 39396 44808 44816 35223 3836 38157 3966 36910 0 6992 38004 38098 3046 38904 7749 44467 35180 37242 11307 10560 40092 34926 44277 3101 11685 44273 3436 8904 0 43295 12899 3566 44583 8443 44950 43707 33827 35119 43360 7084 9462 41076 40039 8489 12999 40636 3374 36822 33896 9862 6073 7224 4561 2026 0 41085 40661 35014 9701 36734 0 4488 41661 0 44692 3444 40095 34989 34862 41433 9503 36848 38546 6587 11936 0 34215 11356 897 38969 37925 45703 44845 10550 36500 36333 42969 11058 8173 9954 44306 38763 0 11376 4570 36086 34402 10518 7719 119 12854 37876 5151 7323 0 10954 12532 42529 37607 0 43723 2997 0 40422 33415 5870 7128 38682 43562 39342 39320 1375 44239 39434 34217 42369 38438 10427 6125 2014 2754 7985 3720 8581 38609 38794 9789 0 39114 45786 8092 43152 11726 4859 11391 37746 33446 33675 3800 11589 9788 4072 32929 45643 10303 2037 42228 6443 0 3555 34540 2908 5598 39244 5627 2083 38150 11088 39541 1497 33334 34224 4874 10595 1093 10630 43474 13019 44109 3483 2555 708 40303 35510 0 3159 37441 5798 3736 41470 33910 12602 9439 12149 35697 32894 7394 42499 12746 7100 39514 39979 37032 34948 37249 12182 0 3324760535 +256 52947 0 22472 55455 12072 47028 32827 40047 42470 1992 0 43035 8806 18784 34140 3011 61525 50624 23338 30998 47013 22292 55999 0 6352 62997 46003 47533 36022 50523 51467 41836 34270 51870 53876 0 31295 17171 27751 10249 55357 33792 46117 64126 0 38248 31237 44146 5420 14928 23296 59814 33700 6943 63678 25837 10947 0 9803 54027 48943 4541 36354 21628 53622 24156 5094 6399 46203 12608 33408 54611 28964 0 27127 34166 33141 27491 37080 64025 31291 40017 48794 5853 22509 33479 0 62565 35880 35705 43212 14542 0 61750 58592 20764 0 30234 44801 0 57843 44297 21015 3972 35314 48159 36222 14775 51920 17513 48505 47496 17754 48845 24258 35914 18180 52141 61853 64359 30352 55735 14856 64397 54609 43747 48877 35973 35843 46981 610 0 59484 34906 31667 51806 31715 4904 37534 46391 27787 59272 19187 1989 39364 60336 52293 19758 37922 11059 16739 54223 54863 16108 52785 10319 7663 51452 16863 30586 53801 43563 45166 0 26401 62873 35322 21792 44041 21003 24156 51708 4231 9767 15402 24191 30452 7559 15128 17158 23701 26564 23540 42957 0 44018 0 3523 20877 55513 15322 20004 24075 821 20573 0 32825 1498 54472 39561 24156 37066 49975 61103 61527 39146 17873 28556 49857 62541 20739 55078 37383 48541 57472 13793 9754 58576 0 0 173 7346 2467 3292 58633 25407 62538 40877 64471 19515 61597 53724 52798 37254 14365 11520 37795 28158 14554 0 63127 38006 33338 1413 40086 40508 21680 27213 62710 167 27323 39187 10858 3809 54768 0 1470 1921 36773 0 0 2704 12730 988 6647 36201 8742 1647 1901 13221 44580 0 44218 10214 33674 38174 45808 42254 1303 6642 41656 45364 41444 10880 0 1591 42588 39648 43678 0 7615 0 12658 36853 0 5969 44704 1368 7149 1282 9827 34985 43043 39866 10565 38108 2037 2216 35100 39143 5418 39343 45699 12481 1834 34496 6808 0 3448 9639 44250 12391 37779 42428 7064 9287 0 35927 11060 10489 11295 0 3318 34410 4353 0 44780 0 2508 7077 37964 43115 33117 2849 0 12955 11055 41076 9922 37953 38121 2402 8921 0 0 42102 154 0 41605 41590 38516 12678 37619 45651 43539 0 39484 35734 36395 35747 34317 41432 45268 45465 12228 12111 6130 33856 45685 7884 41626 8170 35101 2324 0 42517 11996 7598 46072 39805 0 39776 2688 0 42456 37338 36859 36773 38839 37590 11816 3311 8922 5237 3656 44692 9888 35941 43156 37899 35327 38836 0 43843 36361 44919 39544 4447 33358 37797 44660 33221 3820 1903 40109 33240 45068 33941 0 10819 37767 45339 12208 8166 41309 12739 33022 1544 8900 10259 40516 3096 36688 4198 37080 857 222 43693 2544 3957 8834 0 4743 45085 0 10707 33465 44672 39602 7407 44607 9789 8658 38324 0 6359 42809 4994 8063 329 37606 11325 36870 37227 1467 1785 2115 45285 0 0 45078 8466 5127 7024 37913 39252 7722 39635 8468 38667 5591 43178 9325 40134 43177 3148 6269 42357 45054 38412 37291 8377 45426 9918 35031 0 11275 0 41620 9796 13178 40982 0 3283459944 +256 57048 30589 23830 33175 37505 58964 52661 59587 51776 49922 58153 22971 35590 35149 56011 0 15353 40964 28952 18819 23417 33328 35818 28041 48538 62347 34983 31078 18007 48945 3289 995 0 17025 21059 56569 64442 0 31648 48336 36598 0 23191 39354 49274 46893 6152 31649 59033 41899 56966 60227 21014 30236 51843 22289 7059 0 26697 22376 56560 18059 46597 5725 29112 59001 8830 38586 14048 41001 55769 0 49939 56543 41379 2928 29392 59303 29161 4200 4594 19937 34043 14307 0 28086 34874 14723 59247 37453 20459 35683 26986 25826 38856 23460 287 62044 23487 46846 27626 22402 30760 44749 496 50848 55791 41957 14893 3420 19798 34777 25169 48446 272 26907 32902 42350 28600 16127 17270 20334 60674 0 58738 36820 38824 32996 29353 35074 18950 17420 25436 36473 13810 61480 51457 0 29991 42825 5112 20192 15661 59447 19273 41403 20008 0 14960 45803 16690 15526 56087 52062 4999 60001 18954 55089 0 61982 29527 44511 23763 30488 64004 60709 55096 51041 7931 16048 37352 15300 48018 8231 47579 44586 45028 0 31306 28568 8249 43001 13747 57550 46500 17117 14578 45778 62967 41946 0 48224 51369 37889 12418 22301 5650 44966 29001 38623 41218 2470 19887 28870 41676 28187 34997 22559 38117 21993 19913 35485 28826 24701 60975 12091 1733 0 508 54065 40046 21801 45324 20813 32906 814 41899 10349 48207 18437 17733 41037 6770 26367 41630 42979 7602 58988 4547 57185 4431 28622 9613 63510 42355 54966 38928 40198 36595 11732 18783 24453 38205 39614 12711 26286 41051 12306 37140 8804 40948 0 44379 8470 0 35876 34122 12540 41894 9454 42900 42305 6657 33858 1423 1574 3742 9285 45767 35576 45878 10484 10274 39719 642 39073 33236 36022 10048 10772 37021 45568 38490 35406 7728 33928 2109 4486 5212 35766 44281 715 33233 9150 33251 37219 0 9015 38962 9654 35099 41444 2890 40934 42406 3740 40708 4392 7420 42166 2089 43709 10306 39791 33509 0 44403 37342 6157 38290 0 45343 37369 43287 2071 8140 45897 9870 0 35308 6521 45596 40712 41693 1682 33999 47 42790 43360 11329 40226 2840 2037 36086 43633 9797 39583 34517 44353 6569 11455 35151 38710 35060 36506 45534 40698 42081 42056 12469 312 34757 2848 0 1201 1227 42335 12534 34948 44069 39097 35633 1804 1429 34109 0 34051 45223 35521 7411 428 13025 3534 37744 38636 13205 33219 16 45352 37597 36700 39061 39033 7771 0 11321 38739 41095 39475 6649 36789 33640 2596 4517 36447 6066 0 10207 1916 37372 12656 42437 5197 3102 34089 1462 3872 38844 10606 2579 11502 10938 37944 34725 40946 42615 0 44190 44579 3153 38835 42943 34208 1277 1371 41092 41877 34850 8343 3319 0 39282 35947 42116 36362 2004 11824 718 8715 9513 0 8043 6380 44820 33208 0 9537 11177 4296 0 42078 37418 40515 44557 1764 0 44364 12915 5247 45897 2724 35186 37417 6020 37612 0 0 45205 46011 40088 45015 41910 36584 12852 39289 0 0 33147 45456 13263 39825 7096 10868 4216 36972 40235 1623 11335 42589 833 41343 2325 0 3330886365 +256 4924 41070 7165 12430 37274 2748 8073 20613 51666 33081 18987 6998 54273 6437 9683 0 17721 0 52466 49558 19428 0 54979 41927 58460 27830 48019 42051 13284 913 63606 31521 19100 35960 0 2889 33051 55939 28832 34651 8097 18326 29207 10582 53626 5534 1558 37815 58106 64370 33336 27271 27323 5900 2512 1792 27596 32949 17783 26199 22857 25968 55354 13315 30416 8123 54480 27191 27204 42675 35481 58502 10885 53 2700 2431 38776 59808 29494 0 13768 34928 2543 1827 16938 55522 3000 0 14777 15289 64062 11109 63314 34058 21870 26534 50514 63303 58389 0 19135 49243 5174 57028 33560 28987 2040 23812 8786 34845 31680 33260 44014 40274 0 12831 0 21427 51229 38657 35632 48367 10549 36818 16562 48463 18519 6217 33668 5097 34303 0 44654 0 33419 6855 42578 6660 44325 61367 19512 56383 20795 0 33204 55180 28771 29143 27945 13284 24323 0 2037 35379 5843 24011 33460 24442 35115 18612 27767 0 40713 55873 0 25063 24931 50061 13353 54924 53353 13222 31505 44404 0 13726 0 8190 3730 38949 13071 752 5395 46006 60719 60036 0 44063 23632 5699 12581 53785 0 11230 28179 38300 44436 11707 29206 0 33602 48813 5080 63416 8886 62607 22564 23061 49352 45527 50699 45532 36686 57544 38082 60609 57062 28738 22991 14058 49323 4982 2388 28290 43265 54054 39579 48842 36727 42715 12958 14132 57393 26227 329 0 41970 18706 55844 5124 17397 31548 0 34835 47288 49985 33660 45969 3130 33290 8564 27982 10450 60038 59074 41396 3293 4672 32943 45459 0 3666 9169 37748 44615 12465 11089 6411 45753 35289 4785 36765 37268 0 43635 8799 10822 39340 34974 42233 12737 68 7603 10989 37722 0 9095 37300 40908 45063 40629 5303 11541 40001 37440 0 43826 8769 39986 0 40439 33666 0 44381 37821 6772 42913 146 38689 12872 3498 42345 9809 37474 6827 8364 5483 34038 38499 37935 1427 2958 43585 32811 0 2322 5082 0 2252 9514 32942 35685 42469 33647 45495 12336 10286 41600 37296 36997 36333 43540 45533 37987 11068 10579 37300 37008 8671 39670 7605 0 34778 0 34269 12721 3302 13090 43945 43645 35351 37323 11967 37144 13131 8047 43047 43580 37929 41701 11313 0 2772 0 42515 12346 3488 12978 10669 35544 35165 43077 41902 42735 41444 5955 12284 6003 0 13133 10950 45834 0 0 39700 9956 37756 0 100 1608 35695 1015 45131 42061 4107 2460 1707 12264 9769 45515 10995 39354 11730 4079 2712 8102 43264 35338 2185 39159 5374 9542 0 2277 36247 34871 40456 45346 12662 37626 36047 44382 4021 37561 36797 39922 44061 9181 9305 9429 5501 33233 45203 41039 3360 11881 11454 41357 44554 43850 38623 34345 34533 39049 0 3508 0 43230 0 37457 34757 12467 221 9758 10853 10035 43783 41388 416 5357 34749 10077 5934 5917 11252 34065 6438 44973 8597 44812 36768 45353 2632 43911 44836 2832 0 35398 34042 0 5778 4760 10644 38686 5019 1238 38418 36900 4795 2423 1793 37249 38673 11115 7752 45387 1490 6320 36452 0 44441 39900 0 3298290907 +256 0 58658 63133 1370 14303 49868 24156 15783 51343 38349 34377 7658 0 11267 45691 16653 16876 16135 46185 50837 0 55894 49526 40951 61423 0 47467 0 17319 44718 22504 7805 28705 19337 10136 33781 46369 46849 44121 28113 63378 12140 37457 61581 33554 0 42402 0 63100 46203 49587 52752 0 17457 10254 27400 29418 40872 9577 33822 13173 57794 0 60836 10207 64481 52561 8028 47482 56098 52575 15702 0 21190 54124 5874 35604 63590 45933 0 0 60224 17213 5214 7357 4812 9028 5035 48884 0 59822 16764 24978 5825 39942 52532 5151 36886 14860 43765 51227 21354 52738 2388 29818 36195 10969 56495 6509 64045 15847 29687 8660 2872 3629 0 43859 7476 21457 19755 48805 21420 2345 29546 47931 43114 60088 7054 34277 26507 59817 5252 9073 4148 42954 15501 63481 28696 50482 30449 0 20250 11009 21683 39284 41250 0 32904 49596 55375 37173 29461 9072 21615 11571 36816 50830 29064 20864 59956 57891 0 28574 17979 35760 63626 48393 53834 57298 59623 40248 29514 49218 17639 40878 101 28461 35657 29326 50085 7658 0 7623 53178 38089 26332 55540 5445 31370 27943 26206 31225 38040 13511 49376 15317 30359 49417 39615 14712 26327 39820 847 27404 30591 60087 19493 35645 14796 62750 21705 15601 19069 28134 14465 28940 19719 57532 43507 40761 57234 60361 41428 27919 33705 31377 55155 61882 53944 62819 25213 48356 8483 5494 41691 44588 37502 42466 61228 51794 32934 38230 50386 39576 46973 28909 2609 49464 54009 14045 48867 21481 17407 33291 36188 6709 0 40574 35378 35588 35168 37421 9412 45938 0 8251 3313 11543 0 41431 2603 10410 0 7668 37227 43797 43130 8346 0 4228 34252 42036 0 33160 45511 42382 41391 45445 1601 3271 33593 43656 36340 5398 1196 7864 43447 8240 7302 44393 0 12970 8884 34803 5443 34234 4372 42812 43558 40747 41412 39971 3717 39017 7273 34197 7031 12539 12324 8843 11926 1720 1503 10868 404 44250 34272 3710 12721 40930 1500 11957 11045 39600 9603 10712 5767 34089 43550 38116 44099 37612 2753 39604 8192 7717 36908 43759 40352 44406 0 4168 8077 37171 4699 0 34618 46016 4176 10286 6332 40775 5433 2569 34236 11727 11294 33166 10024 43561 3151 3664 44393 8572 5997 11834 8201 39289 5692 12675 11994 36531 3570 12068 41675 1744 7713 33227 8007 42750 11877 40098 0 11439 9798 2981 0 10536 2463 0 34260 3848 4579 7246 36533 38599 44368 11239 13006 37167 3289 40666 4024 4692 37909 0 41963 36624 11316 35122 36687 5719 39884 40751 39848 134 6026 35780 9096 6604 45433 33102 44587 13310 12614 10170 6985 6616 2144 8229 3654 41266 34696 0 12656 6897 12599 0 41311 5606 43137 536 3647 11420 1909 36286 13103 0 5947 38943 43535 5694 42427 2419 3770 40343 34201 9038 12081 33025 36667 2968 39858 45725 45513 3901 44130 5644 38320 13203 9109 43307 41252 2496 1113 2302 11439 41438 45796 4721 36464 41740 10385 13213 45569 2002 5056 35358 33768 1826 2117 34329 38643 35234 3396 4542 0 34409 36441 32784 1684 38483 0 1179039425 +256 2956 63218 47481 7273 13846 13484 28321 0 0 61036 48595 36090 9451 40427 46434 0 0 63976 53804 1124 18340 40914 15932 33105 9672 41583 11271 3461 54850 61833 51334 26033 18946 17518 17113 15816 12321 28658 49128 4489 0 34445 62711 36541 25354 52663 16463 37456 49756 0 35843 11699 62187 30391 56043 48681 10026 17209 15779 51282 40024 63891 49935 28346 33083 7824 23942 33052 59300 26624 24366 0 0 63685 41060 48382 1194 48871 49795 0 59235 45499 8274 3520 56730 40063 27730 36723 37787 16759 61020 60059 60215 61051 28210 15348 53229 20820 19270 27623 7577 12222 37984 62393 35058 34511 50966 14646 37060 40700 9923 19422 26643 47022 26596 32930 61970 34873 12637 23288 12743 33405 46964 51376 26042 31278 26792 35117 39094 21619 40312 41728 25509 7390 62866 45289 55530 58376 0 7511 34427 44283 49151 40694 0 2201 3699 59825 37689 8468 6739 14094 14960 16632 27004 18786 31713 52194 37786 61059 8649 59721 4190 0 52618 41216 4547 50250 58957 10972 40251 7320 12190 37102 48772 17365 45741 0 33092 0 45668 60320 45861 0 41198 63704 54840 50062 28660 27276 21839 5889 0 27017 62052 13484 63430 16905 5536 17648 9578 7353 35329 4660 37047 52442 48937 22255 47261 37911 12010 27352 48163 7041 1789 51050 6505 17490 25837 34825 59107 11283 57290 18952 1621 64332 33204 0 14748 22181 43546 17462 25712 62057 43187 63224 14570 62235 33593 55080 59626 57506 0 0 54697 15947 24461 8741 4815 56145 36432 61063 42111 59147 19301 60630 37793 36997 0 7002 419 34857 35490 34454 35498 5374 34661 3699 3250 40326 38217 1217 12576 2612 36194 32922 0 6524 6761 11360 34765 4348 4878 0 9118 10745 3858 37533 35511 38423 35395 41394 40513 39555 41920 44626 11928 0 4981 5714 44617 10823 2148 0 852 0 11581 901 5635 42977 39299 45887 37407 34161 0 40057 4375 34665 6380 34678 9637 45195 12307 44149 9770 4425 43946 0 7702 3104 8744 45200 11301 41449 7988 0 42165 3046 2713 5853 45914 9659 9366 0 2989 4682 5757 5537 8061 43914 37704 0 43160 11758 0 6184 8813 7732 35067 42328 38920 5185 10432 44054 2073 7142 0 8755 7790 45842 37408 36982 43254 546 12499 45914 44098 11538 5568 10790 10417 4700 6389 0 12881 34168 0 12531 1204 36994 4103 39949 7725 11426 6621 39322 12124 41432 34465 3847 35437 3574 10960 2704 0 6672 36033 40538 3589 6832 3816 40291 38595 45766 7361 40795 40113 39356 4178 7819 38353 43400 33148 43915 5490 1854 36501 45056 39802 34299 11141 2575 35821 5796 38354 1471 5316 0 3466 5883 2338 1072 9228 36939 10876 41989 38256 4028 6266 8465 10293 4937 0 2726 12740 11509 36906 45518 8221 40553 45281 2741 10354 37985 44435 37294 9459 1748 39262 1774 35880 4266 4353 40942 35502 2637 7046 3540 6707 35094 11103 4627 8907 35559 45382 2774 6570 2667 35626 3 5898 9869 0 854 42609 4620 45909 11978 13054 43480 45216 7389 0 1964 40729 45401 7686 10744 45234 12299 7985 40890 0 3296910043 +256 14163 6296 24405 26577 29175 43474 11842 17484 54803 519 5570 52440 43809 27385 8535 8976 15904 11409 0 14477 60248 13675 39417 1730 30531 61836 57021 7937 42077 35034 0 52883 34964 33261 22298 54197 20046 36232 15274 34073 64101 58401 20815 41790 1289 35744 41352 26235 51604 0 11921 20001 62630 40620 59646 29804 36663 52442 0 34267 43537 330 50893 62203 52302 40431 61898 8217 0 40430 51805 15779 6469 64496 13603 3659 23359 37430 5037 17440 18837 56084 55965 0 8920 0 61727 214 26937 6037 0 22140 62913 25359 0 62710 61162 8387 657 12893 31380 50542 0 25234 6159 36044 27329 63064 27612 61550 25704 36300 0 12753 26550 14981 10561 50114 57744 28168 43323 1978 2989 0 21408 49603 6764 53279 26287 58917 34118 6470 10135 0 0 61067 0 10709 55213 0 52096 54583 0 40369 51990 59789 15272 1058 27759 3124 20707 54841 54675 0 27902 4786 19347 29818 22764 4204 10878 4347 9571 52531 47470 23137 11081 37935 42059 40866 33851 28514 38781 7010 0 41224 21106 59840 17961 19354 37860 279 37180 34453 7825 44901 45992 50561 25 33742 43075 11207 64035 41776 15177 17990 20589 19090 17424 7054 45368 45867 51781 0 34693 23636 63715 53325 21125 0 53509 808 45136 278 9080 49750 24062 27807 27701 56525 17801 14213 21215 35706 45406 15295 9269 2783 5085 9209 27332 48827 20952 56951 27353 27645 3668 17972 0 33858 36203 33323 501 26084 49874 17447 49781 53311 0 51532 54708 14527 44292 21194 4560 28143 35323 37406 41492 8915 34232 44151 2085 1134 11429 0 0 45118 39979 45315 3717 9092 0 34379 45843 0 0 10145 564 0 0 34812 12415 5588 13007 41746 45594 7663 35201 35175 0 34809 39145 37974 42341 43162 3008 44883 0 9186 39202 11750 5787 2466 43787 42361 32975 11337 37030 13141 40985 2441 42747 40480 42437 9217 45533 1294 4336 4391 34555 35829 7928 1042 2311 10082 36628 12749 0 39352 7164 0 45342 45977 42577 0 44363 35183 1814 2421 35477 32993 3157 36271 41045 8906 4972 41033 37430 9584 6278 12034 42907 10053 5943 7703 34723 44680 36423 0 45764 41371 40571 6957 1663 32798 34064 33091 12666 11398 13126 37863 1586 37898 1369 37623 0 0 6223 2705 37854 8488 2533 4998 1163 11103 34309 4753 34872 45590 10769 37719 0 37706 42517 8575 429 5587 316 6376 42155 44404 39076 531 6311 33148 7786 3505 37573 12142 7213 40326 9736 2029 4138 6773 0 2943 8686 38355 43973 293 42005 43285 9604 2872 36974 2327 12396 37034 10447 0 45629 44909 36395 44426 46002 9860 40678 41395 36470 34045 11868 38998 3372 4344 1346 4599 4278 0 970 5920 9757 0 37371 40456 12202 35585 33575 7889 2180 45534 5941 4997 36889 11510 41931 12144 43259 36289 41705 40556 36892 40205 4206 43706 3148 34497 8930 4055 43845 39687 34409 13242 12409 38169 4883 40336 41388 39575 2607 6418 5723 1605 39194 39024 41566 12821 8426 45959 9760 353 4015 34974 1290 0 1358 45598 0 12177 12534 12473 0 3297723162 +256 43501 60062 58274 54264 54058 23756 12045 55335 40199 43620 935 62194 49946 10066 16174 13750 25160 62206 38315 11013 3769 4421 19985 0 32953 19232 13975 27385 55096 14554 21244 58701 40739 44214 666 48477 18570 0 40405 9265 43448 61260 58282 12031 41832 5701 49616 35717 47029 7569 1514 41812 30784 15845 13051 0 23460 3139 43332 5648 52091 28266 3136 41381 28614 19533 25019 50288 0 14620 62743 0 29332 5042 2313 25966 7711 0 4508 28015 16972 0 36649 33370 17465 26016 39851 9363 21411 27237 45841 16381 61710 26025 6235 46567 54511 13463 3131 62422 36851 63850 7640 36537 21409 22283 28921 22570 39087 51956 23876 45037 0 35057 21006 42899 11443 62081 48722 28228 51517 11647 10135 54506 45558 35044 3587 791 17686 16135 37898 14239 8795 29226 36138 47859 25637 44480 3680 15573 0 26571 50313 30739 20935 4089 33651 0 14445 36886 16553 15575 34227 1053 55577 11091 36991 42185 0 40439 26878 64209 14499 6706 0 20257 51019 5118 0 28211 18685 50126 38952 60936 1105 97 45994 34361 63347 61565 12182 46597 61970 31565 38749 51200 27111 0 25599 62249 61111 408 52025 22083 54315 30106 9156 17051 13762 14874 20235 46825 26655 57274 42432 15414 39908 46825 37827 0 2869 6399 18426 27659 18806 50469 1974 48953 40527 54714 5417 11480 94 26749 64004 36925 39703 43929 21072 0 45790 30082 56863 34527 14689 8926 38231 24842 43699 6529 57412 45629 60657 64274 26642 5139 28665 24984 0 62004 2134 60872 19847 49837 57427 375 7945 7923 4477 44115 36852 37229 7961 0 41598 45155 37660 13298 38905 36188 36913 35938 5368 34753 2642 6577 0 13147 42244 34066 37367 41300 3580 12507 38017 1288 0 10099 34592 42105 2961 34076 43701 7305 12281 34058 4357 45813 590 5348 5588 6511 45345 10196 9215 2037 8422 37230 45262 38411 44387 39127 40828 37708 42679 42607 8779 39474 598 37300 34116 0 0 43005 2189 42231 3554 43135 34797 482 11189 7661 12277 38043 7844 12281 6819 44501 34865 0 40110 8383 34105 39647 43090 40981 35535 0 0 37970 2292 34849 11280 9045 7011 40447 0 311 7238 9300 39052 40668 12257 38753 11656 11158 11664 12859 40755 0 11741 1361 45392 44471 43589 11817 12500 41367 5806 8656 2006 1161 8027 4438 6854 45516 35865 34021 2297 36188 34797 10427 4270 11132 1069 45892 9574 42661 7012 39176 4253 4564 5856 34131 40202 35257 2190 40169 44623 12951 34538 3680 2680 7893 37812 2882 12248 2573 33016 13287 6618 306 0 13264 37102 5346 42349 33407 0 35218 38155 1713 9918 36381 6951 9351 44810 2879 33006 4787 36863 8518 3408 38401 35481 6586 44217 42221 42482 5841 13069 36975 44960 35558 41754 42776 0 10779 11035 0 3160 1228 44617 2434 0 7552 35261 4946 39948 806 10904 34215 44862 11319 0 42018 37251 1047 3749 3050 45608 33191 38250 8328 0 41470 40766 5148 44650 11423 2717 9150 7304 32944 8861 45226 45586 6227 3527 0 36752 42385 11936 10850 34684 10176 4749 40251 37929 1074 1373 43927 0 1173735281 +2 15360 15360 15360 48128 0 0 +3 16384 17408 18432 49664 17664 48128 3236954112 3217031168 +2 1 3 16384 16384 0 889192448 +2 0 0 0 0 1078984704 1078984704 +2 22080 22080 22080 15360 0 1176358912 +10 26576 15360 15360 15360 15360 15360 15360 15360 15360 15360 26576 15872 15872 15872 15872 15872 15872 15872 15872 15872 0 1249125430 diff --git a/zk-pow/src/api/fp16/testdata/a100_dot_vectors_k1024.txt b/zk-pow/src/api/fp16/testdata/a100_dot_vectors_k1024.txt new file mode 100644 index 000000000..34af43b5e --- /dev/null +++ b/zk-pow/src/api/fp16/testdata/a100_dot_vectors_k1024.txt @@ -0,0 +1,277 @@ +# A100 FP16 dot-product reference vectors (hardware-captured on sm_80). +# Generated by docs/fp16_scheme/validation/generate_and_capture.py --seed 0xa100 +# Device: run on NVIDIA sm_80 (A100/GA100/CMP 170HX) via real mma.sync.m16n8k16.f32.f16. +# Covers k up to 1024 plus subnormal-operand/subnormal-acc/cancellation/grid-boundary edges. +# format: k a_bits[k] b_bits[k] c_bits(u32 f32) d_bits(u32 f32) +1024 51400 45160 20933 51292 39128 19304 43842 38277 35202 13075 40214 4312 2708 38389 62937 4750 61761 46325 38823 49549 42586 52603 2143 52109 56820 4860 30844 61544 15722 43768 10737 12609 11975 51822 25567 6594 63989 46809 25457 5231 10042 57412 59037 61756 36288 20871 59513 59894 4283 1775 3995 8172 26765 15446 4658 52037 26891 24983 2497 47390 63222 47580 57042 51509 27247 2603 27619 7988 5988 13909 22138 63533 41878 20976 269 13374 30529 28702 4702 14444 30193 46412 63487 60458 5872 5730 54923 45511 51334 51767 54303 10437 48610 8034 13189 45212 11401 33526 11251 3582 10510 14789 45017 44823 19882 11069 44867 62312 10787 37915 28960 34931 36667 44224 20371 18968 25905 2619 49514 35306 39324 8405 6305 52324 21304 13141 39665 44783 2102 29698 18451 64004 48326 56106 6607 24217 12167 1436 45475 55879 35076 23440 41465 25947 40294 46188 18423 15187 10462 7673 20305 15868 28738 26588 25837 49199 35579 40556 4337 30791 78 47664 3688 51184 26437 4059 27278 35342 8696 9488 51658 28608 21802 8307 55469 53651 52325 26252 42605 22217 52034 16730 27943 21293 37887 21933 29547 21061 48552 14336 50013 37695 17665 50744 11350 18089 62121 11240 21584 52433 59737 60295 47804 30517 63054 46897 1102 49456 50254 48555 24708 64136 14789 11221 9042 23656 8696 52868 38774 34667 44127 55872 7135 17629 26247 20174 52483 34187 344 64320 9736 62370 31586 15048 10468 49785 4143 37806 27957 11096 15732 1474 11888 57780 35769 18748 22226 38811 46036 22858 39192 2100 64370 11444 2030 36336 30573 38164 10240 54625 20920 44781 43165 57832 38716 17431 31636 61665 31673 44157 34012 45185 11706 46730 14920 30257 50386 13675 31172 41709 11359 21188 27763 58046 18186 16286 1143 10211 61096 53725 45289 26043 48230 21009 23104 30847 46538 40854 48373 21849 54045 61814 59002 11265 60132 35924 61360 46757 35701 24455 10738 62700 45382 55051 62468 16111 4299 436 40935 52565 5394 24598 21463 36452 34549 50815 9999 48056 18190 24046 24868 7877 11307 60848 37185 39343 28397 61312 38905 45134 26503 17202 8023 60964 49943 17244 31590 19830 38110 39428 20526 19751 55976 63784 33544 34252 21100 43840 26227 46315 28421 18963 43664 41879 61005 52351 46503 61413 59141 52783 48201 25843 31045 58841 18872 60336 47499 52437 38527 5067 50815 12544 15161 27586 24435 62816 59370 59781 540 13681 64173 51123 23600 29824 52681 22162 31156 37456 22018 16166 27872 17931 35507 60478 43847 8434 19468 55650 13591 58505 7000 31434 29927 8522 25290 58303 56040 49477 26140 38858 14784 12935 34581 28835 53154 16256 22354 42956 45854 60751 40950 44538 19481 22341 26249 59910 25540 27918 45625 63514 20319 27283 23466 35423 18836 10199 28457 19703 1657 24122 34294 3331 26119 49844 439 15264 37570 63450 15164 45777 46651 48498 8509 48907 20685 53321 20310 14407 34375 29252 34765 51232 11558 21943 45057 53612 52941 21345 19196 41047 30330 20552 49578 6373 14795 38431 60752 26360 60288 5283 62261 47902 56073 25119 51243 27433 21543 17938 53584 7935 13447 24538 40849 40297 20849 47861 25562 12476 2188 12425 54708 31086 25521 14972 58898 4601 29776 35251 42983 60550 2320 41312 58057 61009 36229 26356 17078 22876 6880 7473 55245 6356 50578 60640 36238 549 44294 62800 26662 49723 50540 22384 27759 34014 41968 34216 56972 46874 26506 11236 46763 52627 36843 17088 41044 26334 36329 25662 53043 20960 31682 23668 30772 63767 63407 15002 48638 48379 18733 51856 47792 20051 36640 38304 41492 2574 15164 37284 35719 22635 20105 53674 33483 45666 14658 52419 61946 17700 28684 24536 24802 15535 40946 12579 26579 50784 59245 15266 42601 22781 41061 58447 44106 23699 53992 41883 43339 8184 26143 48894 81 28235 36136 27437 42431 641 15320 56084 5547 25256 47387 7665 21547 64174 61403 52304 26441 23986 53089 27036 5714 34823 15084 58473 33531 3601 19567 15644 13444 64008 36355 63205 49791 61640 7636 23680 57566 40170 62228 14299 5027 8684 29953 52326 36565 37207 62226 28728 44320 60715 59905 34041 42114 39254 27495 40729 42116 17393 9961 7879 54989 13397 2823 8882 44950 25989 41453 7862 34596 32997 16617 63359 51199 45370 5475 7944 4978 16082 63173 28505 9702 7716 61570 18688 30626 11810 36668 15015 52307 35717 45556 23596 1606 44368 59623 1150 14912 17643 59671 37163 10209 34863 2634 46222 34329 41686 33074 57660 37077 58808 26716 18310 45911 44284 37108 57046 50687 57935 13324 25098 35835 29053 46192 31521 55546 28937 56813 38611 41502 18350 54061 33440 8321 36682 14295 37917 26109 54626 12972 2150 17939 8611 53520 51881 50585 23637 61356 40818 6032 57580 62532 51657 52648 27543 12681 1203 44604 10304 16887 44183 12282 44499 35014 47457 41651 31221 35870 2894 25416 12019 20534 35373 43342 59573 51775 34960 24528 63958 21723 10676 58034 49260 58440 24770 20215 29509 21626 19365 12648 18398 10939 12062 967 33926 41825 15578 17370 42597 26988 56529 24919 11147 18265 43833 51678 55947 10370 34070 25006 697 63209 60888 46664 42945 25151 36550 23002 35100 62621 5322 6286 35212 58350 49979 30743 40640 38504 18070 29046 63581 52684 46477 30218 51586 21808 916 63777 23081 53153 63359 14424 15393 25416 914 18173 64101 49424 2018 51246 10376 16357 43211 64463 57734 49558 49115 1321 6507 60336 54985 18946 12832 19408 44994 52611 57443 20333 25265 8691 61839 55623 58879 30959 5117 8578 25062 56250 62216 35454 42879 47392 20163 17844 63423 6657 19227 3018 48173 43715 13639 60125 26342 64354 13728 37668 19983 6788 60677 10039 26561 26629 58088 8255 41737 27698 18456 44153 22432 22193 38017 38443 27811 42623 1803 60889 5562 9286 39372 18344 50032 52437 46173 26003 42981 63008 12130 36227 45595 52138 55209 19413 9393 63014 55529 4416 3892 20060 48198 44457 57083 62951 3200 52729 56446 57118 35384 1432 41607 7710 42668 30101 4281 8916 11309 45974 42257 63231 22478 33223 63863 10168 37955 42043 35908 4392 3731 50208 43685 33680 42971 14706 6271 2272 13296 15838 59453 55573 56713 16337 35740 63773 26609 57072 28336 36623 17354 24143 24961 53362 43548 17015 37415 59032 56403 10318 44174 39245 38799 38673 6047 30918 45184 15525 20543 25067 63889 18501 26316 48615 31075 5860 49228 28447 40369 20741 51769 57427 14880 22198 39965 45724 20192 57774 29001 15673 9723 38348 48840 29510 56945 64325 9793 60337 23976 61203 61602 48717 12355 30540 63648 36027 37696 56250 55132 34849 48596 42178 46409 3400 46579 19634 42199 15553 15483 57955 36123 42381 8609 16912 34767 22895 32859 36850 13283 51142 18934 41386 1551 9085 41434 17657 1893 46395 43479 3253 56465 31338 28273 54471 18614 25463 35334 34371 40785 18186 54206 30784 42319 55722 18701 31557 24639 55708 24928 39394 7127 15268 29613 3594 40559 19568 31743 50949 60273 63477 36788 17563 20669 10144 21706 51248 125 28592 2758 38475 34946 64074 63897 37482 45734 61101 11122 22435 36887 59580 33908 53434 51232 26978 43816 55521 60642 47255 56536 8068 56363 13510 61989 21971 11876 28453 16793 6106 49309 49145 5696 25603 18086 62983 41676 48282 5889 40462 56535 37242 4225 21928 51801 64301 59752 842 37695 2546 43198 56968 57932 56372 48035 3526 40077 63892 43557 61554 45961 11713 10022 25188 33467 37798 49605 26941 25419 46414 41238 23443 50726 16864 19026 40095 29039 63020 22576 2756 50645 52532 26926 58035 13076 49122 36607 62420 43381 7285 49997 43486 33118 51098 23074 15087 28769 10485 15070 51486 41313 4086 45832 42589 15291 26315 13404 23472 322 38671 60801 9947 28787 30858 61597 17793 49442 4194 44835 26030 27746 8767 2039 7992 22941 14604 5777 3221 3235 29140 52255 47799 5735 12576 5509 47328 34444 36317 2877 14777 18701 27495 912 53298 34000 35645 50762 6953 23939 22022 64358 16899 2021 20378 26059 13894 4497 17212 48137 23318 26129 11004 64097 60106 1416 29763 52502 43005 10211 37299 29820 47927 41497 38926 62859 56963 40991 44339 38446 33242 9504 2860 2449 46520 4961 36635 22127 52180 57 24491 7942 35150 57764 1146 55989 50067 4858 19826 2051 37815 59862 47013 17564 34756 50030 20475 30131 7472 15772 64099 29961 34168 44949 56148 29116 47397 29674 12095 50677 22752 56250 17203 20375 14238 35154 42589 39861 63101 42501 19946 7518 33268 3882 33059 51881 56737 46834 28574 15377 26948 19811 33123 16296 37834 17827 13931 25675 3387 11156 63141 25468 59604 61726 44113 15468 42592 4399 33167 47251 13617 10080 31471 47484 985 47793 35675 5376 58944 25909 24222 6497 15653 57969 26249 35157 45599 16607 205 17249 40179 29584 42432 31511 18446 57398 14408 3147 13285 34138 10405 18717 62183 33326 38316 59878 55822 1367 44493 44826 27410 11276 48319 43287 41029 31530 45559 34159 64380 44704 43860 55766 43454 5306 50904 64044 3700 3505 40912 15043 61435 43078 7741 10700 13794 61979 178 51398 39941 48450 29926 56733 46094 21205 21364 3765 22226 28002 38463 17625 42308 36310 27070 17053 22572 26658 10864 56200 33080 38234 44591 29810 48820 54570 1607 16386 44293 33941 3758 16137 3444 5329 37971 12329 41284 53947 55986 36754 21393 35390 17931 17841 1815 25435 15321 8492 10123 45554 55568 36122 6340 60201 21769 30113 30574 23217 37502 20555 54094 16118 24751 10914 45102 58565 3480 56717 64054 43079 13737 62614 1772 60438 37635 61171 62904 43178 40879 51551 42523 15963 17413 8789 3912 21934 3627 15657 40030 39908 62664 57424 36435 20861 51702 59416 9600 46053 23950 35911 962 64346 27106 8335 8876 37229 59916 38774 22225 32867 20625 7689 12228 54747 17576 25120 49516 58746 18095 45870 25135 50886 44405 20409 41028 63227 43201 12983 62436 54299 41003 62699 31734 32879 21742 50557 35341 17932 9289 1945 61472 11123 8249 58592 60094 30242 33133 11395 58164 559 56780 4106 54082 16479 57801 1470 14701 52379 36362 27784 30548 7315 38606 30771 40967 46480 13411 3642 37173 63033 15404 16943 44047 38171 53491 8214 64182 2530 54536 44297 46658 48692 31228 55589 53265 54659 51289 59880 58071 38371 64211 6761 28670 46802 38265 3327 9083 35714 17451 51715 24146 49998 50613 48772 20626 44733 31014 63708 24690 38867 48827 23888 4302 37925 21712 19363 23372 24780 40330 6035 8017 36118 43303 62404 23140 62065 21898 30765 9879 21371 33333 50948 22227 51029 33616 13810 43667 13774 38059 63838 9506 53302 40785 47285 9955 45281 49764 44417 49954 5118 56429 5563 2014 63855 28475 9097 25447 3581 5743 38224 19355 47127 7033 8528 35352 16708 43510 45274 5200 20516 15692 8445 57889 24481 6406 53648 17197 29629 15040 62540 38337 59939 21848 18078 29662 15445 48425 12990 11378 7416 20967 15640 39833 62430 62147 35383 49497 35672 22866 23232 5783 16369 60391 12384 20197 52869 31329 17092 42475 37891 41345 12842 7733 44951 27809 58844 223 56825 53179 32955 24845 34099 44749 37658 62629 42496 29964 50378 10925 53573 50331 17754 27207 22137 25875 48240 45254 28052 35733 16787 20665 63255 30394 4332 41301 10218 47256 33906 43477 22404 45910 4038 26359 29962 10465 30025 39905 50533 46117 59529 51061 23775 42256 43172 27314 61898 47848 11745 48808 7432 45837 47374 13037 45763 46400 37716 42529 27599 25249 1316 44361 17288 45369 41325 13744 29732 14789 53961 38548 26619 6190 1046 10849 21146 43843 8572 63792 28556 43011 52001 10836 12344 13136 22061 61709 53640 38691 35348 60863 7326 2733 40432 60449 26532 21268 27863 20132 52608 44702 8051 494 6717 34045 12322 50119 39510 27562 28225 29618 29665 40937 6861 20376 51785 45124 37375 27883 11567 41773 16922 6595 37359 48000 13724 6529 62495 47800 18205 11669 39641 49894 21560 51325 47587 63726 23287 11216 18410 29974 1234 37030 31698 29176 42151 24274 30857 35642 47256 36430 47786 57603 31202 9174 30167 51350 27620 52910 26521 30543 64055 51291 14392 49727 56031 9193 13855 5194 9378 27812 1774 48890 48232 39873 8855 4046 23885 23445 45832 18539 52087 42273 36930 59910 38245 33483 17316 47201 25958 40442 51848 17051 8610 22901 18757 28257 19260 18410 6566 19418 40606 27271 45524 47512 1252 14625 11035 7870 18385 4619 4601 50380 16981 4379 19506 10211 35502 10645 23624 34801 46592 8658 48126 40117 57453 6373 200 33145 24318 36146 34443 4697 1757 42880 56990 37855 23143 46648 53224 14614 60739 28803 61704 51931 42534 55028 41236 29227 55443 26763 21735 49811 10918 60954 15836 9113 34994 52582 28267 52516 12604 34650 16890 10410 59171 26161 45695 30218 39965 18461 25969 62996 61695 19480 35488 44689 43056 25757 49725 0 3462945457 +1024 18799 865 20322 31073 20488 29025 17618 36120 35956 12171 48611 61193 4457 38199 13536 44384 48244 56296 30798 8952 26289 35594 54092 8964 37617 58325 53772 63048 49617 57330 45026 10290 36081 11599 33477 45274 40334 56871 63368 25967 14660 51231 49932 43209 16724 36590 40666 29068 8068 62833 4539 25659 17214 29025 33083 4291 22465 16228 49938 52920 29438 45007 57270 62238 6726 14282 32777 19332 44265 5351 46329 28607 5348 49339 52955 49980 24203 46314 52881 49623 57148 61344 31607 37606 2025 25693 20444 527 20873 19022 12797 36370 36585 11301 51496 30114 9412 45677 11717 25769 54080 54619 36815 49531 51006 56401 42780 13092 21319 59965 30614 54545 25858 42703 39664 10509 35650 6701 55426 59306 50670 46681 15264 37567 10482 48004 30315 55259 47344 22419 42719 3491 23379 21171 12931 52453 28868 14171 58152 57528 61776 58450 25698 12555 49818 55472 50291 28378 42995 54931 36930 30708 33146 22756 64216 20450 41408 49799 16273 62709 19118 6057 22196 26648 37902 42155 9959 59606 38451 24076 41464 26833 52877 35183 43008 11740 64097 12707 27790 9100 40738 38705 17577 12731 1369 28627 2005 2894 45196 47678 37613 44941 12399 20407 58465 23283 16418 57748 38598 27226 18284 35211 27315 58300 28088 61226 14070 27442 10034 43983 44998 51063 53087 51933 44901 59723 13718 64108 12920 27922 56368 4676 40692 43778 30983 56733 47837 37473 37919 23646 12933 10158 12030 5712 10770 22121 49238 34779 51699 38510 59659 45899 48806 10191 38305 56284 57375 52601 6548 30163 61539 25801 47712 38150 19255 26000 6330 14220 2686 8241 8167 15899 59705 30729 11132 64366 51551 23459 52486 2393 34 16563 4359 24961 5152 9833 20290 42028 45130 21483 18908 10136 11678 11837 7954 144 34246 38429 15383 51697 1890 23645 35706 7588 18191 31630 5218 9588 59697 37245 30362 14494 52556 9596 50622 39818 5994 3667 5386 7197 15636 11078 5930 64385 21621 17966 25276 34181 4812 18478 19502 10848 11106 35491 14623 30376 6978 37877 36357 17512 32774 51772 54989 39955 31178 53424 27563 35642 57046 46420 61607 15844 13020 5547 27619 43874 46584 53989 49574 55077 50659 39713 19044 61574 64367 50424 61275 63393 51782 48603 59656 23121 59182 6652 24772 63797 49858 57247 63121 13127 57369 33473 43509 48477 46375 5951 35536 4083 8080 3923 17407 25526 58890 5535 62367 55963 26024 31202 55830 3188 20084 7476 27216 21120 61993 41509 2649 34163 26320 27196 25936 12338 34780 40469 52171 64031 49020 55193 43689 55852 46966 52987 22910 59208 24752 28376 49887 42537 44059 26614 22289 12765 1960 36333 53000 20789 22483 13359 36394 61553 24750 15673 23485 17495 9952 6929 60884 52678 50268 27377 53730 4940 7756 8014 61696 41350 52670 49559 55568 24059 61013 31065 13740 35081 54350 27074 23643 37475 40477 47412 21969 43800 22429 47454 48220 60945 51233 36720 60029 61809 5286 36590 23331 36498 55022 3186 63042 36750 26670 48522 12611 51929 49562 51584 61716 51786 48583 16971 35645 25100 38999 58807 59363 31169 20951 36699 19446 35905 33254 14604 21552 48604 38564 31094 30074 40896 32908 3790 12919 37780 24093 3542 51127 48472 20264 54879 55849 13176 24735 44513 21682 28185 57935 23485 60584 58370 5076 43825 13972 36528 63712 61037 7104 59109 18089 19439 6961 12662 18268 44190 48101 60576 23347 41456 52171 3392 52117 61403 37154 41739 50520 25984 31120 49024 33479 38208 11748 36580 19195 181 42593 34499 27178 34326 9103 7743 15806 38885 35021 35395 26358 47414 53423 29675 29039 12995 9817 15776 63470 18126 32893 17813 9338 33186 45377 8585 323 19319 16641 24450 41389 40981 6361 44381 37689 31631 28672 23919 42611 30938 11744 56453 16025 400 34828 63186 30514 27170 52237 62860 17917 24556 40372 13116 9906 14169 6274 25895 23141 39695 24780 24743 16110 7678 28945 62894 62021 50659 58099 3340 37466 1399 33243 58729 49143 11285 44796 51511 36904 44463 7654 57591 55662 52788 63125 18876 39562 40932 48178 44199 29052 55713 36230 8545 6870 33568 64050 38344 20872 22675 43059 36814 36200 61543 2785 48487 9766 10738 57949 30716 11734 47127 48833 33153 20188 457 23067 34670 31421 22144 19864 42866 63923 58302 41013 20653 41557 36036 9126 29450 41377 11151 8759 18428 51008 61249 36312 43071 22263 63476 24546 48505 51178 51836 51888 30513 29473 7009 5227 48647 12293 32988 18212 38814 54492 1158 34470 31290 34943 9480 24447 26673 28296 21650 10390 13062 13396 4621 3454 22506 62326 23129 48946 25389 14471 60791 43328 10260 51375 62069 17480 10588 45723 35145 51390 24844 33300 64274 40805 48312 16004 6193 59225 6199 12614 23608 10106 52554 25573 3356 3089 49032 62823 50478 55927 34595 35516 36108 14291 10368 35322 31356 46259 29393 56203 49868 23512 23894 16993 1821 11747 48984 43475 61673 43836 56031 15744 38793 5695 17599 6519 24400 43405 40348 46855 41464 8893 16865 59550 6409 46868 30507 1928 32838 16415 21388 16075 19541 28854 16683 41264 40599 55848 62464 58680 37200 21026 47166 11694 23907 7832 38108 21386 50119 16642 23568 45569 13103 19205 2571 42880 30966 24766 20843 12573 17764 10818 42651 23012 39118 29382 17771 18120 51475 4678 42749 62997 60891 61704 27571 6966 12364 25271 62802 63388 7705 6647 27127 53881 53895 1252 603 39898 22649 8398 62246 12688 64263 21643 49377 43678 45104 51913 20896 51945 52876 18360 43119 48539 16649 13535 6440 34723 38147 18439 6097 13751 41220 56890 40845 25221 26723 41055 33927 58673 14268 21666 28866 48624 60309 60229 42988 23423 31169 50609 39272 35776 60765 37709 27380 44589 3870 41710 14854 21611 38580 7137 17160 24744 48123 9683 21276 3472 37784 3636 44866 48533 38011 9862 21416 28555 13535 14526 47440 37802 12504 12883 53171 21364 46250 21018 42267 41386 62535 56369 20186 35320 34793 15170 12842 19223 58103 56580 30913 29250 33938 14834 43188 28702 54542 26576 56832 61698 38611 29872 20610 54352 52335 40356 15792 15133 40410 11512 36783 54781 5285 15593 4214 53679 22207 35748 54760 59222 29927 43273 28508 24288 54773 57195 53247 61127 27925 5331 13318 60877 3606 58064 16593 46844 33713 45609 47022 42522 24380 37848 56355 38951 2001 16142 33298 37449 38611 49916 24797 37442 17492 36681 14700 8658 56970 56681 6923 49849 43653 37480 26424 3306 48409 53088 35762 36213 3900 9814 44812 58648 23630 25882 48661 53817 59474 32830 16631 62672 51211 61318 55995 19666 4491 55754 22992 58280 43557 26608 61035 63360 46191 8868 58894 2723 27910 48182 31506 37289 19448 14241 23799 1829 21526 51437 61797 43939 36044 22010 51534 30142 26490 7121 55016 49119 60502 51944 7197 49954 11050 59460 57116 37100 1840 6123 42732 42510 39438 27398 41254 46748 11589 12352 57519 25064 24831 11518 57395 36985 21805 47821 51823 22166 58845 19806 18512 54664 12451 17465 59585 17122 8216 22477 24739 28806 11833 63241 40764 9886 54297 61649 3997 8644 54400 39993 10172 38204 51171 49380 21454 18732 45825 15017 41021 27211 63405 28886 27607 54508 42743 21847 35634 52270 58325 64302 53305 1930 17651 5545 47669 41196 37831 61937 55759 48978 41266 18822 21423 37892 60348 7728 60387 57979 16460 17786 7490 38369 11067 58901 7939 43888 50987 39664 7356 26585 20158 41298 61204 24223 53687 19459 36597 36616 4206 45008 20853 16602 47925 60018 62368 12312 37538 7514 53146 922 5375 10595 9244 10767 24401 54699 53578 40042 3525 60667 40908 21731 8950 54201 59810 5131 6967 10881 50913 16605 37972 50085 20514 18472 55160 36853 58514 49280 43828 27286 63506 61185 27827 33092 2500 9030 31724 40290 7267 51006 56588 36479 25969 57919 53183 6920 10175 49103 17608 53906 49584 6395 53175 46999 39927 37914 12935 57493 60357 55458 7791 34292 7445 5609 13385 4067 8457 57672 46683 13279 11430 29808 38993 16182 57567 63912 20314 40002 29668 46084 49446 17755 910 11072 55887 8515 36172 39284 59569 59387 57044 49136 12375 57852 1505 41452 62922 10099 51112 7640 25047 19841 40135 36015 51353 36398 26016 25660 18782 39275 56768 1512 58752 919 57317 28706 57331 9875 54239 20099 13152 30519 52428 49727 29337 23697 64205 52954 57018 59815 23963 41145 10556 15257 29611 24823 16946 41175 4733 5674 57553 22161 13285 8817 43400 42726 211 54977 50268 30418 55736 47783 2328 35015 24752 63821 30101 22794 19098 25938 1759 40130 15319 52679 4181 61566 13683 45853 60336 43633 39019 10732 52369 36844 53217 55037 50124 51510 22085 46691 24939 37135 34533 55333 46601 39676 45123 2106 19332 16724 28100 51014 26491 37815 44597 8602 35713 38702 35145 43799 17090 20931 2239 37633 55381 36001 44160 8047 37714 13665 15314 2732 38737 63153 30446 17305 46286 18143 24564 7797 4742 23966 60357 21112 24629 59000 9953 23409 62886 25191 47658 40039 3748 19066 9955 25236 37588 45102 46819 28042 51729 15351 12589 14974 55508 4143 56809 12401 14721 28894 21413 34262 21063 59808 47862 61705 16121 17880 60303 30499 1359 40817 49188 54507 51695 25517 12337 200 60673 62538 2362 49171 42458 11447 5011 16034 42634 4693 45815 55215 55801 43201 55735 37811 10169 44179 35613 54518 8268 4625 38350 64232 29158 18412 57738 59452 58005 41 25468 63623 50852 18031 52502 46806 9287 30704 11734 34131 28330 42980 57650 42320 1086 49070 8839 41118 20017 15256 45597 46292 53371 43068 42170 51185 28375 9677 53715 20869 27969 21583 48253 1402 31348 1359 50877 42670 59559 45185 24275 7627 55460 49413 57933 42313 22177 44877 13749 17791 16761 42870 56331 54355 9190 30338 48361 51071 24833 63513 29023 40904 33106 20147 49404 41545 63795 3283 61148 18130 51411 33031 46334 58232 44489 30321 26767 44092 48589 59468 17087 3654 33206 57860 26607 21764 54102 31199 53935 38285 6057 46714 11356 46402 17298 48514 38396 20316 59196 60005 61734 20077 57388 22122 63653 50010 21963 63215 54973 50891 50007 61013 49893 22074 52325 37563 53770 62933 3317 37377 43309 44194 59071 59907 26944 38855 64323 2456 58310 45691 37096 35975 17024 38076 29816 38859 40562 44660 22344 63994 16142 52406 19027 41521 27956 2864 13666 5351 38467 49589 63128 50563 44693 29428 60281 15308 4221 43740 57114 4777 51306 29519 27310 16529 56955 803 22970 424 47718 23528 37439 13170 43456 4661 36850 58925 2140 35495 52507 20696 7563 3303 17739 53208 19658 21834 15474 56288 2038 19804 64311 18708 3615 56583 44304 57411 18783 562 11889 11375 8033 49419 37981 55821 37059 24219 26303 51536 14223 12679 45903 7962 31673 20336 39006 20473 2887 33350 49669 47411 29021 33835 63675 25478 51306 59594 2148 51945 58547 30182 18745 64212 56388 54889 6137 3866 35650 42112 32808 23622 63053 41238 22080 62712 47281 5846 28532 49170 14982 44220 27007 21934 53481 11716 44343 13637 44775 1320 41950 8909 63247 51710 2499 27523 17180 1336 58146 14498 54444 36264 24041 57092 55370 29350 46020 20937 37535 55599 49806 21645 21037 38497 42210 12188 44536 64153 8690 33669 42001 39187 30264 55123 1706 13186 58877 49127 1801 18331 36551 54042 10794 49705 28547 49268 49 24748 17440 14587 59477 11866 7240 56282 36166 17940 24440 15441 56851 64141 58896 47948 31191 58229 38127 29132 4625 4215 2336 54700 12912 46863 54080 26470 56523 15105 4414 47889 42967 16438 7529 3501 57724 9988 18243 62241 7774 18280 23072 43922 31506 53468 34076 41098 37105 48117 25012 35963 43449 16507 23535 24491 27659 62282 5748 21917 55963 11300 38307 50220 36767 22022 14998 43256 31305 9554 56905 18316 39154 40615 3712 9884 5759 47247 25642 47440 55607 35640 13002 42418 37997 12101 57597 24961 7258 21189 25598 5677 36461 7046 37594 16280 1101 49510 19467 30216 31675 56754 18001 47186 5087 61774 25837 37371 5338 25225 50491 43360 40309 42902 8713 18658 46652 41310 60066 6025 42431 61295 51784 62368 36531 11807 15017 26993 37557 43180 14332 59549 53740 17910 23667 59810 49818 7887 29650 59380 50394 54093 15286 55960 10335 4050 18411 42444 58857 6274 8747 10974 47084 18107 25219 33180 8395 11417 60957 62480 42593 45485 47263 44039 50854 38087 56970 1692 4312 39850 5643 28461 60612 20516 10265 6378 57624 30886 14268 45659 11250 17293 40964 60879 35442 46759 61474 41810 61965 18163 1337 37372 8112 17298 13334 17947 34307 64025 46999 10171 40405 58197 58157 36421 51584 61061 11909 8060 43304 4836 38876 53937 26959 13331 57531 56007 27917 25026 6256 30895 32914 19602 8275 33107 31741 46959 15299 40682 39219 31559 37765 6866 31638 20422 11928 14555 27507 42190 51682 59389 745 53256 23799 62822 62688 35274 52016 0 3468794360 +1024 8749 51820 12377 58079 2098 14229 63640 61372 35806 6193 22492 26628 34500 1458 47644 46663 61818 31089 61383 5067 38627 61174 49869 24538 24375 46388 47819 4264 1865 17858 18341 2093 64203 19759 30857 21929 17514 6325 30209 54336 30679 17676 20917 52146 48036 33110 47561 56226 60671 5617 9771 54552 44369 54566 29207 10907 27601 27255 41763 45169 33574 49002 18527 57881 13192 24855 20331 8462 16673 8468 10227 35634 29322 13587 6473 54487 39649 39235 23936 12026 27924 60405 5733 11417 55957 18097 46345 18529 52323 47734 30702 38058 53848 28008 46356 37909 38559 60200 10002 16684 3149 45350 53669 23839 38672 10635 57571 42574 21677 46819 21726 62987 35060 37988 6749 4247 48125 40722 49491 31651 63174 55159 21146 60788 43028 3615 44357 39580 12984 17740 9194 44009 49036 20035 4221 33924 62083 11591 57928 4561 51961 37801 48508 11743 37995 24290 33839 44307 45485 47682 46014 60422 21495 45478 59974 48163 26019 31377 64380 36168 46317 40076 1541 43640 3987 14463 8894 26553 62434 6704 37075 56879 21653 3153 46404 50926 63346 12524 4343 39924 34598 38869 16119 14562 9165 59812 20342 28248 45856 56156 15586 17557 43386 44003 49104 12368 57582 35073 6517 16461 54999 24876 1839 38929 36746 58050 50789 7271 47994 1370 60448 60087 62974 52326 26530 7832 39283 46133 14908 21878 56010 38244 55745 35180 23136 49201 23737 39327 42490 876 30371 15678 6264 5636 52264 17718 31575 14873 4366 57762 57525 6037 39678 30890 54521 57277 5479 27743 46826 59558 30996 63438 59530 56227 19548 53823 1921 36128 16903 46838 8117 27995 48032 28104 21908 27812 56454 15675 5038 51535 56969 50290 62556 46697 49629 56341 59873 26292 48087 15294 14965 48949 33888 29896 61835 44973 19755 20322 17027 55111 48853 17839 24449 29070 50696 28554 56096 14501 36170 6775 16468 13273 20833 7783 52742 59259 50201 38969 50092 59219 28976 17966 43187 60954 45156 51211 61935 46884 55696 42918 63899 54998 27255 35884 34801 54761 38184 26351 35879 24165 45390 4395 35403 48193 51157 38463 45926 11190 61448 45702 35386 60391 36840 12533 25141 53471 52520 7990 20750 45002 52376 39049 11395 4310 15159 8002 17568 6993 53112 20691 49822 4762 460 40087 3800 1963 37488 47865 27445 48869 33779 41432 49100 7655 8117 28124 17269 38842 52173 22785 45082 11353 26903 29146 50839 43971 40849 21716 44269 35142 47381 4382 6543 61485 20963 30963 50301 40683 419 16825 24296 26862 50509 2097 63890 13015 51447 49993 49736 30565 57826 30133 51903 22933 35887 7820 38931 50458 51951 31295 34 12141 17061 12203 57544 6865 6263 48341 8440 24762 20804 16495 59870 31336 28080 61044 36751 63406 21486 13735 27386 33129 60970 25542 19340 57056 509 25873 4993 56227 40995 9769 6713 12932 43063 47478 54979 43313 17672 6208 2580 10398 24768 30506 40609 24291 45281 331 18661 39599 17212 41173 21739 14657 10941 54537 62903 7648 14841 4874 52308 3995 10211 23285 41684 54378 27706 39405 47585 22275 4820 45077 14290 12046 50317 59735 16858 10645 1649 19244 52048 17034 17534 58864 64139 25658 38055 53836 11069 57986 62204 12070 38822 24649 42144 47313 44922 10302 1691 9174 12181 21944 6260 11199 637 59843 59879 37087 26486 40409 43395 56344 55394 43499 26476 17887 40237 35939 58546 31502 51109 10279 28704 58194 47826 30296 1700 51410 18014 11150 52868 12874 54574 10619 26886 9036 31232 21315 25820 38222 17881 17096 42651 8830 9792 1657 11471 21169 3784 34816 20475 35 844 21280 22635 22748 9335 64255 3174 3315 61708 12581 60096 53679 45404 50588 60177 14603 25423 11149 11080 16252 43287 46445 37629 55267 57736 35896 20466 57226 47844 42056 41403 57929 47026 17796 5240 6308 50833 41793 38674 5808 50634 25293 34140 24010 58041 15214 17739 52819 54289 18225 54370 32837 1778 33340 37608 52248 39728 17033 52954 22685 38633 44671 49425 33768 55390 30910 14401 53366 35070 53505 4338 48093 18179 18236 3926 49122 54832 10959 22241 59423 38258 42878 11524 1267 47829 57760 44058 595 59270 6503 6735 11793 14275 33889 15380 6912 52679 13678 31326 58444 29973 3260 60611 40084 15926 17389 55149 10399 34156 49662 25015 9374 8868 9944 1892 54073 52719 1372 51881 22820 56850 143 35007 60753 54980 53265 46657 28666 57074 61324 56751 64248 33138 50295 12344 28735 43402 25491 45586 61137 7465 57139 16401 45636 4298 27030 14528 41996 29843 28715 30177 26834 36657 10314 55796 34196 38997 26849 48378 24240 16372 55015 2385 57375 13366 36156 61241 56720 61462 47250 9805 62888 35434 33487 2413 19765 8364 57953 37454 58543 63560 2620 24034 27709 9366 18139 62890 34215 38628 35720 40432 12402 59659 61609 46500 17980 37362 62305 26529 64014 45070 62774 32867 26702 13294 10859 45893 55745 55172 9992 37894 61474 58278 1038 38436 12815 4469 14147 54306 39859 44468 52982 62302 7352 8713 59871 16751 40347 3758 858 27242 23301 54653 31739 37618 4860 32816 41013 21594 17163 5993 45731 47287 57378 50197 59716 51733 13644 39403 11328 43910 38320 49389 1131 8837 47058 58874 63036 53683 43350 262 533 20455 43762 53701 7534 29624 62620 58564 48299 17588 661 62925 55862 2974 57882 9228 35414 2170 64108 49688 29163 16993 6095 54979 39350 35270 915 57925 58173 63985 10744 18117 5055 51062 50613 38141 48712 9779 50874 17159 49117 10422 54014 8008 22856 40392 60705 55383 28258 15678 25096 11520 29890 10752 14895 57310 58548 51120 57349 18362 54631 28834 62018 1612 3616 57189 48062 38400 35836 22019 53267 4985 41407 26248 5004 26031 4505 18174 15727 3781 55306 22459 2838 47026 15205 17269 52692 25407 41968 23160 44770 53341 36476 22421 45092 19856 17812 34019 62574 5031 13622 54195 43544 21271 12455 29835 19385 48788 49685 12487 23284 27452 13611 10552 2643 29289 60888 32953 18209 1391 45012 10650 6818 4835 61686 46850 55644 20970 15326 60723 43867 59335 26331 50525 38305 62624 60326 58820 49268 41337 39349 20110 15412 33592 40950 6233 2411 58170 52870 21898 46851 11074 18569 42044 32951 11947 15690 28863 12408 26185 6044 34920 30497 53960 58042 34877 42012 33381 3513 44649 20204 13325 41292 39678 48786 47054 30342 36925 8725 57191 39956 12683 45876 14240 24391 28303 2277 45984 24013 57918 13581 16892 61674 39077 21460 59731 44662 13772 63430 55446 35579 46838 53895 15338 59219 17153 12324 16727 17121 5204 21558 8018 64185 62872 62976 30432 22554 57669 63288 33327 48912 9303 29455 44324 44607 55303 12891 49894 23327 39589 12804 3208 39172 28090 12283 16015 60321 44252 36768 53067 62798 14761 12599 23201 18576 22684 35969 10756 10590 12914 5512 6404 18294 27303 53164 44227 6776 41768 62473 18489 34747 14488 38958 5618 47873 35625 21460 24324 58546 52045 54730 25592 45912 15638 48036 50896 8501 7058 57292 21738 24279 20236 6062 40566 54590 34850 1269 13379 47030 29851 27153 38157 46490 34131 52278 7204 6867 4355 40474 13863 27925 6068 15906 27679 14225 10540 8062 63403 59363 27460 41579 43885 35221 61322 37439 57297 2174 24866 45767 43745 52558 12101 50309 45032 20939 15720 1736 4335 339 10794 16587 62113 44463 62137 1138 8056 54444 61096 53252 23493 17094 25652 4393 61739 14451 14190 1004 48197 60911 9126 45520 8851 52143 36026 50569 26107 50050 43913 27043 20797 43289 24819 55445 6681 14100 30302 30020 51874 61250 43564 50742 15245 43262 55449 12040 35220 42568 25838 51719 3474 39759 244 11041 55487 14114 33175 46105 59096 767 25177 29141 36174 57094 54215 36160 50400 14121 16085 43822 14001 56690 14061 3858 59639 19012 22340 30022 36509 26117 23624 63438 34213 59337 35806 29871 15036 49017 26422 28011 57003 12418 16376 49982 6551 23607 50462 25634 56597 60223 61726 63412 13562 62896 19520 15833 60017 388 48680 7549 18860 45319 31568 21795 21332 26564 45627 54230 58509 20621 6334 38936 57098 21689 42058 37187 30151 34407 19746 16896 34490 6070 6462 31119 53512 10482 15725 56333 59666 62032 43256 62181 53954 11307 61436 53059 34918 10024 10749 46799 22574 2362 39791 26970 54452 60504 23428 33136 33039 28421 34754 1896 51132 12897 56895 60456 61377 494 15325 24733 24159 15995 4622 31669 2024 52636 13749 26054 39468 22890 16476 52576 19442 35887 61912 46136 18497 50574 1615 16294 35199 6650 57758 64090 45527 26732 22388 37393 35558 17837 11076 52465 25229 25825 37221 37708 6346 62701 46306 28747 45207 34818 40072 41971 12420 43577 52760 21695 27923 5705 22761 28556 34525 45866 56268 27371 15714 60309 60044 44121 44817 32907 64239 23215 16861 3227 56838 35521 62058 2440 63080 40756 13165 1321 19753 29514 50451 21640 48907 4368 35820 21214 7904 51664 6671 27571 31426 29434 33668 23809 62558 7285 7291 8373 15622 57346 64170 14967 5986 43347 29646 8377 44651 60701 30137 48717 34610 27061 47364 12235 9206 55962 15204 44074 29819 53942 5967 25225 22634 35903 45240 10113 8172 57486 7207 2787 35432 1073 22291 15251 27851 50954 8830 39407 49273 48541 22786 5154 44534 53067 32872 16887 59215 48768 21578 13785 59707 22762 21545 54180 53478 47568 6682 56207 62989 30827 46369 49001 47374 34425 58473 63234 34398 23729 49812 41445 29107 3174 61323 1208 49258 42483 14862 12031 49618 30544 16169 14840 25659 51358 50494 29198 28526 44818 55645 26697 23638 58590 56948 27421 55977 22968 61123 8401 45949 44152 42996 3817 43101 21776 38635 62845 21585 8082 46350 22797 42585 21441 22754 42722 887 55477 23453 41789 60417 50089 33227 60902 28118 53162 41216 50171 61544 63488 4544 41976 17118 29605 59631 49169 57539 18741 24696 61172 53421 58799 1397 17551 62149 15216 29115 54216 45104 52417 37269 29976 7806 59392 26377 8242 28244 19767 6589 54110 43326 33043 23705 39496 23189 35263 3191 3792 43489 40281 62173 38192 44416 5674 20142 27217 39092 57198 14946 17096 49285 13630 34927 25772 54911 30742 33777 30713 58148 49104 6402 39605 1337 12717 17749 38287 24983 30884 37842 3236 2228 15404 36502 18636 39368 11806 47825 61771 57039 40778 22780 1498 56445 37698 871 50311 17494 41739 12356 18063 45526 13256 11749 10088 20587 28045 51676 58477 23161 19560 39685 18460 1689 25980 4464 56437 51738 26310 38546 48896 28484 5636 16889 2617 51438 52267 61959 50791 34846 53931 53379 18857 22714 49766 20180 33409 16691 27937 29303 63760 57376 21929 8312 5077 49688 27268 30914 30415 21843 330 54997 22212 1770 10391 59304 49738 60298 39164 27511 14907 7806 5792 24549 59952 39626 19587 8945 13035 16778 51192 51061 54785 1777 51758 39137 4695 8369 31470 38007 5014 1479 25347 12335 58362 42653 63829 37616 59359 57014 56524 41009 50772 62285 50319 1809 64442 30355 4840 62161 52138 45373 10978 59814 35605 2818 7899 31 60677 1402 28601 3564 26919 17550 15434 40774 60463 56910 46404 2486 23542 63036 31083 58325 10037 59214 46447 19312 33365 12919 41126 4808 44899 30521 20677 49245 3701 881 63237 57687 43312 63799 47487 1617 21118 35359 44784 60544 2401 25951 6265 27240 10004 27217 58365 12815 38845 30814 24137 64125 37214 24836 39556 60140 15194 55104 20831 19975 54843 47604 51292 51142 31275 27538 42710 37032 55914 54281 15583 22862 58759 30282 10707 4538 24572 10552 37040 51455 55084 50281 10068 6120 31680 41386 24352 49449 12891 44989 1751 36203 210 4442 29908 8964 50081 16177 26367 16606 38956 3027 37911 28302 41814 49598 5193 54634 26430 50640 46815 54328 40785 41941 36628 32994 37798 14484 51074 19290 57082 43104 59390 47989 10897 12677 22579 12255 15180 37385 1745 60626 59433 62260 53524 27640 9581 34744 24265 22288 50395 7947 62411 47086 55698 20434 20276 51563 26116 29151 47378 11502 56917 15844 17714 35107 62948 11378 3482 21862 3799 39189 378 11066 12921 22595 18535 42174 51570 6571 16886 8835 41438 29306 10864 24853 46607 21539 52916 50460 1159 4455 63077 51088 54896 9560 56659 59501 41445 44616 9830 37638 57266 59831 4188 42357 7453 10672 54556 24632 23493 63048 53780 37453 12196 31511 21835 35755 30715 28682 57404 20570 24325 36388 48643 58809 45878 40943 23186 34955 34575 37632 22953 9496 24832 25899 18588 52397 38609 16062 16311 34192 39754 44643 11639 51162 55150 3527 50670 58989 44091 34794 57678 51357 38055 47274 62721 9054 6070 52366 49671 44037 51992 32788 30338 13655 12545 58735 47536 40224 17616 60499 37159 49632 45877 24347 39674 8819 27623 2510 37744 47565 47821 6515 39364 55882 13212 45594 18798 12401 5753 52998 58377 37073 757 22955 20160 40551 5964 28421 15395 57430 47674 62345 12466 0 1337466575 +1024 22289 61744 26142 50940 41009 43621 27779 4347 4922 15661 50935 20608 50326 56734 18566 7793 54853 37453 28295 3279 38008 35680 45179 46926 37470 46471 42655 46497 49332 37847 21446 12565 61445 31074 445 28661 10931 40821 19898 24722 23670 30913 17012 43675 18368 34085 44141 30006 41875 51555 39619 33636 50876 61789 7956 60816 17392 27831 30050 13116 62951 43808 701 54434 55219 54327 17419 10452 12071 7315 48888 3375 62520 55500 40889 45405 56477 23753 33715 9417 8469 41552 49585 20776 55203 37356 35407 40805 4185 50253 29939 38813 19610 59114 18357 39295 44708 10529 20126 31532 36144 40260 31180 23270 60783 42534 4236 15777 4556 28942 55405 29395 40420 22432 50674 55899 14694 47603 57859 59534 4705 37914 16962 25159 29352 60515 60368 9605 12632 7565 31203 20663 1601 35590 39098 36534 42713 27193 13999 53551 12812 34045 30233 11163 51808 24775 64055 8013 48934 12549 61261 55527 62785 1985 33587 29944 35401 61305 19505 7980 199 325 45486 52572 35009 50422 58158 38541 41741 47879 41067 4199 15776 13622 8757 39147 42158 17689 4833 43338 63611 26319 21288 29854 21200 55550 28326 50450 7302 61479 46988 33829 38636 34413 48664 13825 57244 26914 23565 30471 50326 53058 4548 55009 11931 18240 23472 56457 7267 33064 5546 14430 24970 10861 38508 13460 26711 25890 1185 56206 10257 22281 41097 5202 18779 21806 41524 22208 50041 6348 62841 41915 29350 52821 20855 186 33494 53419 26651 28125 62942 15597 36393 15866 41672 57910 33790 3076 60987 43936 56729 28025 18541 33749 10040 21909 42630 23904 59032 3041 48661 26198 6101 49019 43189 47094 16468 4656 8023 2419 6468 28065 24736 23205 4278 41168 13178 8894 29938 6658 22683 59323 26853 14881 6287 43015 2927 41908 18713 35347 30170 6741 36775 7003 19460 57670 56135 38841 45062 22688 320 19763 6899 38205 35697 57348 13103 22570 23654 12562 59268 59366 56033 60481 17994 509 63592 36004 24571 24407 30136 19519 59203 42457 22522 3215 56736 13833 52682 43161 31323 55324 1196 4814 27599 35074 53264 12281 38106 49566 17759 28713 17974 38523 59086 10989 34213 20136 33707 44277 45686 20089 27853 53919 22862 52674 60589 30729 59612 97 42800 35941 50460 36826 11422 27093 24887 60103 56136 55775 33379 22541 55903 26779 22206 16560 54974 46759 63919 17725 27179 5446 10773 45857 59012 44159 33669 18690 33231 49150 54583 50048 1826 22062 42365 23264 27442 23989 831 56546 18262 62681 49584 13997 5312 56287 39641 24617 22450 38123 8491 42518 24656 29898 28726 45899 8726 54040 1905 60370 10671 36562 9028 23460 48771 5389 17481 11861 57641 41194 435 57948 62792 11844 61931 13735 45580 33975 27520 10950 9534 44896 26256 33092 61024 43806 45023 58853 32968 44389 11770 15539 27849 1016 61985 26514 63103 24829 28048 59385 46896 31431 19118 1799 59648 41369 59135 50345 54696 25363 36947 22992 48385 20296 47565 64055 2374 25195 56386 1744 56232 5515 12218 33298 12195 52853 30478 57190 4598 6382 45962 43715 42775 5230 4410 7365 28713 18915 12776 16465 10967 7033 21261 8654 53177 61312 19015 33251 23435 183 60176 54289 60339 53429 61954 21558 62548 6534 44871 60348 14618 55640 9172 36005 403 21187 61393 9252 56357 12819 38580 12368 11491 42798 30106 60726 45044 10350 46392 21853 3505 24936 8906 42120 38014 30280 62097 2041 54214 45953 5119 37555 64441 58355 12001 60814 9116 20851 6811 1525 40107 63926 59387 51257 16520 61378 39333 45083 40252 19270 37063 11627 61380 53810 24037 8295 13476 28376 61521 53618 62564 19083 31210 56893 35982 5664 5458 7473 10355 63965 6734 26895 3886 41041 5222 43961 4045 22814 54251 55779 37895 50896 43958 63002 44005 22337 5067 17785 62949 56600 39156 31253 39131 24884 39277 25451 56052 18561 43035 34748 12732 57744 35901 62293 9755 36954 25685 7356 39673 4929 16053 56113 33526 7288 21768 28593 36345 37954 20705 13065 55500 16209 49777 28754 4170 23561 12223 40362 37150 53508 60407 30166 44857 19472 49771 49835 1478 57070 52676 13816 4423 44119 46416 26517 16204 27680 46585 9787 16859 23035 13972 42812 49375 23885 14915 230 41723 63112 3162 30324 863 564 34103 55875 26329 10691 33663 1384 55699 37608 19561 43273 13989 57553 23816 6318 52565 48451 6706 17133 38518 35344 62222 64293 16875 55653 17662 44702 20294 40349 61500 18191 46136 25624 54066 28918 61563 29093 50475 39892 30523 18302 5875 47541 22863 20077 12683 23465 14458 6798 38154 18713 55507 31388 4039 45230 22051 60151 62543 11479 29209 3618 62487 26388 64144 268 54298 39139 26813 59436 42731 14690 41060 8738 29432 59131 34015 53137 24898 30257 15246 60079 12604 60044 5106 36458 28018 56681 12492 17303 48832 35383 55016 62870 19391 27241 47276 21069 53006 46618 63031 37088 12505 24600 1335 1367 27512 15600 21056 19384 26065 42531 10044 4650 15531 11503 17963 5462 13069 41623 24476 28105 26672 45213 40984 12639 17697 9084 2633 55852 58771 48078 64312 26082 24344 22595 10440 52834 54825 21702 13075 47176 55628 62136 3475 64465 235 56625 46290 18703 46656 31109 50127 36644 21919 45960 57849 8277 5963 36808 2459 21084 27959 15959 39429 30534 53177 59712 27710 46818 18535 30943 44877 24391 5739 37151 1321 3997 64175 10856 6125 7535 56624 54402 8912 54533 24677 6515 2452 26942 33373 11911 20296 41751 9610 33564 24363 43902 57092 28078 13593 44756 52404 38810 39448 23593 64353 64305 47034 55249 50640 50996 4749 56935 60218 54990 41767 17453 16786 46144 25863 49415 353 21061 60426 50303 3473 21024 51701 45805 13798 12251 43374 29430 43746 45954 12572 20478 54530 25326 44093 45846 33157 8029 36161 22614 30907 21174 64336 42531 22534 40000 16434 56158 61404 4616 12240 12580 60239 55134 10757 16037 15756 40889 2148 52285 57593 62427 43196 44994 48700 64117 16911 40044 176 35498 47478 23208 26491 29616 41547 22993 58033 10160 61712 16626 2031 23090 29371 60445 25815 28405 55888 40175 40537 28756 48032 45932 43779 361 27577 38046 63656 35687 15434 20976 23027 63233 7875 10518 20111 53753 59233 22738 46707 34254 7684 64321 62402 33931 1060 59507 6852 31294 37211 60842 60197 22724 51473 49220 43967 984 5640 1932 41602 18641 24379 53003 23995 53117 7580 42668 62534 13901 51058 44402 30318 19009 9570 8772 3856 55032 48780 12292 19171 43879 25946 38871 36378 6062 56652 28158 33184 49024 55238 31227 58823 59335 10127 1982 55555 32985 53381 19765 3470 39843 42894 50466 14894 53361 60023 55446 28251 1688 46732 13144 412 12830 60598 46320 3260 48513 39364 50162 64465 40576 40775 21441 25970 14601 4836 5344 10070 33165 10457 20014 20727 51643 44995 4567 31565 41080 17143 57776 6790 41672 21101 30375 20430 10388 19726 17485 18653 56634 33151 46552 23831 18302 63719 52574 5910 46110 1999 64135 1861 17701 25573 28737 38140 54000 6368 7050 12809 51831 14477 27132 9680 4651 38059 27520 51188 54145 41524 48649 28998 25375 55394 55141 564 10221 51009 12320 26650 56894 37664 39670 57625 46273 58094 21454 42417 63224 27813 46987 55592 37476 55359 12876 45606 49049 19505 24437 9991 14474 17655 13302 47548 37699 17821 22225 10198 6253 25640 60885 11166 12988 9831 11976 7334 13608 33687 37775 60527 24740 13643 39469 63454 28158 53822 63601 2859 25433 47924 37334 16537 42724 29755 37006 40469 40740 6858 43684 40908 55016 59565 39515 63424 64412 6307 53830 6347 6584 33064 57926 4425 48522 38074 33340 14776 30622 9212 1475 26762 7727 50794 7127 8180 62305 61706 35367 13016 17685 37244 1144 40420 62847 5971 53656 58625 60288 48865 25125 29230 42598 1357 27955 52449 29305 22556 1171 42254 30921 642 4483 63916 14653 3920 4634 8981 7680 1691 46296 30637 47603 33520 57694 47722 47055 4907 43229 58625 57069 58954 38657 22924 15414 23430 62887 7855 3693 11167 63090 28238 21492 20969 23312 11327 34714 9827 47665 53185 18109 17716 62084 27444 21699 37509 62037 60645 3238 41757 53083 61083 46786 25930 41251 3400 63905 1007 58712 63841 7236 17209 7788 19864 54287 40184 44941 38897 14138 22742 39104 22801 5289 7654 60348 46976 45928 30873 62634 57575 44443 45037 10332 47344 44132 25648 57902 23017 30012 11532 13208 48285 25579 3851 16851 13306 10608 24681 35647 60499 16439 8659 9679 36471 27246 39090 29263 27062 11932 5030 15280 22962 35465 12707 7714 15590 1466 11614 20765 35865 49257 42017 30007 44535 14109 29931 1756 41813 15051 35299 27416 39565 33056 19413 10904 42138 13698 22375 56380 42119 41797 10651 12170 55913 25941 43700 41093 27930 4706 63287 46565 27697 57536 54167 26215 3599 58478 51884 59408 64396 21731 1334 36681 40014 51007 12987 33138 50117 16321 14818 2106 26591 46613 27167 2594 58050 54592 13938 15637 60044 14341 46274 23957 40013 42875 49924 5194 19541 43936 63473 7786 51837 5168 14252 40034 57556 11897 22398 34890 51387 58767 27002 50585 38789 16077 17682 55658 1510 56276 29322 55924 59117 12569 38198 13599 10745 53488 58724 20227 5461 36305 21008 1891 56585 50963 33817 60778 31721 55984 28726 63254 57474 52835 39093 26855 10369 21767 12745 42746 11601 22317 21902 55812 14033 6564 34943 153 55142 10365 54159 43316 61043 26702 46231 17253 8013 8742 34742 9915 17847 56812 29012 50567 16678 47699 23106 22482 50066 37312 52087 40230 24070 61569 19054 17729 36696 14574 7206 42110 62959 36787 25548 10894 10949 18067 21712 53195 61660 5542 63358 52246 36130 19465 18875 37606 47781 7547 5886 64370 35714 4486 10203 56756 35127 54814 5938 11719 60190 12767 58901 49491 53512 33903 10714 4804 59044 36360 60399 37224 18790 54063 625 15693 59289 64410 25146 13796 49168 33537 10447 34552 2059 6935 35340 8908 8588 58263 37810 24041 57545 27083 54776 42734 25369 49403 31441 2481 53009 48989 46806 26934 49183 4958 40102 47047 19637 38686 41184 8365 9166 24429 44067 52932 26095 41854 59926 48510 20057 42415 46751 59681 45133 46498 48412 16814 55240 16897 3257 41298 34072 52359 27955 29408 54827 21204 45955 54277 12606 19172 6 26659 26262 7995 14209 53235 56793 4044 694 61982 8402 2130 53211 38242 51298 21297 43042 44366 6535 54027 63447 54768 55311 1349 15022 27846 48977 60704 41509 16927 7282 21231 10519 53536 19353 10212 52722 20296 37177 29805 51977 4936 47145 26501 11122 5723 56086 8975 17771 6721 3035 38140 16775 17944 6968 5108 2372 6670 14038 36810 49892 51965 19292 34983 25812 60397 62571 23627 51700 31082 50346 12197 35378 19176 61590 49656 55546 8943 20201 29720 31324 51972 46643 1841 12004 52283 5458 2768 62112 23813 61076 29333 35219 54867 2424 53126 55232 9206 1745 34726 14681 37912 10189 8322 13934 18588 49760 50747 59017 16833 19978 29529 22141 23223 17789 26565 40560 11617 49391 19943 23695 40294 43358 24939 53918 35215 45502 13454 14968 53777 19308 62652 64023 34387 58663 62587 41698 40583 902 62564 1807 17899 17924 34426 18254 54283 18813 48542 2152 23123 27749 80 25803 11202 1386 63097 35161 6129 49496 25584 58081 45853 54360 64047 11735 63153 8802 28252 44703 26067 62223 15784 57400 19933 62732 26737 50944 33301 21193 27772 35512 37116 63350 34713 23438 45251 19076 49159 25189 34380 24753 47433 62596 11612 14028 35129 45781 57336 33419 16773 47962 20598 6585 13216 13895 8281 33337 21858 28989 18350 26543 16977 63835 48593 2018 10851 25666 47854 63412 42314 24718 1568 6678 44236 46767 49389 3428 58933 52290 11593 29988 6584 57222 48399 12288 38788 27449 57511 13577 25946 29532 45428 43692 12753 38140 41504 28082 60121 62469 47571 51643 18871 44340 50317 60323 52987 20159 55396 8072 16751 61773 40515 40141 57380 63997 49004 40504 46785 26708 7344 11505 61539 10236 40491 1043 22132 58353 816 42308 10700 21841 36394 16007 5928 27329 10313 42367 62275 20043 56690 49619 29991 51910 59510 54714 235 50886 34253 12864 33298 39503 30428 9667 51929 49693 64371 36474 29422 45540 34102 13393 19147 7340 8933 21192 30072 27656 36635 16441 26646 60181 44171 47057 22840 35346 25023 60309 19986 49407 21654 40439 43712 60604 23261 24212 48918 41569 27099 24456 5556 2994 6720 58030 13449 37177 13853 41114 26529 40425 62074 59674 59624 51787 15056 57164 23635 860 40305 2695 13346 38812 43286 47918 20716 64463 4840 14005 53673 30828 13762 37857 3053 63016 45415 21249 62466 6589 60439 21854 47990 47660 25232 13977 19268 58945 21752 45076 50602 388 422 33306 49266 24987 3659 62860 7899 47271 63057 48519 33962 57936 4009 23372 26754 1948 33872 35166 22375 3172232553 3463058888 +1024 54378 19091 44462 40294 63300 55343 4367 50462 36320 40958 31101 26482 39314 43470 1458 57967 24026 58941 52377 46572 33482 59077 12938 46781 57668 57630 56085 1970 37127 46369 12748 49592 55011 40039 56105 12136 23798 27325 45347 37859 59277 45364 30174 32827 57576 52645 4917 34174 26833 6766 47662 828 48422 27682 53652 50922 2359 45118 29803 2517 15353 30155 23364 10811 8265 29403 14201 57453 5795 44011 40283 44065 27650 46189 22544 57948 2972 2782 29783 36934 6783 6406 63484 60855 1607 63272 52548 35996 18471 16624 15419 42083 63771 2944 37985 59124 6995 45254 58637 22886 62626 52758 43093 57317 30621 24494 5798 50408 32819 3966 19747 39489 22091 47250 63714 2196 29922 43472 6575 52018 23770 37820 62394 17976 36662 37120 54573 47070 58403 5455 44652 50536 9155 31354 48163 48162 21496 63290 41896 30387 53189 31440 13712 39623 10720 52108 10760 6156 40488 63347 3722 47720 62990 26547 63426 35217 34288 1794 1552 54158 6594 45128 52129 34974 34942 669 24196 39118 3742 18768 36280 33 41008 61722 11283 53356 53665 55714 20941 60910 41865 63055 18550 22877 49793 56186 59549 43655 3418 24178 64093 52798 17845 16137 50038 56271 54894 44284 6411 15938 7501 26031 47991 34494 62325 9949 47931 20522 44063 23246 18767 35566 6343 34848 17515 58878 26794 28636 49831 12360 53151 39287 59676 36499 2840 28553 54329 50312 56 63219 24404 35807 47468 10387 11527 43948 314 57114 10132 2216 56660 31288 50770 5429 12899 42987 28187 47740 8245 46528 21118 16434 1528 20291 48755 22810 51101 50328 49396 12810 52739 22426 45571 4980 12980 4453 11813 36472 37026 27892 57558 18173 41706 25669 42947 9036 41538 14692 63659 55600 16081 1985 33352 44581 44717 4290 51812 429 10191 59507 5305 19281 59113 11566 4516 45868 15890 53567 60909 5701 21607 21801 54917 40478 50587 56671 59340 2335 59839 41095 29032 29299 1943 24703 59455 56021 62196 29405 62748 56434 5494 44824 56643 21603 34394 30731 3299 56819 13183 55233 53731 49505 4334 954 26664 41260 34830 7853 27309 41868 15315 55194 8960 59240 21763 47250 23461 47459 22199 50389 38479 1721 33502 12885 20311 18136 34372 55705 36057 16288 9575 63433 56681 35355 39329 28589 2050 59747 43801 30175 5525 33189 22923 58155 44157 12686 63511 50938 46283 1002 51748 40776 3932 61758 16166 55160 48187 58281 28116 36787 56629 34419 34625 60814 45420 16454 3146 28986 62502 55151 21201 32934 40142 14554 64453 46131 46697 10398 49054 34486 26203 28710 23379 6935 54465 57670 58715 48433 24249 3706 61220 34317 62190 62624 20496 1434 5791 4134 49767 5826 5671 41699 10125 26810 64188 42624 6761 910 52889 23412 56069 19572 63744 62614 53897 48948 54403 52984 18621 46704 17391 29884 30872 11939 1160 22636 14400 59519 16322 10301 30861 52032 21370 18107 11194 58362 24325 1194 20141 12367 53651 50961 63368 44861 47419 46289 29727 24236 6607 42763 24869 17223 64018 9309 13915 33225 35911 62815 8431 30338 43575 8443 28702 34262 43684 19118 22537 57156 13133 29851 22080 8668 55622 33498 25610 62277 5456 47128 17451 7552 28888 21142 63527 40489 12424 57020 15007 16585 6303 34055 58644 40848 55210 64017 60490 13637 51367 5926 31462 60147 39657 16619 3989 9734 52443 555 28614 42787 63293 27002 49484 11105 58403 60394 8625 13638 44889 14159 63381 30503 47251 11500 3609 12954 61949 32947 10265 56404 63028 34351 20924 54888 14108 49722 28990 8009 42250 13038 10268 61763 26299 62467 39242 44830 1041 4085 53342 18273 20139 57938 58835 26815 8966 54078 55316 3793 26977 10060 27301 59978 22296 33850 9168 43840 53529 3671 44578 50505 11544 30295 6521 33472 38113 37820 13236 54954 17345 22896 4175 5553 36861 47317 55984 12722 13068 60424 5503 62022 46133 34846 4333 40513 15771 3415 18461 64179 1623 9920 34531 54596 9348 39189 45718 38517 39615 39693 2444 55890 16880 6414 50809 23576 63720 41815 34116 804 43788 44497 60285 25334 24513 2587 61774 58561 52796 37196 42429 2644 4705 16332 42783 5978 63407 32971 45830 50475 4638 49270 2760 46715 5238 26085 42234 59253 44215 13630 63725 25642 64085 60258 62068 3580 27147 2863 61051 60827 31454 45874 56835 18709 37880 4229 62471 33767 10707 17097 58238 26868 38779 825 54077 45479 63072 52455 61805 42187 54491 9047 24382 11414 11415 11676 21108 40723 15444 45760 19198 1280 19510 28199 63706 12268 43099 34400 1223 45067 27838 42123 41162 55854 27136 58674 56525 35719 18479 24067 49177 19873 2472 27475 6378 57643 3252 61031 2264 20096 51516 54985 63670 17084 10780 43317 52859 55480 60444 24485 46303 12496 35571 1196 18665 20751 21314 40872 34478 19553 52590 12733 55428 23245 48703 23598 30789 20635 13891 28342 23067 52983 55202 36388 62281 22642 44678 13252 53251 59856 60644 39572 29341 63512 39026 48863 25735 54593 34421 63270 10836 42050 61125 63816 50961 55541 16772 24875 15914 22414 3021 6915 53985 51676 38486 12017 38711 25611 10590 40383 25305 63987 2914 25052 48066 63625 39031 58347 54299 1263 41778 16690 57858 54022 23070 55660 3805 24670 47896 50430 27055 23466 24192 57388 42672 58816 22836 25081 27383 19626 535 48480 21963 17912 52679 12587 55900 41206 62111 53323 45958 2851 10096 16293 14707 17993 12222 13040 1354 20733 50485 43452 48027 48705 54080 49586 53366 29069 44267 10669 5000 36003 52203 47243 55981 9502 2028 26855 26153 42434 41030 19605 11941 45560 30962 3016 46582 5648 56492 47138 30650 10321 42643 25770 45867 64218 2578 48264 59291 26497 56718 11421 3270 11522 27310 18109 40036 3712 17204 15253 55407 63413 4589 43356 38904 12309 39187 61308 9947 29774 42923 63387 52800 36191 9838 11250 51675 34212 58613 9523 39686 13321 33757 15374 49412 42112 38144 12968 12343 25624 27303 19981 8355 40279 54810 46769 60559 58976 56264 37299 2672 53086 34495 23049 29648 7488 20437 43803 2222 33779 49820 61352 30539 6863 131 39106 47816 25048 25618 328 4333 45817 1156 25552 60332 40026 17566 11658 38723 40896 18632 28342 59050 49183 48614 12971 53188 56905 3238 54984 24353 19178 18285 57396 21663 43676 13580 50798 42499 37611 57518 51393 8322 48769 16215 61843 13669 56415 7142 51495 42082 60568 14631 57768 42712 28945 9096 18434 45504 6294 9954 50848 20515 485 6907 55463 23582 29462 54218 18292 16403 3472 14095 21851 22601 22501 1868 30301 45108 18996 63236 41374 27391 17802 47722 39727 4060 18690 6526 37352 63242 56966 26182 45357 9293 15750 48296 56743 6633 64102 35109 6634 57282 20585 12441 58888 25610 7131 50067 47771 23584 6394 58424 54750 58159 57820 51774 63312 57110 24694 49526 9849 40364 39758 24896 58521 41292 402 7250 4012 35820 25887 40521 2074 24935 50347 13380 23577 7096 44524 10957 49112 56289 51021 2046 41038 13116 22204 5673 52780 48210 60435 46009 18183 42382 3009 61291 42724 52455 4088 55780 58111 52106 62271 7107 18361 9646 16468 50533 7031 19810 61296 46705 46908 4209 44938 48091 31466 62069 51679 45187 17168 49725 37566 33379 35176 11815 29900 42582 61402 61901 28882 47574 38966 56440 41838 58598 50392 59645 46953 50982 22616 51903 62743 58654 16841 23505 24263 51690 35428 15225 26108 42456 63966 43864 21492 57694 36899 17837 45338 30813 47699 20224 56292 50408 31050 35078 18375 11545 60230 51015 58312 44629 46551 21832 46962 38236 33271 12576 60768 41106 59328 59116 3651 60258 55645 6850 15094 12151 55246 19586 17006 32878 31591 22861 37936 40272 52712 19042 51194 26423 3869 47252 36599 8004 7413 10932 6984 59303 60286 50127 49351 31133 22249 27436 24864 47351 58723 22989 1842 35536 37909 33020 50808 34582 54331 7815 18587 26792 22140 226 11185 48841 3941 52916 39180 213 39341 51760 1295 60046 19427 50031 59175 24573 58766 43886 8015 49478 2845 46848 14570 35976 61757 31366 44274 24178 51695 52778 53116 43112 1892 44830 58102 63874 48919 38399 28852 14727 34104 22482 64076 10276 51685 26284 31087 14685 60952 37629 10750 11883 4353 43413 2328 41681 54479 46223 35863 20584 58648 30337 20509 33107 42 4028 32963 50399 18710 20905 16074 16567 48931 24815 55841 59269 49937 51902 59335 52203 63769 12132 51908 20971 32869 8590 43201 27349 36330 15489 38039 54382 61348 49443 39498 15929 34695 21886 28356 58286 24061 3684 51711 10461 51841 29480 3255 20427 4545 57659 37763 45851 11306 14330 13370 1861 56399 1196 61455 45668 690 41085 25254 5607 52456 35664 36726 15258 60395 30995 2731 510 9463 34822 39760 48833 39213 58202 61674 26256 14776 29747 44374 40808 42347 36764 9286 9017 18432 1306 13267 26326 38636 32826 60973 53530 17220 51814 52708 52817 25743 55241 25 14496 18529 25628 35438 17032 38536 49759 47652 30181 5064 53653 36301 6698 42211 3042 54836 5858 26726 6095 4276 20117 41703 9180 35082 429 40622 30248 65 31617 28127 11348 18344 12740 61165 40385 37061 31253 542 12226 6833 252 43045 19128 31432 25412 13000 13396 62254 56925 6366 16523 14213 56029 54006 24452 7473 16036 12600 44622 49250 48255 29781 28606 46034 55901 8354 6519 56517 44220 730 27964 6483 16780 57008 22748 63015 58499 39158 7082 1756 23739 3095 51857 25255 64469 27540 52415 25812 58876 12508 61287 61978 7500 25215 29674 5443 20540 37158 44538 13333 39992 14903 54749 39171 23969 30468 48256 40464 34296 39773 46309 47766 9904 56101 59285 62717 52927 9892 64186 36350 41022 36096 12358 39645 53568 43510 59657 55152 17313 20577 9697 14910 57227 22753 53293 30037 54061 36997 40103 23201 28262 35825 35583 31349 44773 10799 5125 43376 46343 49166 21008 62598 54977 61901 40105 41791 11941 34847 46888 28808 25754 51547 6217 46052 37640 9744 63313 4294 30090 36613 8935 3172 16002 50841 63028 53439 57190 33091 16003 31506 53526 34793 27865 13256 55380 41810 46738 4722 38462 61152 29389 2654 20201 36552 26922 15406 52964 36105 61793 20944 59354 34259 10391 17313 51265 15884 61982 39881 41406 60699 9941 60818 12785 13777 2359 9982 2727 896 42263 3114 9309 4035 21770 23186 27779 9801 58597 27489 28371 63519 24247 2448 62875 62611 58949 39208 36861 36225 42343 2849 49010 42421 22289 46186 55894 26480 19853 30240 51263 58016 7862 47765 59334 31629 38739 40854 50248 17957 47461 52886 42240 12142 26155 12370 5339 12634 12055 52648 21300 62680 15372 59591 58689 8325 7076 17778 40808 16871 5636 41146 24532 39209 36285 46718 9952 35806 26703 6547 53079 4460 10274 11547 22049 25208 37759 9755 13508 30135 43924 27956 57286 50185 47075 19534 15264 39469 14355 24085 13349 59510 5521 44813 44560 56661 33188 49607 37132 27732 35596 2448 43036 25165 61382 26408 23185 27470 41650 35819 24297 61428 41508 27030 26479 30029 39849 61189 53081 58179 46361 57777 46811 55273 5586 30490 29682 23338 24917 22408 55201 35188 25758 29178 59651 1660 23859 14887 43548 15 45600 4223 20269 29740 13801 44621 2430 56207 48588 14237 59225 12666 19570 46975 29722 15254 52983 23046 57761 10347 36820 39671 16933 10570 13287 55080 46023 25294 52497 33174 5125 4404 19429 57271 26589 43383 33611 6264 13213 62105 24077 50182 53333 50600 48884 52239 14201 26102 7259 34237 52310 47251 54873 56206 20989 46707 46487 5134 17300 24139 18852 28781 52400 40867 14857 37011 37903 25534 35579 9627 9981 20467 39935 56335 49384 25952 52909 11059 26164 30305 15313 19600 18837 3874 42762 61676 10597 47922 58597 28292 62032 40961 61780 30587 12925 20686 13205 26693 22335 55448 55117 19836 62031 12975 15450 25675 3276 38053 6461 16324 29934 48687 11863 14664 24704 2758 34456 63538 51788 27738 43782 60033 40421 55300 63957 51464 11025 42647 26133 47894 38040 52267 20975 5193 56901 61063 41462 44485 4497 59509 29734 18769 12367 3638 42701 54735 47900 23488 16526 17689 38771 2423 21302 57251 62085 3203 49692 54176 2691 19057 5332 5637 9449 63896 24001 64168 36932 41845 27806 33811 8109 27192 27679 45343 42428 2655 20266 51147 22945 2558 3124 7636 29580 58748 42108 29103 46453 5099 55004 45442 7422 37991 3443 28340 12540 9760 55533 42020 24432 5059 58410 11015 7344 41093 64426 58289 26838 57744 39580 60542 47682 63138 45948 38360 51365 1399 5075 24259 33360 15816 53908 20934 6492 8226 51344 11999 33321 42846 36076 32771 36796 8657 42193 14055 22623 24530 61230 35421 24062 32799 27061 46844 57481 21743 35464 25699 45627 2963 43063 10275 25775 27466 35337 61053 27711 16718 13180 15174 47751 54403 49646 42628 46266 15220 33378 64105 38706 31109 54155 36474 57181 8206 0 1328649664 +1024 35910 5335 17788 6076 57645 39544 1666 9974 22566 33214 43407 26844 25570 400 41728 42314 8951 50151 28506 33347 63234 26707 36967 62131 22295 60105 52073 6168 48222 54530 12008 30591 37431 12601 6083 55588 39881 58791 32972 6865 44689 41082 61315 574 5799 49684 39393 42697 55039 24981 986 9665 62398 3141 56352 54576 52828 49227 28388 44222 58637 7573 59023 59466 53321 28168 23571 62131 7467 15075 22048 52005 42449 6809 17221 9114 48004 50208 47220 52415 52743 12202 16004 56598 8049 50694 54785 27919 61578 54525 61782 17081 1663 36835 38015 7688 11902 492 3384 15333 58992 23038 34286 42885 49366 18307 19642 28535 44443 61601 49716 43356 44190 28860 434 5369 35385 13937 37669 62501 33374 23012 45445 22958 52277 60988 59881 50420 63792 27532 39138 45666 62786 52090 43323 38977 18561 28421 4322 11424 28623 53318 21815 21582 28400 41236 46105 28904 63232 57644 5710 16427 33424 29993 60092 21409 55996 43152 33083 52048 21424 33272 57331 21226 11211 7385 57244 29669 7313 2462 37111 46578 37251 39674 38037 30768 2557 51801 61048 19320 58516 55115 51025 48008 38257 63094 8407 7341 3308 42136 28731 16177 26479 38471 21306 60260 45264 5212 35592 48268 63531 57456 101 47141 53080 9943 42564 30508 40952 62672 47681 14811 2819 3810 15572 26440 31355 14998 43073 63450 11121 16428 38495 62752 60074 63968 23661 54737 17501 21237 36630 28869 24976 3966 10831 13050 52648 42052 17357 50135 61722 15946 52138 54590 20251 49848 62194 17298 38657 31213 54390 36683 29922 40597 59341 38638 52253 63490 25005 8316 16311 20730 34994 62490 3295 30635 49221 9895 12878 16630 23890 46729 2968 11757 43429 14995 2044 55535 57471 53394 56298 62927 55010 31400 30862 58551 34912 3497 29081 14065 50652 12414 59963 5286 2180 13496 60405 20501 62170 51255 21117 48057 37270 8594 43095 55716 1922 2054 8158 60460 23071 9223 2872 14031 18141 24716 50652 60263 7094 60297 21709 44790 24922 20268 13518 6519 52750 33470 29372 63110 41004 11166 3946 30961 24979 49467 15411 1935 57276 19958 49080 53543 61952 1192 5351 49654 27535 9038 16074 22236 7419 13466 4906 26426 59355 27119 11298 52254 30913 19359 60636 51201 7195 57325 52268 60885 4224 13348 49607 22181 42983 16250 6125 31717 18698 16054 56645 63912 8635 50610 29059 4726 2993 62008 41364 16041 4602 42868 21978 38619 51813 2385 31004 32931 37665 58893 33783 9842 34188 48177 20770 31306 3089 43769 56370 21614 51891 63164 6882 41704 44987 56950 37181 9890 49078 60013 38532 59757 48032 15325 24828 23538 43885 6403 2624 33935 35600 52603 3112 59853 21600 62436 55839 27573 20764 59031 9128 59699 26905 38128 26165 29298 26795 37517 27936 28871 46425 38572 36355 34891 24098 42728 34397 42401 62743 31564 42437 31296 48414 49811 47121 16622 35949 46389 33175 34147 21472 9925 6854 64308 37389 43975 16361 32791 25303 22411 33654 60458 50159 25276 9088 41632 51244 36183 11777 23165 29349 21488 31706 19974 31690 18953 44857 45960 36362 57852 63318 16075 24930 13188 44814 22864 13685 7629 50779 39876 64409 31349 20128 60186 35020 33418 33009 12249 37411 63447 26069 18988 44566 38021 20761 12966 14799 51142 55869 13283 3411 6949 1306 31652 45661 22589 39605 17151 35712 3560 46523 63356 33233 15577 43418 50608 33368 6609 28704 60760 45264 46886 17756 63912 62019 5769 55682 54916 25950 4171 32980 6959 18734 47025 4523 7847 47798 46145 11688 41141 15382 54898 54338 30135 42646 53430 18796 23696 29002 38678 407 35733 13808 17928 6076 50724 46511 64125 31271 3925 22803 40118 25647 63752 62749 17819 27580 38810 56121 13992 49267 31525 16882 28618 63492 6571 61173 29443 2290 59446 8880 1813 22500 52059 7348 59838 22158 24366 543 55130 55601 37794 30606 52301 20594 34358 46559 39870 13083 63735 14738 13117 34195 28563 1921 53791 29581 39752 35164 47240 54003 45904 57132 23953 39618 39524 43448 30777 39316 38970 2425 3791 58298 46816 2415 10082 11252 53826 22460 43129 56044 37170 60867 62576 944 48659 20841 15786 47135 7580 60996 48515 21455 61728 24085 31718 2267 12237 51515 57085 9884 16753 47283 12451 5653 57293 47181 40 43423 51431 54496 58381 30684 53907 9298 22725 39383 38093 47563 25523 27733 47712 8085 53796 57229 33791 26433 8403 38572 9667 36453 1145 6061 64427 20623 53251 28037 58190 11543 12887 3643 22827 51963 39773 30608 46249 63878 7750 10540 35810 64021 35228 8650 3434 10732 18817 57 44220 19302 60939 9618 50101 12573 8713 53154 14692 12317 29045 37170 51340 20936 42222 56972 56824 36894 58767 12619 7787 39381 34770 44802 14112 53221 57937 8943 11028 60423 53468 55684 10581 64133 49741 48596 10694 45257 60000 19837 43181 8090 7175 47589 17435 40189 16392 35148 56610 55611 3282 30310 45253 51290 27316 15382 15211 55499 24057 3896 14682 28563 61962 46491 11693 2917 57391 24586 50630 9719 1093 58470 7711 5947 24246 46567 11228 27907 1928 29446 44990 58564 26474 51217 24504 25371 47382 45987 3647 31294 64292 24644 34912 56776 61814 27290 34223 34651 42336 33288 8734 57297 58926 37149 56532 13294 27938 364 50094 58092 51121 27968 12255 38864 13490 18091 45818 16227 42058 38895 27864 36697 12747 42880 14935 31322 9735 12421 24728 52288 10442 42263 47416 54513 57846 16608 1371 22833 42934 36944 32868 9371 16741 8344 61191 34334 54318 44747 12316 22774 37955 2481 38205 39431 36433 18646 1767 39764 55189 45811 40912 58831 9271 5246 629 62844 52128 23081 30168 57651 54597 55651 19382 53296 38461 47914 53478 48267 22393 45135 12600 8864 11312 19784 45690 2470 22423 64060 42465 31121 7512 8794 27600 35392 61829 42606 62844 43369 31145 49994 28954 14876 939 64325 3752 57771 25696 10342 49475 5233 10949 36182 24172 3363 12659 27231 16128 15708 8740 28519 39773 17515 10232 1476 1203 28876 20326 39737 64055 48974 13689 52968 57575 40990 28381 22117 14308 62248 20484 4352 34887 22419 35969 31497 59943 24690 44833 61634 46838 19271 47192 35777 14945 17260 35642 25245 40756 11586 48361 54125 61125 33400 11594 30300 27958 30252 34042 5278 57372 13368 52365 7970 12862 2790 6052 21086 37970 36664 18426 29932 28081 7466 48232 9086 17153 20531 25318 48418 24265 40245 33440 49533 4245 2089 2348 61211 6327 56805 49597 55775 39055 10792 54690 41714 33403 36032 12438 59008 6010 61177 4159 30810 8114 54067 50918 37661 29801 2882 20247 44522 2851 55861 40646 18536 5366 25406 37771 56016 53077 30526 1105 49791 17579 11145 25679 38193 40844 5017 35481 25346 38777 10042 59499 43959 52448 6690 30391 22260 47644 15951 47493 1793 62144 19942 1339 37481 26211 20163 57042 16511 3440 40187 49423 44867 192 45473 45907 64336 47054 50515 60078 47423 7805 23901 63824 32793 57807 26711 37601 2848 52819 5947 14194 38101 12654 49480 48682 59738 42856 59475 27712 20084 34198 6113 34171 27633 34766 59902 53948 41116 51694 4781 43291 44044 32830 39087 922 22917 62695 16314 28541 56762 31690 41792 62434 50937 46727 6147 20306 53172 54987 17668 33404 46059 60214 39631 2421 54326 646 11663 40752 52190 57617 30860 62203 61643 16818 12679 48890 60696 45084 21277 56040 47090 55807 57027 10798 38265 10551 60346 61003 29818 45399 51043 31203 46112 28355 52261 25074 16043 44860 4742 51170 4717 48869 20730 31614 33951 9122 3098 57598 61516 51533 10670 5402 30089 9392 59899 60777 42239 6644 47544 3249 55020 25315 11539 179 57638 1330 30675 52978 25461 38259 7066 56219 27992 18238 32842 7342 14007 34148 36786 56017 43571 33480 54898 33969 948 45536 37161 41646 5688 11697 63094 53463 5302 45974 21608 17490 20419 59959 52234 57227 53234 59853 48100 20204 15453 57357 59049 16140 25131 21110 36942 22219 24744 6021 40351 8584 798 24442 52521 51584 4640 52526 46176 54202 17684 13050 47789 35052 19236 11467 15743 33837 21347 33935 16355 6683 25061 40676 42205 22449 52249 14252 51160 27118 23411 61208 19118 63843 38674 33023 13273 31724 16158 63754 55576 54383 2599 41238 51588 58184 59137 44749 57664 38238 39006 19620 14545 22378 33757 53155 28127 3841 562 34862 14479 11920 24359 2781 27924 59358 12629 1669 526 40072 22345 40884 49972 33201 50823 50718 28322 51930 56742 64059 51824 21839 47694 38702 34869 57819 38598 55867 20786 48104 3610 21505 42683 63928 5064 30463 30981 16006 5727 22634 13729 43101 34187 1026 53854 33361 33721 34245 49042 31640 14243 3319 57962 34386 7280 44461 52937 38589 28005 15732 18815 44656 16085 12679 10166 13531 16732 35603 46372 26813 26262 56044 12129 15722 44055 46635 23579 11503 32856 29398 24276 60037 40878 53116 6139 29053 9081 39657 45560 9764 29780 19587 10478 56092 23422 15040 24562 43835 27619 18838 45977 28497 52758 4485 21272 15939 26554 42759 43608 25329 17509 60294 61322 55155 60871 23887 47216 51416 40617 4886 52290 12405 64429 7057 24202 4025 27544 7767 2764 62794 53079 40737 2344 17518 14225 23391 32920 62481 3911 27701 33096 44666 61927 34484 48552 6076 13121 28601 60494 26021 4030 26421 2088 53044 50057 59264 16302 25667 28156 6682 8714 64177 46071 12272 64106 943 11120 17999 22015 27208 55566 51357 16884 52267 57032 9957 37534 16294 55095 3127 34275 25305 4755 46990 55003 10648 60035 10241 28191 50809 43573 11496 53676 7182 12515 7389 52342 30945 50970 23626 62001 17675 6164 49627 55598 36362 37402 24638 47611 2908 2391 3303 7080 23132 40642 1510 26998 48601 45622 24071 20452 44341 18989 48576 36125 12372 60614 48098 47561 58582 34506 56000 36085 12615 3036 2345 35869 64353 27553 33278 59070 59434 45490 26 47888 4686 46784 18092 13843 25366 44929 4988 15552 8984 3233 9817 41808 25717 18463 10663 14950 59343 28667 42014 26177 11990 43219 61102 55920 45032 12564 23480 29180 5250 476 64227 2563 134 35394 50946 19392 30107 43235 55310 33453 1452 44585 62266 22108 20486 46972 40812 31044 61553 50117 42788 24212 29668 6031 21675 38652 5740 58418 28011 46497 46616 7987 47384 45032 25768 11762 3337 30692 18375 33203 2747 8021 25858 1756 61447 46599 39034 4498 9795 64315 63182 49062 9222 14446 6382 58809 46541 20665 49202 46494 11406 26750 13126 53851 53835 27057 34921 20697 53334 29010 14255 63086 23373 9597 21493 25915 25292 48763 44118 1571 11971 30971 55223 34210 19467 55520 43660 48807 13400 46069 62393 42654 56888 8340 54973 42809 61975 30159 18037 15579 42521 53857 39416 61187 38878 26844 31429 31725 2170 3799 26181 9240 58871 16459 53678 7916 63977 38581 42286 47342 37536 8178 55444 55259 41689 42061 8220 44556 44783 63322 34643 5492 45879 23068 35624 36538 5611 10702 25016 19782 672 38677 24063 40177 11884 63139 57413 24971 20230 37294 56713 36507 22727 24061 16922 51372 32879 41652 60630 44660 61157 52565 9552 37089 18406 13582 19922 61108 55438 31313 4805 11749 36579 10257 3953 18595 50965 24033 27027 33287 57265 53988 31008 32960 34074 45772 24961 29885 34521 56315 47721 15761 63926 29337 57326 45272 38731 2049 38855 4703 2619 30727 52877 56519 8323 4344 47457 2046 48694 26252 28686 52265 47808 43175 4456 47442 40466 23347 25760 9029 834 33819 64295 52096 52927 37828 56326 56494 51934 30220 17990 33060 870 3931 12571 16342 53009 23993 52233 23292 6667 8524 48984 41161 10670 55233 9144 37449 5202 62216 44416 49545 58564 42195 33420 53743 47929 21731 39561 54605 29110 19380 43691 59721 29931 8401 20275 59701 48591 45331 56283 126 30041 62251 3010 285 27276 48423 44088 14084 46656 58483 57769 46018 58168 16048 19191 28305 2698 41622 52322 25078 10604 54504 20990 42998 45362 38691 12505 11720 48634 35238 38779 46506 17420 2554 57703 22897 53853 7240 45461 44826 37177 26515 47137 16697 28446 31638 56741 4736 64429 14666 27215 45130 50844 60241 13998 12848 43699 54065 19538 27845 43827 58549 27901 19763 48841 62331 12059 9433 19904 59131 15567 40695 61376 52203 61963 45857 16709 2931 15809 58910 6185 20617 54792 18236 20865 47411 30266 60528 25590 24383 8110 58968 1482 15786 31304 10813 40506 42723 59037 10499 21144 49504 26117 20193 48961 51106 26175 46625 18324 21418 53827 40541 12643 63358 34604 44106 48374 60790 8003 7780 7888 18367 43574 57996 27037 49319 11578 14455 31407 19286 19118 40505 22807 63929 47409 28635 10212 8047 526 17668 15978 6337 6757 9295 2548 26010 35748 7309 52368 56192 27389 57546 49165 17430 16690 34417 8281 9459 27272 27017 38496 30248 52463 54008 22326 11734 50058 63637 29501 61483 60063 1078701470 1338170674 +1024 42890 62122 26337 6773 726 14829 2132 26109 61678 1134 44189 54077 46051 31221 59942 50668 29964 53851 6764 6810 23078 3956 61389 33886 39179 52695 52058 8237 44273 60742 2525 24391 63071 6613 34671 57188 31532 56215 30662 58153 2503 40081 62316 31635 26323 22277 30381 43029 25460 62756 7041 63559 33476 18601 46576 63396 59968 9401 59231 54785 10473 22552 6504 15703 34672 3407 10608 50019 26572 49161 4249 11364 7724 12692 13754 42418 26061 46706 28313 13904 2793 17733 26192 43685 56679 8534 35955 35461 59095 13877 48921 39156 9618 7237 50561 12283 54471 54482 54863 37474 1290 59462 18754 38499 41074 1852 24726 15406 39466 56010 19664 40751 46000 19833 15529 30534 58594 37401 11254 55819 48722 57353 59483 14097 2662 25500 27453 30188 15621 47953 20652 33904 18562 18072 11036 44827 59574 50692 51595 60539 52458 33347 6261 17647 9945 40052 28832 27852 57450 56763 31732 51334 1286 15723 41931 53622 49720 61321 55941 60624 18951 27821 24780 50609 54623 3927 35625 57068 24963 16569 19090 53777 57288 36882 17198 34721 56133 19153 45589 11715 8869 17182 60774 39040 19428 4596 26471 3122 54649 23097 24384 18493 34901 49794 30383 20433 8111 32947 3456 56181 41703 19859 12774 48020 53909 27534 854 25939 63042 37165 51710 45123 17304 61793 47131 18330 35727 2829 44389 30944 22040 47554 61155 15531 35542 51772 44478 8553 37669 11257 46929 42462 22563 56343 16364 63778 4529 54451 10424 38220 46561 10138 23316 33923 43797 30313 41713 45691 53699 3604 16582 34039 56270 14307 60335 7197 16326 51117 61948 39446 4025 26997 62524 9024 44674 1109 23376 6873 43879 1476 15277 34092 58967 16212 24016 56727 23038 20879 3351 15416 9216 62902 13811 38736 27302 19579 54172 44927 19068 43501 9467 39300 28444 63436 60301 12021 44331 29281 11670 7122 46717 8594 36568 28006 12690 19816 22135 39825 62873 13474 23708 16457 61397 20298 15772 12915 39599 25157 23173 36101 34569 2607 41064 6825 11377 14882 23324 2873 36485 36002 19782 21235 13161 59888 44817 54941 46911 49628 5876 28015 63661 48513 51582 45208 30768 62449 51060 63999 57580 63807 29684 38545 30848 5273 62070 25613 8354 63807 33967 13455 2529 16804 42581 24798 53314 52505 51 34004 50968 2231 9033 40215 26683 30066 18172 19964 42636 52619 14083 60235 23877 379 48188 4983 28299 52513 10793 58403 56534 26136 52951 2555 64424 23993 55481 1660 43830 31021 49671 5283 4829 2270 57075 60848 48219 30746 38991 17169 12074 51651 41039 12506 61316 11904 38630 5019 56168 7473 56448 57059 60909 30833 31210 946 34379 5193 59123 15442 33951 35408 21315 13549 11753 5314 25793 26051 16133 47673 56609 14127 64147 5911 34 8543 18420 17909 2496 27284 37318 10729 18453 20046 26353 25687 38275 22121 42042 13245 54104 56303 8 47055 4844 7912 50715 54447 33760 41753 45743 9816 30386 18238 6125 60184 35098 23098 39574 64380 33809 9514 15885 58150 39143 38893 52906 46445 28241 36602 43709 57140 10603 21449 4953 29048 40886 35482 24778 56919 26873 54198 2080 46184 38318 56240 23918 28088 23479 9092 54199 39281 38538 10473 44742 5271 2226 40150 57694 43719 27381 57134 55525 62944 48812 33450 42696 12598 51958 18467 4993 52509 55898 40392 57273 63925 49670 59959 4399 57485 59109 19130 31717 62175 63915 3266 30543 58704 2363 43251 40835 31323 26316 22809 42135 44100 46733 5309 33547 55093 56413 26210 5879 5890 45878 14243 14859 49418 42079 36781 28960 57746 45957 57356 9946 7020 36761 36413 43538 23489 11064 39187 28931 52230 33369 21909 34376 33936 8529 33486 16553 29735 35148 38278 49544 309 42314 37663 20298 50776 57343 38887 64094 21471 57266 36685 20711 47498 4055 51999 8574 57778 24445 63276 372 62013 12472 140 58296 30131 42989 13824 22631 11592 46096 59510 41452 9262 48288 25843 33099 25659 39861 313 8205 56589 8101 24782 15214 43146 53687 64231 15045 48896 40809 35742 34418 61437 23972 26903 61645 21135 36728 25808 20691 4416 24349 9143 27007 25523 37522 63995 50359 64509 11633 47265 16457 44695 59750 43194 48373 62461 38165 30080 24691 51548 29658 47930 16555 49483 37686 17300 33729 4339 38109 1953 26386 4102 34497 14250 19780 53994 12516 59052 26684 45797 41967 13936 35562 1876 46788 4888 4724 30398 26173 46015 45534 11796 21885 50081 2093 7923 60146 48755 4917 8470 47556 36588 7477 18039 4652 20525 43572 47994 40616 44663 51972 26573 42099 20305 11955 25201 2302 62825 34705 49079 20236 45707 56089 62699 64161 34540 12334 13221 51399 60764 9741 62258 60406 35848 52087 30409 57033 33744 34407 24798 61535 13275 8913 13818 1568 15838 55768 29600 22112 27993 35951 57097 45275 6268 34330 28724 13843 43132 22523 41049 27790 40107 61379 19405 29314 10405 14567 4209 25317 44736 3131 8492 43293 35189 29921 10741 12889 30746 57828 56930 19350 24632 2814 49192 45943 47210 43977 49132 870 18132 58835 34006 6869 27416 15713 38414 11815 17995 55330 50725 25557 11661 48888 6362 17621 4098 47675 6452 29802 7248 59480 9160 3367 55974 12199 7230 650 60728 39189 56489 42953 51155 14488 20943 53085 46007 5262 49156 60041 55773 57393 37666 30450 38879 54755 9011 35576 6564 62733 52866 16494 48469 17686 13978 5849 21759 51305 53109 39390 12154 37768 47715 49599 12934 5399 15361 26518 52803 57930 18181 15948 29788 7440 25762 10845 28088 48413 6807 4475 35725 28657 23090 12088 31260 59781 10733 37423 43648 30120 51132 17993 9721 15752 48172 16491 18583 8534 15934 49920 42292 59736 1327 38876 52476 41652 44979 13535 42758 11756 24533 54058 20412 27534 60188 58345 47792 3547 10650 24855 44822 6890 44859 58415 58298 19999 13102 58309 53757 3855 19077 28132 36883 26760 50612 6282 17876 2428 43129 6252 39069 6829 8014 30068 16483 25269 9020 49032 15189 1679 13257 16692 40276 60231 46269 35935 25954 31727 36882 62591 54582 39713 63766 42283 55720 58754 58170 45969 64198 34905 4518 23644 37542 57845 16690 58554 31262 40715 9891 35121 41857 55497 29375 27980 25021 20119 39006 23729 41206 58266 17310 18404 12887 20532 14514 30753 28627 38067 10183 21699 53445 52290 39780 62915 4407 3187 24278 58516 808 47215 25612 22824 24255 37122 7417 37999 10790 19943 30987 26432 43633 50787 170 29385 25596 30080 36651 42633 11896 30051 30902 31682 43239 3733 19241 7291 26338 41475 12814 43634 46040 62659 36178 63845 24511 28167 64438 52796 57480 2339 37336 2281 46725 30556 38622 16135 22445 16155 41705 29130 33288 21368 38728 31696 7019 50633 29148 54897 57229 47339 36836 7371 49599 15425 33684 5991 5173 57773 12655 49159 41712 47471 36458 32896 37177 1596 44592 2500 42430 59691 23688 41943 41084 58300 53466 35077 49026 6117 28337 38477 42901 2604 21524 60501 11342 48466 61979 63535 62159 38034 36731 18461 6469 4905 19660 44626 49603 50288 23896 40578 12564 50291 48405 7743 54095 3325 50602 19815 52034 59320 36809 20282 49851 56849 45383 41218 52914 24205 29209 14429 42883 13927 19408 17156 12028 24079 42848 11529 45206 47693 20928 62147 10983 28305 863 58423 41922 25496 53105 49627 3783 16243 45307 26760 57257 56586 53941 15171 58975 11960 15102 7982 45485 16262 1055 48764 48064 42302 63338 26403 33871 22402 58156 52460 6244 45809 40471 15764 20667 49054 29048 43647 13515 52193 44555 37328 8659 36502 47572 49871 3200 44076 41677 8192 41641 16265 57849 1550 51777 47391 40438 37902 1275 11557 53579 17606 21630 38686 60497 28996 10379 16720 41423 7930 64096 53851 24138 13475 14829 44265 19179 29977 58877 27967 52043 44786 35931 8090 19177 40732 39544 50265 27716 55098 24387 52891 40231 1582 31128 52529 61030 51557 50908 63774 12555 17234 26076 61737 17858 59985 3829 831 51239 24274 48083 17850 55726 49604 55929 54916 10262 4305 22778 21124 63291 48114 1183 35328 38539 15586 31021 36014 58789 28357 16419 29122 2003 47610 59968 14776 37424 10939 37648 4656 14517 54936 50927 24670 61936 27003 32871 25883 24970 52352 49691 57607 37885 9332 52646 10580 28773 40330 5716 45798 1236 17189 61934 37758 45486 60120 20379 49019 15955 46824 21711 3035 58950 2972 60299 47858 44151 25722 28165 21039 8003 4158 9352 48561 54394 44409 11183 60382 29571 32877 37056 55066 1030 7696 10697 33055 63801 37405 55049 51996 20626 12762 18765 59214 46930 12828 54003 24407 49425 46670 28052 12711 63055 51026 1047 24649 47099 44742 2194 22275 21395 13979 13862 14547 49080 36654 21672 22442 56269 13678 3509 22550 576 30436 19403 49489 19663 40383 64496 22497 4360 63854 9779 25557 15011 815 41679 9844 8865 43491 31096 43957 47228 38322 34607 61151 5172 58575 29382 35377 17053 57394 8936 39231 24212 55743 36673 21737 19510 12743 53958 52707 48778 55408 81 61899 8969 49437 11502 17056 25927 44418 48090 31135 45557 35009 2617 20521 59409 38647 38766 7818 38703 24184 9748 62085 21228 61323 384 28094 35716 19495 5037 39830 4007 10942 16797 46526 5342 45250 53749 50963 7067 28990 44594 64219 22812 33815 53450 11564 47788 63018 18780 37573 14640 58634 28505 55966 9029 16596 18500 49932 28066 60648 19566 39615 31281 61071 19269 52460 36368 19527 1478 42685 50678 58811 57038 15883 51893 9410 6255 63028 57770 21535 58371 6894 39153 2597 51501 44409 5881 20815 43354 60337 39753 50083 15663 25301 25764 16467 44666 8488 13728 14081 44936 20736 64230 4957 41768 5815 14170 23922 47790 12228 7149 23435 5139 28936 1996 29204 23763 3801 41681 52809 48949 58048 48121 48791 55411 36957 49216 34906 14763 54046 7217 41338 21328 49563 35347 54553 55333 39072 31135 30147 31113 53799 18109 16116 42171 8256 6230 30251 2326 55569 1979 5161 8912 11328 55047 17989 53636 50798 21802 50292 27912 57968 46257 9928 44696 62483 39888 33903 30929 19237 33956 6404 11863 48140 57043 8498 24280 26280 9707 20628 12704 62419 59219 41006 54049 6898 8558 30571 5162 12352 14352 5331 354 49978 57788 27494 58280 34586 33567 47550 45789 4955 33169 27238 25087 60173 58948 37445 49093 18183 37260 56091 60310 10045 8976 56827 46022 429 36445 6547 4381 39569 52944 53959 51389 17737 36537 43208 59203 18371 17268 10081 40755 50730 13703 33122 12981 10953 35550 27134 21483 15684 10436 43083 53635 59560 14106 58489 494 37280 37163 50054 18514 18053 61288 35829 61350 28286 39333 49715 61260 30000 30323 12978 38692 57399 48243 468 24756 51447 42683 11054 55919 17343 53518 671 17476 51996 41692 6888 60540 22060 59014 12336 64107 23781 46768 36336 9025 26456 42122 61262 19085 62804 52793 14584 62441 23502 25491 21904 11234 33440 5807 5832 58845 8809 40757 42424 52702 23776 57881 25219 25905 4384 10543 13364 33183 56943 4381 55908 90 14845 20339 62644 43468 653 50786 11701 41346 8131 51368 43230 18708 46477 13931 48872 46487 11063 57826 41432 59695 44790 14339 15519 21744 29066 31254 37145 56964 39888 2060 49123 57740 28423 2999 49181 29955 3341 13597 48555 49553 16199 27363 28747 47777 30651 9731 38033 55203 44988 53405 44674 22383 2816 35988 59723 50237 60097 11739 37248 51567 28526 50676 47617 33595 39345 15900 28391 17037 19366 58857 26366 20570 16779 24026 63417 43405 30110 20233 46433 24354 61549 12981 33253 53962 12473 63570 44549 19450 4442 48277 62556 34061 60545 64456 34344 28238 19055 26638 12050 13301 38270 46710 23586 42589 12334 30596 825 56914 6056 57210 528 55264 15781 36070 59302 58483 57141 13249 24689 58188 18388 60904 27976 9008 38650 49037 63526 15645 22902 14014 50217 63536 40080 25514 6717 49594 33358 8635 29770 27561 14304 49078 31370 25214 59508 25559 63238 42815 10718 51985 28207 39381 64028 30298 27077 5940 21502 25748 61714 49685 59008 49177 11474 42612 53841 53196 43042 51596 28322 23878 47471 57614 9612 15977 3614 16689 28111 39875 17422 38534 46559 49504 1994 40803 29365 8800 8134 55430 43893 45412 16019 11573 58298 61442 53706 6149 4348 3676 17356 12622 40138 28729 29364 23157 58142 15239 2854 62836 36502 5815 14010 12729 1937 51528 809 57709 15303 46020 27138 29284 4579 32780 51851 40700 51247 35807 63868 52288 63995 15432 42282 6815 6779 35314 63123 11374 37953 19339 52288 33623 63788 46170 36079 46024 44294 48549 7954 19006 25965 59726 39532 59237 45393 47373 58075 9000 6965 17522 40889 632 56161 55474 56066 61381 42027 21803 22853 4181 22200 38610 55394 42479 50621 33414 62066 37331 14744 29601 59271 64043 9293 26984 28566 59211 2945 13381 57388 15759 2722 26057 33757 63869 43613 26694 60606 31603 0 1294944555 +1024 40493 12891 35842 8686 36514 382 11051 4116 43921 30982 26045 48324 31027 11388 1814 40758 14471 23211 6684 50155 39643 41169 14794 36045 33670 37930 43736 34343 49994 33118 42346 56852 4206 633 50284 17773 11027 20795 58006 49871 33052 2618 21067 29165 5309 25478 6549 40383 1087 46842 9539 51783 4081 3177 1720 17900 47748 47432 58507 9373 26 43646 53123 43296 33712 6171 58543 47333 31180 50980 12047 38710 16883 39966 18892 54526 18170 58019 43176 63043 45021 18792 17123 30332 3122 48434 38063 53200 49411 28234 16882 64321 10400 6191 5184 37727 53467 50595 25136 11404 29515 30927 25298 31542 26115 25143 2748 51242 22243 56909 55516 9555 50238 20521 43370 28536 41398 12205 55393 55738 59473 19292 24705 8753 37571 61172 10601 6057 26939 15638 26659 33562 40827 46715 43039 60019 28975 18221 35736 21144 3795 54189 54104 60508 16547 976 63679 39595 43912 5341 58460 11947 15384 41793 51501 38263 20847 46318 43312 26092 41204 2390 17614 36186 24259 34359 27061 60053 33834 21461 56507 34109 63029 1660 37745 44376 48891 47436 39823 53451 50946 45124 48941 51693 30626 33831 14496 29895 26769 33120 25077 58054 212 773 24265 40265 56358 26139 27280 39961 18522 23757 28495 11789 59789 6900 10131 2592 7262 64028 48955 53872 44742 7305 50762 16120 63256 48036 18323 21393 11798 11855 39764 8171 3291 13096 19690 40852 326 18407 21317 16695 35785 44050 42405 3897 14957 42648 62160 58989 62932 53609 55168 37382 27737 38685 60084 21224 35864 47615 45930 22092 15644 8166 31232 53603 37374 27382 36275 51354 29921 40843 53952 45646 6098 26048 30604 59370 11395 18553 36861 17208 63661 26643 63885 29032 8441 7579 15645 60249 29244 15849 55049 52533 52710 35125 16009 539 36450 25656 59821 27615 26279 58845 19044 5935 36344 27585 20438 24261 153 28261 17830 55805 57743 7156 52405 4107 40415 39247 22806 23736 44380 9010 39874 16634 29831 15504 38122 59190 60134 53900 52784 47223 20116 63223 37854 31178 14751 7313 21630 18879 62170 24256 45000 35129 51507 14574 53273 46821 26693 9051 5000 47208 26490 26166 10342 12613 7898 55195 25429 22761 38607 25815 3377 35497 30216 21820 49654 55109 27784 47655 49399 13075 14489 44856 47968 48799 13330 2639 25436 30113 27253 53795 19143 51723 44043 21892 35644 40356 59173 42673 3167 34851 2048 939 59932 62009 3387 3873 55370 28546 25985 28892 22901 8737 22422 27064 11628 11499 41034 31005 28606 6765 28004 13908 17981 61906 64258 28624 49390 48361 26265 53960 9442 17325 10361 39181 31598 23885 49600 58175 57843 10184 26612 393 62889 19571 16701 3658 55839 36702 17546 61183 3669 41886 42673 48055 53561 10641 1587 24665 15781 46516 40053 43000 47310 46888 49482 9637 38735 46992 52906 28224 21191 19347 18195 25785 49744 58937 28880 3194 17845 57736 20686 55733 49151 63444 43609 63357 35892 55036 26927 25682 11 8761 27301 20446 56414 17439 28360 10852 1395 35675 6644 24524 34581 44032 22360 21701 26086 31580 28695 1954 45058 25073 48668 58350 50815 30031 8666 36516 25982 8649 11851 51814 38186 16767 58581 32935 7748 8574 3387 27592 47945 51560 12588 57873 8744 22591 55828 43323 58249 54398 44847 64369 58303 48621 41398 31112 3482 19026 49520 2020 35817 11853 49619 32983 856 47033 37491 14677 48052 33369 33167 39227 12723 62448 16147 55838 9450 30563 59632 6512 23730 8923 25237 9266 62304 14474 57789 8064 57682 42301 8585 29546 47982 25925 42253 13556 22622 11087 123 51225 36569 57772 35018 58635 63262 14368 28564 47696 8573 24357 31620 24853 18819 56793 42982 19716 31121 55858 47972 28605 7455 63142 61626 8008 20761 4926 8260 29920 45175 44152 20846 12720 16815 48980 1674 2017 4427 53263 25658 16834 15635 49742 60279 26878 52394 58927 34211 17785 19536 55228 1183 9003 12903 42166 23714 7416 29960 25721 63400 58396 33687 33653 46313 11269 28452 27138 54081 27132 57151 56341 7640 25068 14578 11670 4512 46777 38157 35110 24651 37556 49763 5514 38160 64374 15147 63305 27363 18644 7690 30401 12598 26601 37155 2026 8784 40181 1918 53851 6686 57961 38233 19176 61601 5066 22485 37499 56210 55846 45291 44669 61599 53669 37100 24020 63103 26770 33755 60244 1454 22332 13944 15651 24982 186 2142 5151 10562 18585 34230 18601 45422 55686 27227 53341 8686 10864 25968 11338 28246 19583 23227 36745 7542 38744 59287 61542 47461 22816 21868 48985 4920 5876 36973 13205 44571 57360 14010 58773 61245 24872 26103 37996 3189 56548 16088 24378 26160 395 59090 5727 19371 24016 22804 58769 55278 1568 48514 61569 48350 62470 7746 17798 15362 41501 14568 48835 8918 12187 12220 40240 63398 13307 13243 16648 12317 25851 53343 54153 52616 7478 39290 26437 16913 10259 23369 17559 16996 60442 5432 56078 57575 63012 57967 52753 46210 58690 47676 21800 28948 20086 47066 60756 23270 6146 32985 49507 20662 2417 14594 16067 32775 46481 56575 39878 55390 52702 9759 10791 5210 24296 6910 18372 55372 35630 48948 8507 3267 55412 3359 27315 19010 8024 56263 33238 62429 47593 33448 9356 11260 61128 33155 12099 1967 53287 50035 8524 22968 14484 13708 44552 1427 47452 16580 58222 45609 11454 12430 51721 52171 18289 27637 48836 60214 18006 60527 27928 2804 24856 411 61605 60332 49985 40993 2213 64464 17746 23236 20050 54383 30347 49954 48996 33644 43534 57650 5106 34928 56366 5029 3404 846 54415 52907 54306 59259 28536 12230 920 33124 55398 16541 35124 20020 33503 62811 13173 12498 7363 53355 57845 41006 49911 42112 59310 62582 15588 3731 43514 55763 8350 15204 48491 17328 63731 30114 15772 52058 42255 14339 28375 2179 25535 31140 4819 40837 26472 46626 14561 56230 28826 284 41280 52907 56875 48740 21538 55537 63588 12250 51489 56804 2517 36250 60743 9827 17152 3082 60767 16534 47489 56051 28840 36515 62627 14766 27166 42745 27166 39441 36964 58802 19803 31244 39044 21382 52833 60074 48093 12097 47526 27678 26813 45316 37631 35530 36894 1842 37377 17562 7894 60707 4784 35155 17490 63107 7875 512 458 13927 63305 63342 2663 37337 17560 10043 37767 27090 4060 12401 57770 33752 5654 41945 1001 14535 48327 3567 50844 61801 61691 35134 12294 52983 24743 6085 40789 22832 46693 63520 28092 41693 15400 11880 26466 25053 26122 10451 27925 2954 33131 36164 24169 22949 9271 2628 37854 1675 31040 21170 8026 60238 41726 58862 31414 46044 52305 24675 40624 30391 50792 61318 36958 41916 49558 57585 43737 58794 13385 33963 23131 3643 38307 16166 25817 23531 7079 61985 19487 28475 6150 36961 60531 18969 27573 11443 63030 63070 18691 19364 61035 59987 56703 48784 33540 3421 45577 45882 55958 58403 34409 59872 43418 31303 50418 46142 19499 7725 40551 33894 26587 39504 14581 48848 63709 1249 42688 50350 21142 47321 36045 38938 35899 53735 49647 60056 23486 582 24413 48196 30981 43009 25410 31118 13101 63389 39824 10076 58685 41087 46619 56154 18729 63281 44865 39492 14477 7837 13601 29989 10694 58268 23565 11939 18347 49645 49838 51992 9054 53978 52083 28372 35175 11661 62129 9346 13911 53718 53162 43029 9951 26665 43170 62393 51344 33383 31181 40309 47331 47971 26721 20156 30851 15416 26235 3757 29692 43661 48082 27268 48013 60872 47666 3944 9365 26057 34807 49651 46836 52667 40075 47029 5977 24082 8239 4355 20622 58254 55123 12772 10765 31252 33647 27048 57570 35002 13780 22146 22655 27909 24791 58806 54311 11263 19384 42255 2777 52327 23740 19331 40993 60507 44554 2266 15221 57222 59629 58253 13929 17836 45421 39743 29932 41808 34343 14083 40848 512 60440 41515 20014 3318 33661 24814 15964 6713 33712 58847 56880 26864 28695 58072 56317 31374 29629 14937 56287 37188 21635 45142 62846 64285 60809 29852 45379 3595 60687 8971 21698 61551 15039 8794 38367 9296 55484 25833 3829 24856 40439 7892 37974 1552 49553 38644 22918 18762 54365 29505 42048 4651 50375 31425 50133 38260 63084 25232 28801 16021 20120 49906 11677 53784 48029 40119 22007 47834 43456 40626 47881 32865 19004 62282 35431 30822 64194 40268 15181 29933 4209 3287 9092 16191 27617 60398 49164 60920 6384 62323 28004 38610 26421 59182 39003 40387 24818 38688 38678 34154 38952 39202 60624 57468 30808 39385 19483 4814 21621 30047 16363 21228 10474 34185 62346 9786 56010 16723 2131 37843 61872 64091 18357 10934 58547 25266 4515 57300 35592 13594 57541 57634 50901 53282 45111 53406 2384 10372 12188 13702 48475 24424 2844 18752 56324 42376 55502 57827 28630 12553 16972 50186 2944 38851 13078 8146 4820 22923 36057 294 11845 43290 63818 37835 15503 21039 63708 10879 54770 42526 36577 1259 9616 24971 11768 27573 18844 14827 56975 47808 16870 1541 14690 3757 46369 49953 10145 36495 22179 27569 37581 30913 3398 28003 19239 12443 48557 25593 30834 53857 34513 52463 36804 28164 56 47590 23501 22444 4484 33059 36193 3467 59668 8947 27038 6730 19942 3526 43925 58576 54615 29690 33688 13258 37597 13727 3291 37305 23318 25342 56948 7549 27019 60772 57945 63174 19370 58162 47211 53841 13949 39242 33138 28214 22858 63164 1607 52918 39771 47469 2963 41003 6099 48404 6462 5844 51393 24735 14274 21531 4357 22406 6185 39678 1093 10758 19252 62739 3257 33309 27702 12948 14638 20890 12109 48516 22171 7890 61692 28341 34142 24836 53811 37081 18260 26141 13507 59944 11844 15800 34188 43064 1162 28930 18268 19844 5033 12226 25033 48389 59078 47505 12463 42087 10569 58685 35142 40443 34650 26710 38265 16276 6901 45130 64419 58275 20990 30730 9879 2106 61710 982 25400 41914 24305 44203 15297 34141 39696 46082 21988 50682 12357 28084 47610 45533 12481 46193 21804 854 45723 18566 29914 50389 55067 17382 25202 15644 23104 29006 16066 44906 39457 60421 40109 18999 35572 51940 38089 29148 54239 5255 59276 2951 50707 20031 46096 46682 63825 56771 19816 15930 38046 5091 41972 52918 16482 27746 1962 29536 48919 44022 62176 22104 54940 50068 31025 11584 59995 50930 47825 56333 6658 34698 12083 58859 8161 28693 20863 45548 49454 27921 21425 45245 62746 49162 61740 17387 9267 10096 12395 44522 37766 57560 6030 4897 48696 5824 56923 48803 9272 53353 46634 1259 41355 59008 20104 39293 55086 48653 13965 33856 27738 63556 23640 13144 31388 22108 41453 13034 16214 13919 38356 8925 12666 5576 40829 36506 43170 5859 28456 38810 7995 37834 30204 13903 22232 46513 3640 25422 20771 17186 57211 6471 44482 61073 14048 8948 45957 27230 52034 14877 8722 11444 61057 59120 47338 28663 49218 22234 29696 45750 37134 54818 58472 12534 29082 11928 30138 20028 27429 16517 3705 170 5380 49799 12211 2030 42412 6955 25472 30661 61499 58767 40503 45751 46955 33246 35440 18142 42817 1527 40450 7452 6944 62821 43528 35531 24010 40758 11943 26276 27406 53258 18775 22071 38294 52993 38079 12107 11233 51561 19004 46577 52949 34694 47662 9781 11568 35527 42017 31731 27416 38897 44688 7255 43694 10514 57684 35937 25246 35627 13207 43769 56401 8765 56484 15358 53288 8637 37709 29090 61841 14901 57470 38517 29758 14874 62162 55343 42788 38429 51759 33010 26697 57156 18289 63365 40407 24819 50113 6976 4978 15650 5972 8748 51007 52417 28599 5259 45041 59126 22292 1498 2196 33626 35205 18676 62717 5163 0 44019 41640 37491 6214 41778 6807 49002 12369 27918 52955 33225 20161 56462 6578 28309 29707 25089 59889 17632 14143 43370 51689 56195 38608 14586 24508 42951 29350 56327 8726 15653 25403 15853 2939 53970 6457 51562 62103 12385 3580 49096 49059 45572 47562 47777 43575 23183 3001 8294 34512 37664 5211 43098 7032 41575 39983 39886 34088 57350 28703 37600 22446 11164 59420 14149 42893 39207 56003 41505 54135 26184 48537 9285 42761 3864 29964 19285 58769 35416 10202 59898 61237 2013 31079 36778 63805 4448 51112 9742 57912 57267 22500 31631 60909 18912 12818 58172 19383 60577 36671 54944 62589 60132 52677 39452 41625 23085 4447 53889 37715 7406 26276 55029 27664 11740 15186 13610 1481 55851 16576 62152 52261 61974 59809 43617 53458 17224 42634 40367 25986 7769 61317 42815 17198 31671 35778 1003 2979 47339 44439 44629 39356 16050 59441 17406 48704 50469 11658 10024 15039 19895 31486 35316 43698 7397 15833 47629 47865 33265 34470 56390 60259 53841 412 6800 61982 12524 6576 36685 1082 30383 62581 49214 14649 46944 42777 41517 38465 14786 47522 12799 51446 1582 12963 38533 61335 46195 24678 1261 4996 47267 18783 46025 61965 42893 49177 5784 62641 6561 55537 51758 33310 51225 12059 52992 53492 1123986126 3466807499 +1024 30882 13414 12260 37984 34711 57719 15953 57877 46930 53099 3353 11043 63593 22109 36810 34222 42666 57046 56271 45480 49447 60766 51025 5961 57497 12958 41481 7295 21346 39739 49954 7898 51047 13260 11299 44074 55059 33775 10852 57266 1978 50991 42890 35463 43925 61650 6836 45407 27155 6806 1839 53486 51474 19908 46041 2208 19167 26419 48108 40426 12057 61926 50321 41307 20605 54110 9982 17987 13263 40245 16961 37792 52744 22149 45927 48829 43369 34239 4394 59754 24896 51076 24671 24338 51652 64441 16311 994 46400 18427 59017 17536 55651 1031 40855 9970 14960 2913 6037 18722 59255 44167 60395 25801 42730 63630 35922 22871 6915 48722 41279 36331 60469 1272 39225 55108 40035 58445 26827 45752 21676 1783 1067 25495 35186 50944 49421 1679 40683 11342 20059 47930 24066 32964 7528 15562 56060 43190 30521 47422 36064 42366 61998 5922 16885 47784 63127 29037 1031 45097 8741 34818 38850 24378 11071 22462 11404 56380 8574 52259 64376 62634 49950 43840 26894 9373 8592 57543 47608 38341 39397 28946 26596 64004 46159 32897 2656 49895 37750 29369 34837 15515 61618 27861 40381 35806 55835 26158 56573 58007 59870 54403 60561 30771 61934 42875 61865 52177 17108 15328 10791 58498 59492 57775 38512 21623 5585 16479 40985 47233 22788 37950 53221 46730 31672 52397 62841 45956 11500 46814 465 45098 12486 50186 45757 15755 39436 12280 49956 13862 29184 48296 30313 48534 30494 44638 58398 22066 33204 34392 56615 24001 52919 38298 62335 63757 7288 11505 21249 37901 41820 15096 39853 846 48766 52483 46390 2582 57659 23922 7640 52433 13028 50373 38059 27492 2295 22538 27963 57355 42397 57246 8312 28549 39868 18487 14523 62939 15948 44477 42520 37596 38686 11231 51687 9736 25195 634 34825 7953 10077 18782 47970 27006 61065 27333 350 23243 10947 33165 56159 11265 11489 62524 10543 43039 45983 42939 31261 47800 59794 25177 10525 36626 14002 59756 43387 29034 45264 64246 33127 62256 50897 64421 30906 62137 47716 35520 35199 32953 16309 41996 27002 10611 64444 63989 32888 40179 21125 63085 45455 29587 35564 56546 35499 41142 49692 62678 47021 22699 37234 47614 1843 43825 12785 54803 41379 55958 17663 2579 59514 5755 14914 38034 9324 53165 40773 21291 33392 34804 2844 25055 56129 3713 44646 15633 54480 21316 2562 39817 36098 51020 12751 9564 13948 14224 16130 42630 9166 59444 61340 10458 48305 52676 34216 40990 9071 4702 13568 56686 10861 22788 61016 62068 63994 22357 64167 9618 59894 25630 42969 35773 31433 59808 55340 61057 2909 34456 49350 38031 58213 4670 3084 52108 60516 16977 5299 56711 61956 17459 10581 19069 58285 16987 59220 29452 11315 50585 59744 4448 28034 42925 57698 1975 31007 13942 63965 30094 36676 55786 1203 21343 60396 7304 4358 21151 32774 58750 17164 21653 20001 31703 40211 4420 6566 55719 17400 12838 4426 32845 52720 27224 36626 43196 42655 12587 30491 5220 25647 50468 30215 57647 23129 11912 23415 15012 11636 4353 10844 42204 34029 29224 17777 24474 29501 47787 50543 22242 23425 24134 42233 37806 10379 17530 4686 20202 10296 9906 3675 57808 58332 38277 16190 18853 45669 8535 55705 2032 9730 61506 41408 62464 4347 45269 10910 25794 13779 50596 29624 19089 30874 30842 46990 47639 56593 58579 12810 11128 52978 57311 4154 12804 8694 11142 64024 64015 28300 5968 53671 63618 58573 1923 46337 8443 45615 13894 46123 19569 63572 43863 63258 45221 48331 27901 13357 5194 51659 58250 29738 50462 36954 8426 62779 11107 23709 29165 15011 15617 9947 1683 33429 50394 51991 52136 53671 34912 18212 6650 57339 10518 63897 28460 20399 7750 16597 60753 29106 28906 17106 39153 10557 57325 42560 308 6405 10039 17598 6931 15349 19168 53488 36607 42260 14525 54139 41572 13411 58966 24992 17027 7102 43022 47274 19030 43396 27016 24498 8977 24566 56707 992 45928 17845 43800 62076 59241 52296 4566 2472 47008 10624 34410 2948 3014 57807 59594 21215 17990 13850 2643 33668 44647 7377 2990 13760 1843 38389 52895 48835 616 51217 17822 12434 19784 51741 31058 21111 39560 3514 34730 48991 13692 21733 56768 62832 18879 34727 39264 47227 4484 63741 9116 60901 16384 318 16927 23036 46932 34414 51217 39627 53755 18315 4513 23156 26504 10904 55542 33463 4808 63174 6259 54072 7698 29532 63018 46265 59112 34224 21113 30564 20255 21463 40793 24144 34368 51168 39390 17610 62299 35654 60038 47254 21212 28265 62989 22380 46129 37189 59391 59204 41575 34792 42724 25738 2773 9519 30540 20077 14470 33334 53342 23278 44236 35894 47712 35881 55579 37684 9816 14823 22616 4119 9532 62045 7252 14312 25689 47114 47710 14382 61526 22780 31717 26175 8010 48013 52530 58284 63140 56577 49625 17781 11572 60586 30098 25156 20674 57381 34405 8089 42731 3852 42113 45987 21986 55590 49513 11882 50804 51770 5481 11960 50809 1202 54056 49117 24840 10009 12968 2467 3907 50753 17747 8000 36261 63783 25261 33125 61306 26977 40767 44813 62780 29224 64060 10302 46419 41972 17184 21366 23309 4072 63609 61181 6446 1720 52964 63769 46361 36488 713 3959 51961 7260 41861 15462 17089 7962 1339 17321 45437 6201 34561 8112 59301 64001 41149 41130 43096 2362 58965 18618 23542 37405 24743 48244 53724 13959 56765 30224 46645 57495 43146 55561 23304 62558 10814 20014 55587 2518 4633 46041 30565 28781 37980 56711 6894 63937 60866 20605 25520 38310 51234 8360 34521 17760 37895 43208 17196 61496 10275 11967 62029 46623 48746 34247 36353 58569 35734 29842 10923 20861 54963 43151 5537 58476 15127 28968 8806 20307 47625 50330 20707 55409 53434 29678 41175 44382 57354 33187 53008 48819 4014 39558 33765 4891 7280 14256 56738 11602 50492 35186 9685 52253 46631 38365 61065 19294 60551 40008 24614 21406 16260 29095 26687 41224 64352 34025 40183 15868 24022 59017 35855 12739 27746 36024 16861 22406 28183 59544 18800 58467 3786 20058 3949 57589 55975 42784 42844 42586 7752 39379 5122 63133 11692 42661 30472 42822 4060 41704 25514 33484 12399 60680 37343 51059 60032 47619 54336 35794 3101 53189 15060 390 20025 53861 51175 34977 36951 41151 33740 31025 63114 31294 22579 1525 12198 56816 60596 63236 36289 43064 57592 5802 48834 1964 18385 41527 56280 16629 51197 53035 3265 55357 25741 60615 19167 10007 52204 23659 20473 58565 42498 61103 38801 51763 12366 44429 10963 62471 14231 54393 29565 58987 26121 11859 36017 33534 43360 26005 3208 17972 36920 23463 36785 53458 30706 16318 60082 14824 40328 35764 48801 37094 32959 35691 62498 25354 55789 57520 60894 44053 29271 6325 393 58157 22404 22128 35495 48726 28722 4709 25878 21872 21920 30844 13575 7012 17483 15339 52184 59274 46124 59692 6732 9305 16068 26982 38849 13300 30199 6379 63811 8736 6642 61176 28921 1413 521 19416 54144 6970 63501 23835 61758 16003 2860 17827 4997 36049 4625 13342 7904 61662 45042 63604 29434 29934 34628 700 46684 19404 9411 56665 4660 51903 54352 41078 41952 55382 8311 23423 20244 53102 7620 6479 55463 16339 33358 4988 26028 8936 53299 57662 54368 18382 9863 13160 21046 7084 56314 55340 5288 60301 28158 56297 29856 20730 32777 40392 63266 892 57730 13301 39913 63708 51064 36307 16550 40528 2630 36612 22432 22320 48749 25119 51607 53915 19833 29474 47151 50535 6612 53658 43694 8155 63132 49999 23138 35239 24504 12277 37150 30084 12051 24879 21756 48984 13553 23056 9632 26943 24429 34133 23908 15981 63286 63733 3901 37430 54466 42037 21932 11302 61079 2631 39767 26220 39414 8903 21713 30738 27873 10340 21994 37309 55194 39357 44739 53093 5050 25568 53408 53394 11765 63639 28266 37484 46774 61505 2331 17390 25386 34719 12306 51774 51911 41623 57445 56381 58869 20782 28357 57168 28608 39582 13495 23536 29328 56766 62423 14349 50088 46839 30510 35180 46333 63510 20691 4056 62193 17290 51597 38843 59418 52497 10206 52254 41751 13062 4440 33912 64328 15336 14246 52103 45446 19510 55623 10774 44141 46496 6874 24451 1450 13556 19732 2153 50841 54131 33439 33178 39530 2803 48607 10734 10776 56878 5963 56385 44763 53278 53788 47066 53654 23990 57911 50637 54495 27173 56620 10592 37532 53695 36618 44423 14254 17106 60974 18557 56163 41583 48516 58548 48062 43489 39150 51982 9513 40105 25791 28919 56341 35808 5690 1496 54339 62158 46517 8657 16466 41943 61383 58756 30632 35402 38780 59642 40661 28539 22388 55699 686 4480 17060 40953 40545 63819 7251 56694 51066 12698 43171 55919 54048 7369 24165 23502 48588 30243 17439 38548 6344 40902 6888 15952 35027 25140 3744 25550 55258 10913 17315 51219 54445 54966 26588 31678 19283 42691 16396 49662 46789 49030 23504 4173 43982 24147 3168 12484 598 44782 17835 40527 31179 3181 56103 57826 3406 54217 20033 31287 7451 38214 8319 43432 63799 50577 21451 247 722 21054 9084 45257 35119 40691 13946 22085 54204 39235 58639 39662 40571 9682 33829 10473 60624 33689 57758 59446 7707 55721 2073 51780 62307 5879 17970 54055 40852 2054 40648 19938 56281 35943 15788 7800 35365 6371 1239 39210 24664 63366 50617 40006 55499 45025 35277 30377 36559 29929 51435 13973 24544 39925 43989 54163 21553 46041 31633 26878 15355 49912 54475 51030 6863 41580 11851 27854 35466 41207 2873 64329 42571 18947 41151 41575 44408 1812 9834 48176 971 10601 10449 30082 27381 58657 54443 1693 57694 10649 50916 7762 1440 766 37423 21464 42675 46383 57026 5422 33477 24292 8100 7122 56316 57609 58609 120 21354 60563 40362 22950 51212 646 57714 40615 23733 54135 12333 59751 26279 49354 22819 36470 41612 58143 37225 58459 42139 38432 39705 10516 10743 52016 36761 17685 11191 54898 52319 62538 9486 34210 24029 24440 64190 43937 15873 23673 43247 64005 10716 6140 10491 62849 37181 18824 34451 12163 29489 11931 38622 47769 52267 51740 15609 9220 30030 54655 41836 38225 36914 20304 19088 395 53014 3583 27785 4502 30812 47101 18062 26793 3710 28567 37990 3011 24908 48645 1783 37680 13261 25901 7762 6066 29696 46529 33932 10518 56917 1703 15553 19022 46597 14356 58248 23476 39244 8966 12565 4638 33751 37304 36573 37478 34611 41734 39471 5707 46336 36804 26008 52334 17997 4129 60719 8177 6828 21799 26250 36150 1936 16345 35023 54280 1988 39771 44613 572 64084 33139 43183 7432 20033 14512 51794 20057 33603 61661 56338 29999 31003 42135 52567 18604 25166 43603 62222 56683 23971 12408 49813 33322 49323 46888 21208 41428 48802 30753 49196 11062 21950 25767 35307 53439 16182 6262 64237 26177 5567 46952 39768 53257 24580 56001 52967 19474 40169 4984 47098 44209 45605 35662 40701 61325 55727 52212 24641 4090 1456 55841 23379 15566 2148 27990 270 36465 57271 50593 1455 48643 47986 26617 48946 38409 2382 57381 55949 53097 16836 38310 46489 39972 59010 62530 58188 21206 49109 22532 13784 4659 33541 36954 44055 6326 23312 58754 14356 61658 13208 50207 58144 59814 61914 59165 24913 50045 57336 50642 15726 14982 49501 37611 2453 48634 62970 1399 9097 25706 28627 63315 40855 49520 17903 23493 10591 23377 14172 51442 31578 48366 22918 42959 2440 64025 27132 11391 7250 61007 4384 62372 45736 29860 47300 61085 21359 48586 39039 60144 20686 33216 976 34961 56141 52877 57422 13823 28759 61230 29350 17340 46514 13106 60791 5586 62808 63430 37983 48818 32984 62861 42785 14012 2713 21755 42766 10933 55653 11523 29730 35409 49188 25644 59161 14444 36652 16824 12065 8240 60691 10839 51644 21416 39780 444 52457 30248 9503 944 39153 27127 61306 11105 41658 3247 51615 23444 19052 42102 24315 42526 44488 57091 49068 9039 29895 20339 42277 59912 3014 19004 12528 23885 63958 40135 5499 59444 33267 5546 24632 9541 25817 58494 37009 30942 23973 59825 24321 40071 53898 13127 1785 57845 7574 15209 28221 17837 55099 45379 18288 12724 15814 17425 40629 11996 43195 20651 64107 18407 12082 50064 22659 12614 19808 48544 15695 18839 36203 6618 11580 26390 61377 14023 29416 52937 37341 60022 35508 47813 56520 23925 55585 39155 21826 47867 49631 42060 53526 20213 64422 40913 55574 10335 29878 31466 42381 14659 41802 45334 50798 20270 42436 53619 24596 46249 33141 50229 64216 39034 39742 53240 57579 57981 12424 64359 12180 16079 42904 27756 56822 12661 55111 14299 21878 24517 44533 63787 8512 38383 34079 24641 19519 16948 26011 47558 51832 28342 49938 816 55151 60647 31082 4939 10318 34737 43244 39633 42754 46043 38534 45095 5849 36291 57429 55197 10147 10748 6387 40973 37106 25788 53532 39250 42924 15778 2068 28743 34551 3188071536 1310158889 +1024 39258 28780 46959 26418 14670 49692 44986 8848 64219 38998 24906 15642 30551 62390 23066 25483 26227 41219 7493 22316 38726 24770 29140 35846 1552 36303 15878 29611 44418 52077 53400 33853 61758 31662 10092 49223 12867 19966 31493 50905 59602 23576 9511 6544 25755 8103 33358 646 23123 63399 10395 50961 60026 22284 28744 43264 17300 63126 24203 47395 42771 30219 59058 12561 41409 1671 6316 17755 31196 41120 44351 21306 47774 59689 42307 2303 45963 37061 60636 17158 51839 3538 19461 28051 45555 53943 63479 44072 12724 42241 2030 44327 54127 44171 62939 61905 38582 9999 3220 55207 3348 1712 43645 55257 17022 302 38913 30284 35212 17813 61872 40421 8426 21839 12669 7525 43524 62121 54135 846 30757 52288 40257 56338 3841 50420 58289 29326 57986 889 47462 2714 28680 21911 43098 8631 49818 58699 51289 59520 15315 63566 36143 40091 10284 11452 62958 62457 2610 14714 19444 11624 17422 26804 46853 4366 14144 16676 35220 60651 61405 36849 7737 48879 57116 16590 61893 52960 33970 22358 9987 14055 35746 2199 49477 31424 10067 36766 29318 6707 24581 61702 3959 22514 55295 23078 13990 33329 25409 46852 59174 63204 54548 48095 27580 24117 53487 228 16803 19199 38295 807 56221 35833 16005 10220 42465 3613 43965 38808 43540 51326 18277 48879 39001 34362 10812 420 57448 61854 8035 56468 5104 24385 19960 47535 6777 44800 63000 58855 37840 7415 25056 44710 44360 59631 28700 40786 12668 34521 41272 17938 57849 1996 31331 4719 215 3497 41797 6324 29019 37270 21936 46192 57257 56018 11224 30494 36675 38500 53719 4226 24211 46673 11883 36626 19769 13551 24274 41575 21403 22528 28849 48259 44171 64251 56070 12759 4111 18943 60264 51363 57305 27683 11527 44706 42622 28763 22862 54995 51207 64173 35549 2524 60458 16570 45404 8675 41905 24460 21317 41556 47559 53866 24566 53711 54154 61598 19106 32828 63083 9601 42415 21902 13947 4375 16546 2799 26995 40337 46131 63001 29821 25228 39057 44608 39839 18867 19844 52044 42293 6811 18625 42194 24531 26290 10426 8263 44799 63548 1879 46440 6216 21346 7941 63802 8458 1506 6849 28630 13591 63025 25164 20801 59749 56206 53703 16874 35453 52703 2659 38714 7446 59347 34084 29140 33381 31383 31502 26723 26492 27039 56534 56871 5554 58853 36854 1554 652 42503 45300 64453 17968 26649 37393 57714 17365 56105 17936 62262 13017 40048 56304 31509 31070 23599 26027 44923 35663 26510 16102 55354 53936 40624 55547 27571 337 53875 38928 12373 24144 42224 17924 55917 44619 32797 3388 31078 11575 12559 13023 23441 18312 48584 59905 7000 26305 49813 45477 53698 37125 52449 39306 14512 19927 64149 11079 1641 17495 8873 19704 26257 30979 43962 26129 33444 49882 26356 44988 42163 60157 39852 50898 61452 32987 38919 7147 42619 19055 34062 14706 1460 24611 51719 63667 48412 8475 59594 59101 49967 54267 53517 48595 43659 14365 44085 18139 12590 51660 33350 34659 7922 24602 31637 46234 25407 49234 628 9619 48250 24084 24441 33410 12178 33426 48917 43805 57956 12746 41569 44075 28713 61234 55355 54001 36075 27119 6800 25206 38237 43600 14288 50312 42221 25086 51078 39698 24441 54575 48317 37558 54215 10587 12843 28611 12926 53356 4516 18078 45895 11606 17801 58214 36075 21388 16581 17388 39938 30952 55236 28978 62155 29684 13260 10904 6349 55994 57485 45482 11236 18742 42451 8067 25988 33901 29316 19055 14455 27635 7464 15652 54075 34255 11828 26053 2142 40884 41447 36219 11807 10931 51763 39881 28734 8699 30593 24646 29460 671 54932 14414 44365 31598 53883 50775 13065 19997 1861 58314 59074 52466 22858 36492 44666 47441 63042 33518 55400 6886 34887 48793 38465 12555 56273 27448 10901 16335 54499 42705 42400 23795 30193 8582 62620 61059 36470 56798 34172 53431 9842 14056 17029 27993 9489 57309 18832 9403 24088 54764 49187 51613 29703 13526 60305 12475 13118 53207 49394 13871 17822 488 63737 23180 17129 28113 31655 6853 17731 38689 20112 10682 43181 46264 48214 58961 55122 28699 37528 21358 18158 57774 55293 40946 39423 24176 12570 63190 41204 619 27344 17141 702 20104 38886 38634 53209 60959 19221 42185 45292 43323 40161 27788 29502 4168 63613 63473 47076 41966 38911 7647 34343 17548 44016 51795 15626 19395 33595 1535 46214 15264 2736 63244 44525 3634 35466 31049 27142 42103 8231 16402 9035 59764 8694 11516 10722 6366 48445 16232 18752 60185 61175 62776 61676 708 10521 29016 53225 44085 1154 46365 35913 17045 35958 6131 44960 44662 50129 33199 22209 25159 35242 53390 12659 63473 51121 21463 14242 1149 64455 34262 16378 34642 40741 52971 34771 36774 48745 26183 1695 19324 40678 44456 2563 41265 25144 12408 8114 26107 49718 14263 4954 27144 18185 60237 134 50762 23975 64471 38073 64210 7287 35933 55329 21282 55519 28890 45695 61791 47680 38881 53778 2337 19286 34322 25164 46908 55342 36133 54201 53230 57250 13564 49263 56557 45904 26277 13299 24768 28992 59039 17832 25633 37121 15374 53676 17147 74 37445 61853 37843 8536 44128 15669 28796 19716 30791 16293 59913 29073 17946 9447 27697 62595 60579 897 33004 5793 59032 45447 36964 25387 20199 12336 6458 4717 48434 9397 58344 38694 6272 2961 1931 7912 3009 46406 56536 46431 30087 11931 930 33465 59699 4276 35767 2463 58839 11321 27676 20877 28149 29837 36303 28372 3343 18140 45014 1487 47896 58854 61493 3518 42368 63546 19768 62911 62369 49902 41532 49326 15267 53099 49801 61791 7973 12583 14387 24992 50543 24007 42125 54367 42668 13823 8409 6300 8982 23688 18439 53140 54759 54386 55171 4398 12137 26385 26480 44748 10174 40270 48041 18783 41661 4235 63118 63573 58587 3715 8485 47038 59991 5668 8618 2101 3008 40794 52410 10295 45946 54486 38051 48181 8355 6399 16218 22294 55079 9213 21553 30842 20839 42342 43709 16383 24325 34927 8943 5868 41582 6870 29945 18413 30563 11688 48439 29877 8788 3194 48717 33778 13120 10968 5649 19026 5291 29186 4127 26467 30405 31302 47442 49981 49809 13281 59444 42206 9843 54459 27166 55535 36344 15293 62871 52896 54961 37687 52975 48116 17445 26908 4413 5851 60635 22574 6407 62043 10058 36753 20203 23463 31034 30719 37035 22159 64469 35455 30051 51279 24914 54065 57657 28243 54167 45449 36844 59506 51 63309 38142 62992 54877 40659 29127 33413 27769 63144 57532 5376 53961 29262 14209 13968 51999 25592 54426 45638 24543 42035 40548 7953 3482 21390 21308 42456 1093 19308 11997 33527 35640 20219 37519 29133 48092 33648 47086 27899 6807 60371 47392 23981 34681 13574 59894 34639 48066 62868 34108 22205 10356 9939 7525 5647 19394 20456 34288 27481 12372 41040 17275 19586 34291 15620 43287 49349 21019 61951 63660 59351 54812 56929 12422 60538 59366 7305 7625 47045 39465 38173 44750 48341 29446 31743 29649 42454 50987 37307 39983 9433 35247 17685 51502 44171 16375 48481 4000 2689 45942 29485 812 41762 60139 56034 15296 33985 34096 25614 60943 52913 42848 53425 22082 43051 53029 27547 14949 46095 36751 12940 49646 24335 5775 17397 31128 50813 9708 62147 27016 61868 52795 16013 13494 27739 15801 37756 14655 23060 45126 63945 27525 36419 24757 63608 18384 15639 47920 25739 21379 51109 62566 43559 3956 46419 17762 46794 39309 10007 25032 17667 5810 26902 24551 17580 62574 16837 53642 7787 11912 27686 22320 16145 63066 45068 56452 21112 14445 38705 53907 30970 39393 10228 51756 40748 38715 35738 44513 16272 8312 16483 3997 38583 51303 2987 50758 33079 45280 49184 46104 60567 29862 41064 1101 26194 8265 14902 23143 21484 1527 51803 8558 9839 15593 64126 4296 50313 60313 17982 1602 14317 7949 52772 46984 20568 33853 63100 40098 22351 63927 10935 32804 62107 33641 19763 10243 48605 44342 8032 47950 26220 44168 11470 21337 29107 34900 33096 8569 43719 38382 62918 19171 11028 50135 62506 15028 14908 35728 49658 49602 54687 4367 55450 2107 55021 54710 47690 31651 23110 1342 15973 3657 8518 57606 52796 58212 34713 1489 56171 39753 48463 36738 21520 45274 57615 48030 1062 31379 36307 8972 63386 47296 35894 6744 12949 63617 60905 15353 50016 45472 60660 42785 39946 26818 18328 15642 20725 26249 54718 61819 44960 64166 32977 20587 2685 58283 38388 36852 35254 61401 32905 4527 5134 10397 29481 57727 59138 31475 41021 13302 63072 34543 63773 31086 27545 25120 14823 60872 59851 6427 15671 43846 63368 46974 16048 3121 4958 31601 39277 59575 40819 33780 58438 58630 49142 50850 11563 44232 7122 35993 6733 50777 22924 64086 1123 21097 17773 60025 62066 55681 47832 20 13237 5178 27125 10392 44490 61060 4947 57504 54499 60927 62966 18216 56365 50722 52758 2675 23274 56028 56253 6330 54451 16097 46934 9856 25285 9169 40574 59681 44287 6137 915 8397 56671 50554 27466 27573 64250 48031 39788 22183 13220 47970 2864 64398 21132 47407 21042 36299 39620 46761 27169 2414 15501 51731 34 34347 17045 24995 10757 48163 16209 54499 63645 4820 62110 24592 58593 5151 35835 58081 5093 1127 10333 12279 10179 9021 24218 33591 34315 18751 48723 45386 27628 30142 48805 27630 28888 26049 23331 48167 22810 13595 10850 13148 29416 24347 6148 49770 43408 7116 39298 14517 41866 966 19289 13471 44256 47444 5520 63674 22727 5936 10395 58776 12154 26266 62528 35110 18049 63939 61872 40472 48794 53877 25551 15031 37931 48983 976 64018 63609 41577 62127 31587 9258 4951 30819 2628 17052 26400 19276 42847 17163 57580 3277 56943 38848 19099 53848 51900 371 18592 21799 22815 47417 15442 10061 44042 30548 23352 30298 10851 32868 46301 148 52716 22451 42276 2120 56744 20699 19681 23131 4481 4353 31669 2425 44867 59811 20847 8733 37630 59068 35111 13268 38760 12116 6376 14843 43246 44057 46468 11505 35932 46894 28274 42439 15474 55238 46446 6304 42320 54104 64049 55881 19127 17386 41955 22631 38595 64405 18154 23243 17444 61517 23122 60916 63927 45980 5349 55741 41169 11853 24049 46375 14110 57373 47615 582 11567 28996 43999 57992 22071 35200 1635 45619 3611 42328 49783 16828 25364 18589 38551 15707 21019 1605 8081 11453 62143 26228 39910 48151 6845 41021 22262 42981 10156 39847 25252 45668 40112 16020 33623 57112 26417 37018 30700 19274 48397 42199 22466 51357 61887 45276 28266 27924 8644 11786 41837 51018 29890 16623 5669 48077 47966 36846 61145 36088 49167 4755 28081 25670 30198 44463 34347 14826 61746 18752 20610 37198 55497 42346 51365 27905 38738 2251 29848 29726 23376 15016 41880 35857 50967 4480 47379 8796 56797 24763 45558 57451 50752 17337 6996 17505 20001 7117 56819 53140 32864 49076 9270 37351 5488 53803 60104 14518 59423 14680 21615 2078 54699 26472 63654 40109 14491 28510 26511 44812 19189 40287 56736 14565 62914 932 56393 26537 15502 4205 29752 24921 28392 17402 26244 19688 9352 59146 28029 45572 50321 27399 3606 25014 39385 11193 56100 42119 27492 57217 38581 33987 35205 49736 7423 264 53334 36435 3532 26708 36095 57535 52983 34541 4392 61969 16673 52339 31093 62185 5389 19501 47998 19909 16795 14392 6053 54115 53249 2482 23266 9756 13661 61461 64255 15603 45105 55649 25978 42342 33469 29392 48652 29664 23053 35859 1085 7439 47490 52444 5697 27681 29275 44942 9724 51372 57611 2889 6151 54674 37491 29206 20502 29971 60250 39478 58715 43955 14162 6394 19179 16618 29302 49321 17285 38779 28997 43265 58982 46200 45790 26220 17724 12368 34080 30919 57057 48630 61677 24079 37048 14252 59065 21975 19449 43169 47707 23988 60857 20480 35383 51764 15691 62274 22970 62116 16652 12516 5499 36384 2019 55931 6370 51245 53947 60898 55428 10596 19497 35813 39858 11439 12050 719 49944 45535 50196 10582 47876 29103 18758 7796 24009 34507 17256 53209 59952 5013 53121 2231 39167 1892 44103 8593 49996 10247 1084 51786 15630 27455 25846 47375 26124 27646 18431 33418 33699 2154 22361 27797 58213 34299 13807 63657 47856 48298 42333 63236 18525 30320 30278 58766 47426 53263 34229 2817 12098 774 29910 13850 36388 46165 38046 10840 21750 53128 6937 177 45899 729 2174 18716 22969 48108 49183 33275 6278 9410 8032 9087 3150 59792 63005 4549 55916 60106 33563 56874 14153 17408 23888 64153 47802 21670 49667 22318 3485 43597 38178 45313 52515 15675 26025 60144 17818 46787 15276 11626 62189 58234 19007 10909 52779 10397 23416 17606 52759 49671 41107 24791 41609 3607 37299 30713 16001 27887 39151 38148 55925 33713 1551 37204 53307 51619 42509 62057 11591 43495 47707 31300 38612 45575 50688 39942 4539 46406 57067 24491 11793 44314 0 3454567366 +1024 4633 11015 21388 60603 54804 41344 49251 48609 63266 159 49327 2292 16989 56064 37074 25134 37122 43721 15891 4934 7367 62168 60255 61030 53787 15199 24290 11502 52865 61465 63175 50430 18219 25222 7981 38437 29857 61124 16132 60999 41232 2262 30238 6192 44658 12436 56569 49207 30973 29590 15605 19642 28430 16518 13847 3849 31611 17604 43582 8176 31120 48393 56820 45432 9554 39265 8311 56596 50005 34227 30853 49757 41265 15379 45019 20494 20535 32909 38761 63971 57079 55844 36030 52089 58021 63126 39996 54903 61623 57589 44825 14576 15072 60372 63822 27269 46863 51151 56239 10365 3119 93 59538 25883 56065 34584 33407 13724 34636 34049 52206 61436 63973 9882 58753 35657 40427 54277 31379 60383 50037 14958 63400 21922 51388 46678 38607 60809 29644 28175 20618 45362 9691 15739 56940 36946 49490 52663 12201 56908 35889 14175 15416 24128 55514 56422 63234 49405 53106 40793 11987 8984 34322 57205 14100 58300 62372 2662 8417 48261 46283 25168 38570 19602 50302 31293 20757 55021 58395 64049 17633 61834 31176 16492 38636 31581 10198 48345 51962 45513 59425 54295 25805 52268 35237 11753 40730 18137 56026 63266 8955 54777 61996 29404 19145 24756 47319 48732 64064 25767 62888 12342 61002 55543 37640 26384 46971 11117 56285 62750 19449 52485 28135 29171 4122 46320 16690 37991 12880 47172 819 60157 15139 55831 56348 30477 50685 41885 3221 62892 47988 48009 17794 40309 52421 47937 34023 59176 4548 10147 59759 51357 37896 19870 39201 38322 46782 566 48067 24099 23436 28456 54161 27951 50464 47953 30566 55721 35159 58971 58483 62100 63111 3335 3679 56404 9194 51074 18255 2551 26005 39493 26852 52589 20893 2718 34339 14069 42285 51919 2787 38191 20065 51934 34065 41692 54739 7293 15727 15703 43025 23592 22841 57345 23614 5047 64114 11339 28265 34125 36612 5110 14715 48103 23355 62298 39941 53704 34328 4418 15147 48905 21773 41363 48526 4275 42080 63241 24919 29260 23028 52050 22689 21661 45551 52691 27949 38856 3637 42554 25987 2431 27436 39605 30456 21612 44131 54650 38268 56894 55031 23902 51855 49585 64019 13369 1059 16170 37633 3509 40054 57497 4153 13664 20286 60562 9829 15166 11488 16667 63111 58823 34508 24113 44167 27335 23084 54537 58616 23533 29891 3423 19085 52062 28440 33864 15260 57024 20600 34540 20992 56451 15471 1634 57602 56225 13837 54968 51690 14525 9847 52803 9224 16540 10099 14416 55864 18900 55904 49633 40487 15573 21654 40884 29120 25422 24847 16226 21777 38558 51108 23408 4825 14590 41710 50456 235 42206 30570 15703 51385 5267 20861 51638 7099 44638 21938 2360 52409 44236 47562 19441 23177 33435 39833 14320 64118 51430 39973 49991 61818 55669 60345 14422 18564 62208 58015 33788 54845 57614 19619 1318 49524 58132 33580 16937 57847 53066 60336 28921 59368 22280 6573 19335 51735 15589 38716 14455 24472 32788 7089 60096 45532 8152 23886 29755 35821 3528 54941 58835 35191 24411 61236 33354 22511 35704 28877 49178 20680 55141 32834 22724 9984 39578 17896 59892 49072 11901 19816 18420 9546 33369 1974 44274 24313 8626 63127 56364 17262 9744 29505 35449 18926 13604 19743 12457 58215 31705 63123 48475 45941 64445 53433 20339 4733 21143 54316 20145 56842 10297 41675 60294 14813 23137 19645 53548 55557 54673 10112 50162 50097 53950 53321 61081 15012 60348 44492 26629 16701 39924 54252 2120 19602 43008 27168 34870 63521 61821 35130 5874 9882 53814 41615 49586 8462 59741 13782 31087 25741 26086 13623 16504 46129 55760 54817 10457 8205 18345 56587 16261 904 1974 21306 20659 4761 36960 28366 12569 6383 61408 455 50754 60621 14788 58036 27594 63748 4420 9898 41239 58039 44012 50904 61628 53067 63037 29882 56631 26625 28317 5231 53161 49940 38060 5873 10770 44208 34514 29044 2114 57163 26471 9298 62352 19089 64339 37523 16286 11062 38073 31611 36872 20338 6849 53592 47140 51619 41860 58609 43789 63970 13236 41463 28864 16989 22772 11537 44532 47335 56752 41146 7153 33969 2763 57571 7754 19426 54288 16567 4287 59889 39190 55617 16908 13509 12826 36871 13531 54775 61909 30255 10734 18978 2456 57750 9447 14459 24366 15928 36250 51659 19285 36764 46589 22631 46655 19323 29668 15978 62936 41800 50503 47514 14728 9952 30362 52915 44605 63025 57031 6307 52570 7738 48721 6433 18636 17389 17694 44714 18053 10598 37396 63459 3344 16762 9190 41255 61230 29513 53689 22866 55086 52289 7130 53964 8715 53116 4087 58707 39093 16745 22827 39910 5956 1911 33949 25837 51826 41206 47624 54879 37471 46465 52925 23868 16688 11249 47486 8817 950 49251 13025 49783 41441 61295 10285 34639 51960 35717 17367 19693 17800 7335 39411 29620 611 8276 19660 9647 11786 39005 30211 37426 28621 28176 60017 59696 42870 52390 10451 41714 34768 3076 36425 64191 35470 56089 17955 42348 7943 46722 53220 23982 14606 58770 41853 40549 18977 15460 53436 28112 11279 18636 52045 14115 47327 28541 17283 26171 64008 59084 13793 19378 22300 31001 7851 55433 4996 21356 41003 59290 16791 31086 44274 16277 38462 29371 17350 8653 11817 8902 44995 37514 31698 61697 4801 7831 14916 60496 46019 31399 59815 44332 61390 31108 54817 4177 30722 3324 21060 13794 57988 18470 37030 30126 56266 39717 1250 28301 43721 54331 43627 47515 16017 43644 16397 40405 2449 52794 46047 10135 28359 15707 6787 35452 55802 28609 47266 61946 48234 24798 40312 42026 35032 26556 12453 34715 62426 12037 8493 31057 6148 54377 45289 42745 8122 2067 58588 514 29358 27600 52297 53390 2650 61509 10961 60739 11633 41341 13318 12949 14212 35250 20838 60287 61116 41431 54476 45085 44696 26890 26399 25192 48766 33301 15708 31743 34240 49206 57215 16091 6952 63350 37292 40101 47518 29298 20804 19811 49945 49794 23148 50364 16450 49428 28608 23338 55581 10265 21404 17974 3382 19411 36564 33302 38626 16314 4493 60171 37012 63508 63760 60663 24522 9792 9738 26884 6576 16525 11860 1008 49569 26191 42080 40911 1817 17929 54666 37159 44526 21759 49528 9216 31685 50070 48563 56985 63280 20249 9407 19739 10474 42167 22531 10492 57337 62483 62986 107 56436 23316 25014 36791 53103 4301 36153 6278 36947 15351 8671 61701 35558 48550 35241 64270 33447 9171 47131 59510 13684 18286 29069 35925 19868 9304 34802 31025 27568 26371 6729 41999 24790 26845 2421 14963 57558 17677 9691 33060 6868 39440 39385 44802 31728 4848 40890 13618 35562 55844 31212 22979 9132 1414 50307 21975 22375 15376 36036 3328 41901 4815 42054 6078 40903 37175 24272 11472 25328 57484 44185 52312 23014 88 51543 28912 6829 61124 29655 33500 35673 47451 47196 58795 30025 34086 48919 29197 7325 56031 38167 56536 45494 30596 57901 42446 6796 30036 42392 10381 21020 1057 26044 46315 25598 50543 35544 15584 37893 46119 39943 26855 63653 45556 46346 18407 6405 27231 13798 28883 26777 62434 45076 40657 63660 50167 16003 50245 4066 33732 26288 30956 54457 41597 63078 63034 30087 62301 58609 2991 7081 54744 16339 3473 39009 37861 38465 15156 19632 60154 5992 37957 51759 27141 50786 11488 11847 12064 6102 7444 18509 38716 45982 49940 53554 1262 35516 38548 12933 57179 14986 17870 47609 54332 15393 39960 34279 12566 63088 24008 53068 16592 52329 9204 2988 54415 13396 35784 21872 25290 17869 8594 58628 8349 47980 56906 58850 48784 30350 27819 36060 35208 50848 37019 19427 4014 6957 29612 55790 28114 38927 29502 63907 20876 1113 54448 18961 27573 9482 26101 45632 56354 26371 34403 31469 35327 44980 54107 10658 35534 23119 37707 56992 28045 22184 54037 20330 62284 25900 27534 29760 13269 59387 63031 47397 9218 8728 8045 52619 43974 20612 30964 24665 61418 6400 58396 6890 55688 14123 51797 13807 4320 43290 27976 1160 10560 22485 51374 33241 9237 1962 21277 54986 5387 53554 24960 20544 62971 747 53692 41539 63725 26301 11246 28035 38032 49864 28705 60754 22735 427 30445 6817 15673 49827 52088 42635 33154 42292 44256 44003 2284 39658 55694 24788 27323 9942 59003 54652 44747 47299 8533 39107 51019 2414 44746 38527 2988 42948 12321 60058 28665 15195 29063 59456 4319 41545 6758 46256 37918 47626 18519 60930 10526 2405 58024 42169 51484 17702 33527 1319 64042 63201 29694 44068 51989 45197 12372 19717 9845 54310 63552 16039 4031 44660 28222 34993 24530 53869 47935 48631 21545 26318 17375 22636 22628 11517 15643 54410 63459 14567 4560 52031 7532 25290 6712 50543 13167 38883 56344 59040 9167 47107 27120 5005 2417 29498 29807 28152 62665 7207 47395 18529 61005 11618 30628 38192 42035 22292 44893 6559 4172 50164 6806 22831 33859 45528 24782 15269 26826 15231 28027 54240 2532 39860 60572 1858 25217 15807 60064 12441 36596 26705 1801 49222 24694 15741 44935 13411 52170 57358 48573 36194 49091 20949 48787 23218 51844 28282 46524 8857 44864 46719 59835 25325 61644 27990 49877 42897 13166 20422 59505 60104 41919 57354 58705 61139 40452 37501 20459 57651 57962 62967 37881 62598 23117 53619 40861 35300 48155 45728 5036 53094 11740 39655 48165 51008 33335 1868 5429 29341 50708 10334 19755 61471 35159 36758 43504 27634 37767 26700 42304 28666 37335 7820 53108 56268 64009 56699 15907 24243 57330 31465 934 33286 38066 17095 9959 25087 11892 10979 44548 34846 20384 10390 20416 21828 36224 15037 60169 6789 43849 42463 54706 55444 21311 59555 56729 24711 255 61439 3245 57493 61432 27085 55557 51238 29786 58015 24674 43281 23185 60189 16914 51818 30450 36646 29737 24655 60845 30534 63062 58914 36749 59020 41294 1267 55309 45944 36998 9706 55599 37619 22814 34146 60140 35516 15006 26970 15346 55726 63636 64312 2871 8122 44487 53344 34733 57337 22939 3178 56050 36215 52907 15203 46803 4510 53872 18776 52056 49974 30972 28878 38699 50652 52409 14434 36884 9135 49817 62314 41954 54326 47525 16501 37225 20690 1420 25789 14396 59664 14743 48950 43170 11489 21590 59401 12248 23554 54597 63241 36748 15174 5841 40867 39198 61661 54635 47194 23547 30738 55438 10462 31267 39890 55983 53700 61928 44009 37933 57354 14167 25135 41355 51043 8097 21447 59642 10167 29474 44169 55411 15752 55131 3408 44240 6770 44862 44967 17569 52874 36266 46774 12853 6223 53491 48393 15832 40027 22098 25167 27691 26844 29190 4419 16370 33435 40105 12203 56691 62908 14884 46805 27665 3145 5786 61809 5322 6977 16380 87 34515 54882 18167 52659 46843 12103 36419 50224 62051 36962 26527 57062 63135 15847 18093 31154 14611 8640 41137 33304 4432 8917 33657 63192 27020 39573 63454 6857 43620 55155 27884 57281 54691 22698 21879 17964 60821 23879 51293 56726 62728 15660 1037 30479 26737 63204 3364 59017 53565 47401 55617 16333 59045 2995 7772 8863 54580 19148 57393 41899 33930 4011 21370 35384 34230 23658 6795 26074 2690 6783 57406 1509 64497 48221 50515 4609 26691 46567 53595 52225 9075 36088 42716 6024 22388 47812 45262 60443 14400 4405 35391 49891 38309 28954 44579 37512 20935 50521 5250 58456 37799 11787 64003 57730 22938 4531 6787 24840 3320 23238 16980 25913 48411 27192 46241 46920 33661 14589 15592 53013 4439 14175 62740 36124 30318 31365 20624 37458 59510 28715 14001 10142 7467 56440 12723 1821 47249 48002 12790 24045 2386 32846 13523 13074 63797 21174 57281 47797 56720 12142 63503 53308 6111 8864 26998 40099 7935 18222 44768 8768 21456 48984 19845 59629 50998 39297 1444 5055 52219 8131 14673 14941 5207 34772 16760 6166 38891 32962 44269 30478 14530 47065 29097 21201 21212 37220 25268 24430 22533 23787 35081 17419 40424 40975 41276 45418 23809 55963 8355 36311 48710 46523 1533 55025 23568 50581 8264 19347 59884 16135 25878 52757 33650 47179 11895 3946 20314 47757 29352 57815 53160 21287 19984 63941 36547 63787 4691 46529 40307 45220 54172 39788 4135 8562 36110 40010 4974 2740 37339 12212 16019 47015 14189 39259 40395 23648 14513 55076 46969 34213 60012 43758 1778 51636 54116 5048 41667 19968 35697 22072 54756 64103 31242 62615 28961 41787 16848 14062 40654 54130 20096 35287 24263 35868 26525 33121 58573 47942 38105 64195 1343 22237 61804 45749 259 22377 23428 16542 24728 24401 36555 2874 4793 11132 19602 28294 9155 50889 19489 43454 3599 36130 53463 46254 9282 49215 3358 24829 37752 40245 50110 39373 58619 33418 51402 62903 60457 36615 3691 27329 40469 46244 52358 52192 64417 56978 62292 6147 15523 53783 56011 3197 35477 55607 35954 15450 25662 62968 1299 46184 31591 38169 32924 15673 54600 53917 40220 57319 11325 56608 28008 15751 20571 7428 57457 45681 48820 45062 3364664907 1292641429 +1024 61022 49568 35261 44763 58113 51071 39754 42176 13839 27294 35578 36012 18337 18700 12267 42960 9991 44246 7788 551 3411 52569 24852 23641 53924 24018 105 53729 9112 25919 15283 62829 29540 28040 41896 50255 6026 40589 48446 4047 18685 62370 38619 61016 7283 27677 8835 12481 6339 34371 61604 51537 49486 28331 56455 44495 8859 49040 39073 55456 9734 24953 42632 16489 14671 35717 818 37060 47426 56152 58525 44195 47653 62364 59206 9757 13478 2381 22281 5042 10951 15145 24459 43035 17648 4834 36392 20395 29457 52884 34706 48866 51129 57472 58051 36737 57505 43075 46705 48782 51637 1440 47573 49869 17772 49384 13 10349 48490 14858 24770 36120 51043 45259 48228 46360 31170 35564 33924 58770 9052 20125 651 38989 29654 25896 29021 58485 9193 14552 37060 16426 23342 61685 16360 9984 58612 12904 17595 11338 53148 20459 49238 28083 56650 44692 43311 52626 37840 45325 1373 36726 5344 63729 7739 39456 24474 16082 26431 17078 26824 61707 13509 7305 39525 56579 13813 29043 35981 57632 48001 15503 47176 52699 5724 9888 4611 62605 6955 39564 24773 28000 26952 7894 1521 13525 10099 43056 29776 287 29591 21377 35849 34686 58130 21909 36143 46442 10415 51696 38763 39058 18657 44045 58353 26621 42122 48369 62718 31196 59895 27714 51692 51648 21919 34120 2774 46630 41290 28715 17098 7057 3671 56223 24589 61941 1127 25838 6401 18846 43212 4243 15103 6802 25616 63304 15209 46956 1475 7004 20366 24660 64351 33489 57994 1673 56756 20153 64312 16350 2024 14927 43292 10149 15396 42651 29972 21 40289 936 5604 52548 50662 44132 63683 20275 40187 47707 38254 18879 18530 45032 25505 26271 55302 36850 702 54304 7357 3081 60607 33914 8807 48992 11070 6821 5947 19733 24854 41191 11035 54216 55500 1515 16601 26937 18192 826 58493 58261 46034 35877 47197 18241 13821 18023 14112 39014 44367 58571 21526 19321 21161 63438 46412 22434 42232 43244 26229 5741 50792 42736 30242 47506 15255 24176 61344 16839 26667 18397 34481 4676 43062 13306 45406 37099 22667 5844 51603 40491 54283 58714 6755 62741 39063 2526 31668 29089 42805 19550 23930 52824 28611 58888 18833 10817 4071 38816 56761 24125 13692 51942 30543 9610 3106 1208 12671 95 21041 8673 15887 31578 16690 51124 58070 5147 41130 33555 60887 60213 33463 42962 35870 43158 59208 60082 52188 47751 34081 64352 64142 48246 46720 13686 44814 44794 47202 17347 4028 22008 9658 25352 3500 57668 19574 56989 50636 17602 35850 57723 20695 56495 42838 38104 6312 22957 3723 4796 37425 12431 24445 52419 20594 6267 56589 61375 7926 35286 15442 52101 35229 46370 31415 50229 32815 61496 18562 1896 27173 51980 30094 47634 51630 7553 27163 56975 10199 16856 37852 31548 5693 50142 62799 34679 7382 27349 25880 50036 62549 48324 59476 43468 50714 40740 16075 62206 34367 25159 19075 51462 36395 36843 40961 4304 8711 55545 56394 3648 27993 56497 3843 59395 15366 38560 62062 35432 5980 33618 60269 36219 40369 48432 58819 18269 15115 45474 31507 1105 54628 43953 9743 6067 50505 27526 17827 35378 13611 4412 5026 35234 52940 44561 26283 41703 52309 36729 15155 56492 8020 58988 13692 16313 17949 17939 63550 57318 46325 54235 34995 34990 25393 43266 43003 42558 59044 7221 55870 28148 34700 8860 60383 61302 24545 17848 36254 1655 59530 60859 8974 44353 14520 62098 38160 20658 26274 12062 27688 30380 63651 56830 40793 40365 48369 22272 56995 37067 22045 22441 1630 55887 50660 22198 22707 43573 48500 37890 61266 24980 18176 34765 45079 39147 21545 5491 30606 60432 49529 3921 9084 30064 4581 5989 29294 50945 41178 13564 52111 34266 62169 16197 25082 61003 26186 22229 53878 15560 57646 39521 39094 19449 35304 21705 15882 35620 49073 17828 62462 14694 33389 4712 57000 631 8818 63857 47981 22358 62983 63672 56480 42266 64445 7678 38028 38761 62795 6897 47750 24854 51157 57154 29637 61488 23959 42691 19292 37290 42559 48908 24357 49495 57156 46877 1979 56120 18495 2716 45103 25745 6397 2616 4325 50655 58220 38014 16772 21198 3707 43649 24057 25945 62963 53393 19960 7215 46082 57919 38545 28998 12950 23700 45446 6906 58144 45609 4807 54650 7860 40809 60059 24269 343 11276 33885 35020 50460 17324 55350 10448 50585 1731 58368 12817 51721 45276 43428 18885 12531 5320 1570 19974 31622 38321 58366 29924 6336 1351 10607 56054 56597 63410 49383 54182 8177 15926 5604 1293 37338 28105 157 43034 5071 30774 9485 1 20477 50761 21725 28557 4172 1838 13047 40619 57913 55185 48729 63998 3094 19804 33310 46884 56702 55173 45304 56390 57824 2984 18992 23325 42499 8147 6864 4808 11512 26208 16762 31685 25468 21268 30667 30749 64219 22491 55716 15024 49306 12068 14118 17754 5408 16217 31284 17953 3892 733 5301 52312 53556 10268 47811 60060 10272 39999 3648 25584 29897 28403 12846 2648 39375 55714 52810 22833 24123 25323 6587 46488 36729 42484 9418 45899 38199 9509 26775 51459 51900 18917 19175 3858 24825 37181 14346 16270 21869 19016 64185 58975 50144 40237 59989 19446 49694 34982 1821 15217 8619 53383 19581 2985 9526 40377 15582 36441 7872 22072 63555 47318 73 1113 34546 33283 23399 8270 57982 23122 46993 3364 55567 4767 49362 45474 25420 4474 22039 44412 57332 56408 59576 38186 52909 24203 48786 54413 53923 53006 26647 8820 16712 3854 33299 13470 3984 14673 21308 35642 2381 2864 59186 29205 1534 25751 4993 52372 44833 29055 7490 43556 23552 21031 40506 18224 34186 52655 27315 62929 37070 64424 36394 29561 6524 14076 51487 4019 36045 13604 22126 29434 57468 21227 47057 15080 44234 63381 62540 42520 31256 40932 39043 58120 22130 53039 5709 45683 56147 17225 11625 4677 53681 4281 21452 57102 10927 37739 28892 4166 30933 13429 30266 6132 19131 8701 45025 7002 9511 46726 51615 18886 5373 4484 57244 59600 21870 62682 12787 24132 37865 38888 5584 50883 31051 47976 13152 63972 59378 52135 44273 10954 36127 50658 38184 21325 7183 26932 5498 40192 39422 55524 16078 37932 54422 54432 57536 28481 36218 55565 29347 13780 34347 2279 61047 1714 51948 6027 1073 61826 61095 13136 7801 24234 11791 45611 9443 24740 64040 6839 30210 49482 49742 1379 43343 12905 4237 29687 19625 54040 16506 4503 44719 4854 18355 44690 40723 48901 16833 52503 54775 27190 45167 16628 62896 63906 53559 12829 60197 55120 19552 57248 6227 24074 52630 23282 47543 51238 35305 48763 39751 53047 54862 133 38610 56857 30729 3605 33342 59429 45762 29071 61975 38172 42329 52177 38804 38018 45792 14103 62497 42035 28500 42317 34125 57272 8852 9416 36933 35530 1605 4182 41507 39277 49156 51770 11728 25475 13185 21507 21029 55671 24045 54440 46060 35050 1772 19156 19073 21593 13912 1746 23738 62701 22906 22635 2322 7504 56252 41019 18726 30637 28898 55928 54079 44207 18945 33860 22613 14656 14270 53004 25341 55818 12316 43435 61635 20979 45901 62182 62739 23946 48231 22664 404 17801 31646 14959 8860 22807 8036 36182 7972 30821 41603 46346 64152 4268 55238 16687 8163 21710 47432 50355 33996 11400 50646 48163 13152 5271 19814 21213 36462 47988 53179 22610 24418 10684 61419 64308 28300 47913 9584 57275 30195 44577 11276 17964 48579 15291 13156 3029 326 42547 44076 39353 16351 43550 6846 64188 56206 16582 56018 8419 39048 52936 58260 59755 51686 14895 19799 2258 7869 15583 2250 20868 16531 31671 35129 52589 56384 27258 11277 9061 18894 62605 38293 58073 268 51657 38311 13269 45262 48969 35438 25183 4946 38875 24433 61332 27156 53774 1675 33571 11123 47183 43769 16860 55807 26189 14210 6574 33392 15294 47438 45988 27326 19586 53431 46348 34979 6785 43121 1164 7817 4548 55113 41893 61355 58690 24562 64174 10219 6119 49508 37403 2002 30727 14064 39115 37711 8893 40782 29638 26259 56784 34418 52480 36081 24473 8396 3719 61719 44013 1788 44708 9688 41192 58518 29995 30260 52166 53064 57192 25819 16506 54190 836 54391 40197 31155 56062 1984 51290 15587 41003 11377 60333 14214 42953 53697 46697 52784 30605 9522 57736 62526 27977 761 972 47053 15039 29932 64393 9369 672 39266 8737 48006 25637 53844 39773 59504 34912 22109 59807 39473 24232 21930 24698 50189 30295 41542 54080 17877 63495 35685 15430 25002 41437 24969 26411 6270 14398 44760 45670 24087 54306 51278 48881 15066 54769 33571 56932 21974 62065 2767 1795 54373 42034 58626 52387 14507 30240 57106 26766 24212 28458 18046 12404 12083 45697 30074 43368 61421 45156 32822 30651 48711 59462 34115 58684 42626 41335 9581 17267 58451 12687 21194 29107 38253 25574 37375 56049 6138 57136 50911 64179 31201 15447 34556 9356 33556 29746 26758 49514 35909 17927 10978 44303 29664 36608 42906 51205 44074 19549 54733 22961 18880 24932 62858 10428 60814 20217 24938 43581 43098 64214 53794 34373 21831 44301 2638 4740 54573 61201 11063 26995 63105 61792 29065 41533 12026 13589 48442 50348 6746 43767 62377 12611 7735 36909 44232 55850 7338 45799 54728 30089 11111 44662 6916 44095 41850 19466 7257 49602 55598 54872 48572 6461 20505 27078 17802 64160 60099 37897 24139 10070 21042 28288 23230 9683 9707 54339 9323 56761 60231 60505 61949 8224 2363 59283 62728 4056 1206 10568 50288 51968 7890 13053 7827 51620 61940 33488 19136 2124 29953 23698 40761 45676 3636 17415 12137 56615 22673 39158 44523 56307 22101 34608 62736 36135 57646 63944 46198 9489 59716 14234 35346 61948 21830 18874 43633 51385 39751 40409 6328 9538 22803 14530 28173 49137 29529 23016 5483 21657 35151 42495 62932 54821 46634 61870 54810 63557 7404 62894 21148 17880 22090 12768 46769 15766 61928 50945 15029 19529 11406 51036 34312 51178 13512 17862 57486 34162 16727 55117 56611 52582 42492 56175 9915 34701 34904 3361 41156 62603 3528 58995 60087 61706 31523 57511 29517 13452 5761 4242 59589 59352 39320 28062 17489 12564 50870 44840 13051 38516 6212 62228 45827 20448 14641 41359 27835 27884 58343 51905 12447 34517 33794 12564 30639 59754 1571 44297 26594 17123 63623 2264 29942 38512 5783 59748 7078 59036 3112 54328 10939 2675 40132 22788 39475 62595 42594 50413 52500 53942 41963 53089 13337 2023 23651 22907 10839 53581 54961 19877 63807 22635 54425 43625 8598 35507 35700 64333 16416 30385 49383 52272 1794 47370 43716 4750 44078 64296 22399 51896 31230 33327 22348 25947 37634 44403 21438 29794 40341 39283 59237 38068 21414 9092 5829 42821 43589 29911 53953 8409 7536 16059 59637 48377 53811 45130 29721 39724 14597 26054 17196 7085 44573 51001 54277 38754 12969 6316 18764 21823 35357 56214 33251 20501 63616 54900 3182 52573 10737 42708 42487 35698 6591 50626 44417 42470 35638 7292 12500 41096 62519 1750 2489 6534 50548 34956 7084 29283 62827 22868 60382 33956 3929 48848 55069 6647 23084 44965 20004 53709 42700 46019 50230 22112 23909 28382 57485 45947 55105 49118 15847 35602 10830 28091 61175 26024 43964 11247 50366 53817 43807 10590 30717 16923 14706 28724 29639 37124 34530 60551 59747 19333 61457 7817 1936 35897 20930 33120 44658 931 17046 36416 16358 6125 51016 34960 29358 36487 48103 47806 21064 62765 32970 44798 22635 45766 18981 19610 63817 9749 21217 12052 25684 7229 1121 50342 25091 33341 43495 6466 1803 59609 45241 7819 34509 15798 44053 52626 42717 46485 39845 20104 22882 53241 27589 58678 50087 43046 27175 59589 40303 15402 30330 25632 40773 29995 46860 7792 53737 19028 3246 17195 21678 57847 46205 39331 33862 14558 11263 41579 10417 43244 60127 14284 45502 57277 57762 10246 48849 20808 13823 5330 51587 50496 38894 21588 54742 42047 18702 22763 8901 32815 19086 59744 30060 16083 23682 38209 2283 40038 25332 52900 6442 8774 18932 37533 40694 23163 46688 10338 49208 8459 7180 54718 40960 19745 21612 42739 49945 31630 62805 51112 4470 46135 4454 24829 50941 48221 59964 37925 24618 28507 61107 44727 7800 42294 46664 42752 54059 162 40058 33601 7665 16542 12340 19861 30692 23180 53012 42113 20730 43611 19317 42914 28018 27586 39327 29898 11469 62282 41045 50190 33020 62418 4266 57262 15758 39436 57676 21807 39754 63092 44852 61893 10918 3518 2039 59607 748 23075 23014 28947 60366 4898 4546 60671 57137 24643 13478 26488 63944 42252 14595 28083 6014 35875 19653 52291 21413 63413 41774 12067 28993 27457 5405 55996 37372 40040 28020 493 23026 34491 25794 5483 23012 49092 1795 21287 59386 38567 52749 50983 60484 34296 91 44123 21176 35739 10785 37083 49132 48604 53484 7741 18780 62023 3453 18105 1152032819 3459447924 +1024 33525 24346 48686 14466 12230 14419 1025 37760 38260 62291 24791 21634 56789 49317 12407 33767 59422 13979 5436 35270 5447 2906 37633 62913 53694 26427 52821 18561 29694 48222 48492 4226 54437 53894 48410 40627 961 62944 43346 43894 55463 42664 24184 60353 56018 24788 31442 5292 34278 5596 4885 374 1463 43184 11372 43920 3729 48671 55741 487 36838 8980 61608 63965 9582 55616 38290 57384 54082 4353 42586 17991 45186 55936 63630 2271 52360 23516 57446 16409 50231 57338 27796 62305 54801 22803 318 53078 50622 56861 34705 60949 57852 48768 7848 54944 3414 42130 59284 33628 9874 35600 45752 51384 61435 55435 25405 35370 4700 14151 64218 41865 23431 23606 37819 59276 41582 736 61005 33069 9788 20507 64037 45854 59742 51091 52747 40276 58220 45667 61172 56386 27535 15243 33126 9337 13398 37928 45330 61241 26639 26514 45376 35793 62595 12143 13439 17695 7922 16656 55408 44560 18188 12507 57140 39862 63383 18502 26748 39838 26064 40729 25661 28691 27021 59447 61721 63506 4900 15023 48039 766 35598 51187 19943 11548 3627 63378 34349 23206 23362 28161 1596 20068 23854 62232 38138 4940 57779 3518 25296 9027 11240 54154 45699 42751 16504 61374 2405 20360 29434 36190 18769 56158 54989 50628 34877 53022 24962 626 41308 34749 51177 40534 39383 8090 22900 41646 21468 57552 28812 14857 24641 58094 46945 2111 15804 12831 18943 43997 24212 8663 2851 35976 52574 55097 9687 57481 59899 62359 50722 51338 8292 48731 9315 52175 1780 34404 10053 62017 17487 38904 24723 62209 25132 45635 55354 37909 21461 10624 5180 20241 52836 15375 64131 55679 3597 35989 21415 9525 12626 61381 43102 17084 20446 21986 9128 26543 8350 47828 57084 6586 63363 2164 48536 56833 48629 25872 16464 53424 12396 21611 57753 63623 25356 38732 27067 28725 46343 19182 34592 50591 8198 51326 54275 38399 15183 10622 35974 14819 14275 18240 16144 59142 39439 34088 63714 30542 39730 10583 27418 54201 61744 52627 38348 47017 10601 34566 34524 55779 18388 59832 37773 41202 41217 24785 41186 43066 26108 49092 60557 60598 3726 10966 21647 6378 53700 9423 39599 46198 38938 58947 47658 46834 41505 26882 43473 43665 52999 22379 29302 8965 29475 56928 6790 51696 6002 24668 5682 301 44819 26702 5994 60887 29145 3569 27583 2556 29724 23098 34120 29928 20675 64440 5215 18548 5043 63451 52448 28954 60442 3904 62988 49934 52756 1453 33424 8900 24854 54600 6906 5410 53967 61383 47891 34012 35942 4593 294 59554 10309 58886 17725 24570 61700 60079 63812 7324 35531 25716 4275 61866 10597 49695 49644 35653 27073 11992 36153 43796 63483 9920 18975 12321 59298 1472 48044 53559 4558 8146 45217 6139 22865 20477 45354 46864 56205 42004 19256 13248 51090 34803 22786 4242 33792 47416 29415 39413 7211 62074 16532 32946 23104 54586 51195 58923 23680 47596 33682 54098 17671 40210 60625 12259 39910 42683 390 64175 36100 59183 35970 34834 53172 42390 49388 18884 31306 16134 39332 17612 38728 56355 35539 12000 35238 8020 57746 26684 33928 3134 8171 10741 38679 7652 56859 18894 11777 55133 29198 36358 24740 20785 62732 23064 9653 56847 33393 374 10790 42952 20797 40635 52491 12286 40644 3551 37342 7345 9876 29704 43255 60114 36069 48979 33603 167 44592 39773 50912 6152 9170 47 4757 6111 23760 19457 61186 41004 41217 59757 61621 53681 41770 33109 52116 52912 3299 3848 50305 12030 49491 21331 63285 56211 40648 1934 15961 331 8640 56527 26318 8568 13685 39414 44697 24638 9655 3487 31341 14114 63041 38906 2489 63026 3498 55476 26542 21541 38934 58529 25926 30732 31068 63469 10474 56623 52980 26120 58026 10078 21825 7392 58397 39274 6622 6652 13333 23794 13018 1733 54977 22042 56985 21263 58776 45504 56865 39260 38910 28080 6747 38455 50809 20772 5178 21712 10322 21511 45980 24607 28897 17441 33084 45477 3652 52450 36098 51981 33329 121 13217 24311 55927 62668 54158 1044 54434 36897 26861 15742 59071 26285 9929 11930 18964 35406 20353 6338 34848 57397 22577 60061 58107 9224 53878 33936 5361 17534 31601 30243 27212 32957 61348 44437 56076 28705 28761 23319 62325 18947 42517 19132 8541 692 36580 39482 14721 51310 11452 53521 42062 24850 12314 32852 14930 3231 16946 40173 39657 1559 15143 64384 18799 60121 53839 19778 64173 36269 61188 2854 44428 26484 18746 35540 14291 31469 1022 17599 23831 64434 3809 7547 2539 35380 5792 36731 57312 44682 33653 5347 37893 4452 11982 50874 48481 41462 4173 14715 5508 14894 9642 33646 43593 12405 58751 16626 30782 49957 13462 31259 55111 62541 59712 49081 29035 57960 64097 38717 63404 36703 40768 56775 58699 30117 48280 4272 49477 24412 20714 23056 38671 59288 38488 46552 35742 30708 56289 28102 11500 27082 49805 16463 63619 55120 60536 16652 26830 21357 24589 20431 7084 58598 22960 3592 37204 30115 45692 63298 27771 953 10247 46000 33219 19627 45028 57396 52032 56969 54248 53141 11061 13307 603 34438 7245 1981 27058 29588 36411 2647 61740 39544 5949 38802 37437 44503 49263 59094 34218 26746 28899 5244 16566 43927 33871 57256 46700 61779 39596 1054 18120 54099 35525 48454 59209 52224 51683 26784 97 6528 29512 19651 64114 28231 53921 43596 13707 53659 52586 4083 4900 46804 12407 18224 33924 53222 54580 26901 11776 24420 48735 14566 11204 26300 58157 50767 18407 25846 10333 58105 56199 48401 1949 63500 10244 25128 7921 59878 62337 7914 38482 45030 30489 43857 26536 46046 63268 48920 43752 52224 13956 9902 27814 5624 50928 16683 13377 4581 19621 39209 62794 29561 57658 58360 27909 145 6314 16403 21062 18667 45785 52564 52551 26838 452 4048 23073 12958 49273 62254 10847 32930 26019 31670 42931 19445 48420 63693 51358 48630 13010 23849 34535 30641 61607 30631 11016 51192 16314 8319 5449 10106 59533 59688 17514 53596 39820 35835 36189 283 47310 59503 4943 51330 9993 58448 49272 15978 37363 16961 52046 40920 13478 9907 58538 9983 58322 9874 40242 21877 27838 39110 46221 13838 18745 54661 54998 8763 49785 30554 36355 19286 60647 54397 16723 60454 135 59969 16782 49876 40287 42913 47424 46406 15629 27175 60761 15924 50115 2700 47004 16739 58383 38680 56605 24889 26779 7998 60529 63878 33693 19343 32815 4765 2065 20281 23439 14351 15081 48369 31581 49298 20079 21398 43367 63470 5299 26138 24106 27330 61151 54642 1223 62295 64 3971 31151 62010 2601 30026 29618 42607 49808 41523 42454 17168 38736 62475 5899 24858 43907 5520 48344 58401 47473 53863 49345 23442 38166 19848 19556 50636 9991 9933 7195 28169 45325 24920 11332 19278 11591 34756 62888 33765 3019 49355 7946 55042 8744 59152 9149 33772 1520 20039 26184 10796 12191 37355 42555 31032 46724 12334 11571 23744 20075 12742 281 26766 21363 56076 12971 31431 59048 29264 57251 37525 2289 1468 25490 31256 36266 44960 33001 4919 46195 35873 63058 43167 60833 24267 50250 11164 60841 2886 4201 50229 18670 56093 14620 53045 27817 2236 8409 18631 12131 10954 18378 867 41383 25163 10418 11560 27509 41010 20085 18458 7306 48286 51439 38570 29228 52453 40793 17336 53578 33839 54652 60928 18192 3763 28408 56177 28848 57229 2167 40913 31589 14767 14555 62199 10040 42331 62758 13519 46172 40898 9533 63447 60019 48834 24184 9107 57079 47637 12134 61789 42232 8964 2998 37001 56663 45157 36947 36919 11955 17823 8143 43282 26279 38684 22838 17058 53900 53089 57143 34305 53707 1128 51934 55501 35805 11211 48487 28018 23641 27642 54162 52405 48810 6585 56181 54017 8391 10178 4331 59476 24348 48091 49986 28186 35543 61100 28293 33821 103 30497 53664 47487 57904 55364 61257 243 13044 28620 63891 21726 16019 57712 8270 40751 34112 63360 2220 49962 37418 18374 37852 10445 52667 45829 63491 54114 53081 21622 40378 18315 11787 28707 21554 30399 19404 29120 22468 45896 18509 23330 57714 13469 52095 63818 16902 25378 49582 61070 15232 56903 15469 31344 51783 45425 63906 51564 59216 1955 62011 27755 437 34728 30370 22715 46050 24772 14878 12726 12870 55596 42968 59334 42529 38474 42570 194 33292 20929 17673 24677 24117 49957 5664 32798 13353 15918 40501 24526 31225 61505 225 16269 34382 61940 39069 44560 44922 34146 15743 21988 21844 11613 55425 28011 23795 48719 42269 30639 24813 64036 36159 43758 48276 20893 50822 52920 38489 50087 50691 46545 28868 52993 11519 55378 30418 20625 54231 26848 30153 51019 50604 40145 21042 37161 22085 53815 28701 309 3912 22373 48052 54335 24677 58467 27242 20939 41995 18245 19149 2650 54625 40278 58716 50413 28515 42470 45669 40094 18602 33133 10702 24087 20580 12579 49773 30011 11879 12819 53625 47174 14507 37153 33341 62683 18589 62079 49104 36005 4676 29485 61465 15446 47013 4900 38082 22758 4860 23080 62489 12160 21487 31302 19023 35712 59060 13877 1403 18669 21570 28258 30032 23877 61657 64267 27342 42071 48762 53525 33314 25843 5701 51249 62426 23460 18571 18308 39826 13292 7842 63865 53032 24479 48150 56846 52647 42532 62231 23915 17986 45347 53608 21441 54616 57384 50394 64065 25815 59586 33085 36876 54011 45589 31463 44556 20139 17916 13748 43132 62203 44223 46093 43429 8423 18970 59447 48615 30415 16658 16109 11843 53712 1300 43381 28151 49915 49065 34631 60589 46055 49038 48441 17858 47088 18955 40260 45176 17446 15898 20834 37462 16622 37006 20155 51181 23588 901 61681 59988 34182 44905 1214 9362 35932 40360 43689 26725 7277 49072 27934 23961 2309 7472 11966 25399 47048 44487 18102 39438 42299 63681 58342 52752 60170 4560 48089 45363 13263 52108 23521 31707 38800 19065 36796 17206 52682 46972 50204 62694 58924 38060 11553 56939 47536 59592 25605 46827 33087 6910 60862 62957 20739 41605 36176 44373 35011 45252 22880 18679 38983 30401 16742 48902 12086 26915 35224 52176 4734 37816 30038 53515 21314 13300 33428 31291 56120 24301 31252 41406 62218 53336 35872 26587 34677 19165 5097 42845 46106 32808 44889 1500 52480 52847 54194 13598 38743 35122 20101 64297 17515 55255 22226 57159 56706 36152 40392 40110 27035 44573 41903 12726 36052 26751 63530 3554 34566 30785 61600 38563 18082 50104 62699 39449 60389 18900 20031 25016 16266 2346 7698 18632 46724 49392 19210 54462 51680 52229 63456 34057 26656 37888 51027 58348 48814 8700 20443 19272 42125 20148 33936 29417 6797 38088 36541 752 3013 18863 56174 18988 6811 33291 49548 12727 21806 35364 37310 10645 34410 18979 14534 53897 15035 61755 12876 62490 12422 34121 4262 60142 2163 7946 52899 48920 53784 49857 2677 53722 60690 31203 59664 6946 52716 38146 50329 58346 42702 35282 29062 63260 27554 63896 25737 36650 56790 29086 27275 61462 57629 36418 10336 41911 31649 20807 22312 18604 55334 20474 20951 7449 58885 21850 20694 47294 5984 63215 33972 57158 44221 41761 7226 24499 42649 52271 48677 15596 14507 62904 4443 8592 63268 12359 4795 43089 1403 50354 36535 47390 39562 3985 2447 37930 30693 12549 28340 36724 937 22245 10140 34163 26847 35756 569 19197 25368 56407 49190 8956 58452 26638 20905 47856 19020 51642 42695 33208 37723 16910 12019 15300 1608 62058 35448 15981 25259 48963 52416 25363 62097 21263 51102 51326 15042 12123 22593 28477 35926 39228 36346 38518 63304 35457 12643 16962 45898 18870 16441 58369 14756 24631 25825 32996 53368 36332 33915 44060 3737 42860 45278 59209 9965 18331 48617 18647 19487 14866 672 43053 59434 19656 61176 51288 19721 20614 39025 60172 27102 51071 34950 27458 20532 20631 60530 17582 60956 8474 9188 44435 37562 29919 49461 59257 24906 62210 30441 53544 26349 64110 2004 28536 3636 43921 11319 59267 20618 26459 61410 37648 48016 4168 29233 8948 63651 47352 6025 41355 14568 39844 43109 5019 52766 63444 46306 4190 52011 17024 6677 16770 10097 55785 54814 5537 56843 8127 12345 45266 14446 6157 13444 26077 2164 2970 15266 34856 19630 2217 17596 17909 29880 50680 36240 51882 49182 32781 13265 57209 22933 59416 33401 59022 21617 62820 52529 7420 37909 19810 31495 11041 30597 58301 42483 15125 33157 36946 27663 60650 29174 34810 37040 5745 8624 52512 43736 7685 38121 23368 38386 26941 19679 6194 19486 50142 34229 37069 53426 40781 60079 26176 14572 47136 61552 10768 46733 33462 25389 15211 10324 52665 55591 19229 25907 37895 31275 29580 4254 35625 52584 7815 45669 31155 18973 58293 4960 56632 41182 59528 33812 16694 1924 51767 40756 50462 26617 60910 10848 55226 13690 30228 22974 38794 64073 46461 43781 12867 630 36460 16131 63581 421 907 58 10279 26332 29068 3340462237 1307442022 +1024 46345 14382 58590 45864 46378 22089 28579 28246 53911 39889 15459 15722 60660 39797 62364 38465 44848 5608 37256 20653 29874 42523 59296 9069 63990 22676 62913 33209 33770 21779 39505 26973 16529 2341 55622 12399 42483 27568 45966 11540 6084 2273 16313 20301 15207 46543 46740 15014 10029 24273 37134 63939 57916 60954 49326 63429 46311 62049 42713 16792 54445 28909 275 53918 38190 20335 55514 17027 37650 3562 16935 23643 61164 21841 39041 37720 234 42483 28383 15930 29619 21176 50906 38933 15464 4719 35831 19311 54462 1837 6753 49270 17814 57414 47611 7804 2273 47359 35829 62426 21132 7373 54344 45498 7053 13858 64297 40332 18518 1971 38286 51987 61417 63319 38165 29909 30871 40015 56207 48226 55388 21995 28032 24932 2432 9276 19297 13105 17312 62255 17670 47304 50006 24809 58261 62007 54746 13320 288 14029 29998 59106 55958 55278 62233 1840 35927 15683 6920 43038 27053 34310 42848 54298 50403 42392 24283 52697 40357 66 7743 4229 30866 63183 55384 6096 806 17666 62699 16578 26342 33499 13023 60512 38318 4836 16315 23562 25692 61719 48553 14246 39178 35669 26616 40948 26564 44222 31433 59423 13839 6446 59623 56465 35026 62659 26662 28783 43296 36100 19505 56664 33006 24691 57983 42372 48827 47299 29846 38840 35263 54021 55929 5527 5691 22492 3109 28822 63328 19544 28047 25927 11304 57143 46176 2664 38118 59698 15515 15140 51969 57805 53233 39236 4479 13061 34106 62416 43278 6596 31736 22829 63823 33159 30127 20443 57349 19499 4840 12185 21027 41709 9406 23913 55209 50949 30788 43996 63684 45507 21432 11394 4727 5851 52406 63576 17369 44282 38518 61092 204 35697 11395 14554 14200 60365 53309 54049 12831 30591 52556 22702 52743 11266 45359 35143 60985 23629 46982 28276 62604 23624 39878 46674 6694 30704 9818 9410 51775 45978 1554 63329 63231 4194 44738 29201 21740 47205 57954 23123 85 4137 12543 28373 61561 1083 48501 45696 49595 37345 31212 28006 25830 31398 13531 1724 39448 27097 30991 48838 41065 61389 16108 41659 59565 62744 55369 60996 59959 63003 26799 24902 7387 56247 44744 23265 30120 40585 49612 16190 36315 56949 46 47971 19405 9944 55906 6155 44117 52376 8262 42207 29788 63115 3806 6429 57192 3594 30975 25035 4586 22731 46885 53386 24664 48252 41356 5127 8451 42473 39189 38844 17524 47554 28429 11913 64434 43221 36545 42382 27019 14236 51571 54672 36456 56754 2124 30248 22729 50697 26511 28254 53944 39322 24958 30493 54853 8867 23547 16647 20074 46493 51262 29932 18082 19147 61570 29523 63087 39826 23848 64155 37365 20081 54044 19587 26134 941 21527 35437 42162 63156 62713 37755 38799 14489 13236 57816 55726 13509 27230 29270 4606 34549 56506 34309 60607 6128 21903 1671 53038 39077 12013 11265 60683 21714 16864 3406 40883 11286 10844 7883 39170 63819 59147 9728 21465 46594 29560 44400 4629 41111 11888 33908 47980 57142 45102 51448 44637 52237 47196 3251 22397 7139 63470 48923 43470 37288 53609 14310 24905 51645 2501 34976 42547 30577 13856 22723 49005 37974 31173 39839 48397 24133 5962 60651 3772 61376 45199 61519 50000 1587 24372 57309 17929 51519 62905 56877 59256 29607 56775 8163 53264 9279 20539 54585 25734 47839 18687 12582 39271 12202 46290 44709 34277 46425 41496 8987 4264 40323 27015 58533 8000 50662 3751 49978 8204 39112 47603 16616 58219 3765 55122 17532 31138 14374 47699 37249 14435 54743 3101 23389 191 43849 39557 35698 22744 47870 63473 37711 48185 58166 2047 27005 4143 21084 49508 7887 55569 45604 63652 47322 21114 50548 53652 7510 6877 49051 6125 10223 6960 45438 6911 27689 9214 48111 19451 61447 33403 53014 3973 23484 56949 29325 29565 21401 13625 7036 28482 19198 59826 30030 43053 11252 56227 43070 55886 41940 53442 1337 46740 3987 61773 38339 14028 14428 59250 36056 40040 23305 19944 36261 10475 19886 28488 33615 5352 27475 14062 22646 41476 29205 64505 35964 47921 20499 3863 55850 12497 8674 42245 41189 42554 33462 938 17765 51014 56022 41617 8721 48519 48137 47800 45913 63605 54366 3169 47153 28333 4781 11357 52224 30910 472 39275 31362 46622 8414 33029 9618 25669 7130 28225 10223 5981 33735 57823 4196 31732 55677 61914 4716 10533 54120 1361 31007 49080 24520 21750 26156 53888 12587 5923 11191 27952 60411 9511 58896 9632 47514 5072 26392 63789 43034 30978 55613 37702 10387 33424 1489 5349 46280 29371 49032 15674 15808 55748 56145 3297 18763 15811 53210 57219 27145 38260 55408 23087 22210 44929 28903 61534 7624 17214 47230 7194 20567 54573 49753 14319 16463 52332 33780 46307 62942 61520 40019 44155 10670 46918 14593 19337 54740 12286 44120 3892 29923 27666 38127 28223 8749 42741 29288 38285 25667 17568 58305 57505 50743 31095 43728 19662 9342 22617 59652 40344 2958 15586 169 15017 3699 5240 36640 36753 41914 60735 26033 40973 59638 31121 5393 26061 7557 53920 44089 4237 11586 42625 23741 3076 27084 10780 26793 7105 36279 46467 50132 730 52449 14345 47062 61845 51196 12645 8860 59425 59797 33429 32773 4361 375 4866 24601 46550 45230 47960 13644 19347 51551 38367 54772 8054 22305 11007 17618 1373 37676 2387 37617 29194 64049 62839 3264 54366 47347 53277 42492 48330 25619 39633 57099 6084 20084 60633 21180 2594 4302 22581 40471 23962 12150 38057 33855 45399 54426 41978 63254 54111 23269 11327 3471 53860 9029 27763 19076 35033 22983 10126 35935 39672 25727 35510 4475 52868 4227 877 13010 11111 39925 42371 41167 41665 25641 13895 38444 10571 2287 49440 57652 38864 10104 39622 4026 3140 6181 33369 42803 24798 4667 24136 21537 45393 20104 62017 43783 40399 18791 7488 9569 42073 869 62922 42037 1259 22134 20038 55040 27485 63380 8857 52245 17156 35109 45901 29815 23724 36368 6300 33256 1843 15700 17678 34959 18720 21080 14980 8243 57120 63426 48230 39141 45079 55695 9242 45818 64298 30520 51186 20950 39189 26953 28447 26014 39640 62816 27490 36916 42807 28673 48214 59785 43377 38353 17973 51877 43462 23427 34604 52341 29581 61122 23842 30941 13351 23023 50807 55108 56803 5623 4470 57725 58472 47532 16913 58517 63032 58863 71 15398 23791 48804 31270 1626 1331 16635 1765 30865 27240 5234 34395 8723 8116 12977 61360 59387 34108 54894 28116 40572 42023 57942 53891 36929 22277 1530 28506 37185 28677 28262 54439 40864 56334 62113 14047 55967 18833 24447 17380 4911 52544 3546 40495 28388 21095 19240 55645 8544 4743 28450 18158 7421 5926 4025 490 32873 35320 32918 10668 3967 31624 50678 31301 12074 57596 33619 52528 46611 12585 23019 1293 63291 3765 18381 19097 16546 5958 13847 47540 46026 62906 9147 25574 60641 33636 40474 6930 51428 27214 57656 54356 52820 57718 13538 21470 1621 33245 55085 58028 10150 60368 12193 46800 36277 55441 39818 25713 45860 34882 56066 4622 29659 29211 3653 14615 11124 6690 42593 48267 22001 47672 11639 39016 42187 47161 56313 48022 49750 18297 60731 41431 7550 17903 50789 15222 50899 22137 10040 56069 32886 5528 37293 15355 64080 22606 50125 45611 21378 45124 61294 27763 47692 51366 56891 3690 29444 54585 35662 51080 9345 59284 16711 16264 13915 16133 52936 41586 4683 9923 23793 16768 14568 31579 14630 59909 58355 60031 10150 64373 62690 9952 16120 10293 21122 6995 8809 16020 55949 15786 33788 34155 63546 26827 38165 27668 48699 35152 28395 55255 46309 41098 57633 12639 42737 38071 38956 59201 21899 22472 36277 12184 20899 12307 48654 35759 14031 49813 5629 52316 59212 27769 43501 19764 2044 15012 47495 48599 25657 9700 28308 17994 2538 50077 14113 62961 4814 46541 34290 48807 17392 42590 51703 37635 53158 10015 64356 8194 22667 23058 30250 11653 54924 10503 27608 16107 25695 16902 63052 60884 62336 9490 333 48528 30990 16122 38968 49776 16173 4355 39496 37332 25058 39413 47863 63041 25782 26131 46979 7428 38302 8019 53668 6358 60703 37565 57905 14056 35678 30562 14287 10791 25795 52590 48366 9179 50133 49400 45821 25103 27642 10062 29900 33745 53274 48134 48146 53568 7616 29029 58128 2199 684 1685 57729 56532 62807 24137 55183 42201 21742 49306 38960 30465 15645 50580 59744 47028 20506 5546 43365 42695 7253 63871 31614 27887 53637 26486 9232 28410 49628 40435 20393 282 19079 53648 58295 54937 49332 24006 44835 23138 8134 34872 17916 35977 28395 30652 10838 50224 9087 33579 51843 36638 37734 4734 54272 22928 31566 6485 24871 49303 59529 40911 49902 45564 57376 4656 61047 59506 44919 33879 40703 53811 8679 31576 27692 60614 19178 63365 33146 28640 64138 9500 47822 57669 6528 22883 33344 22087 56020 1415 3480 15106 48839 59612 57268 3459 25575 20375 5728 53655 49941 43604 12930 38545 34483 33377 35548 42681 2599 35695 29686 23350 37842 36911 38879 3666 59542 45934 38383 4860 26589 37250 27913 1161 43464 37424 20535 41472 6019 13170 22551 4991 16595 43943 11858 46827 1912 59895 57519 45906 8886 18117 13783 36245 6992 3824 63116 39048 36731 46482 34440 49965 16763 28089 52863 19052 27954 58053 18604 34916 31101 59277 54237 36036 9168 60026 62964 44797 17825 23901 4319 63885 15259 47283 18550 42611 51195 40272 46600 20861 49013 12497 11833 8599 49628 6377 12913 62188 8929 11786 19128 11052 30720 42590 47616 463 34964 8436 22818 16770 43770 27395 43729 64418 49007 40292 24617 11512 52190 37526 38669 46195 3410 27742 28200 1517 49031 12001 60095 16633 41237 62367 17593 17960 3945 56420 4977 49680 3100 7160 50079 27114 24028 9936 48945 40814 52458 12369 21786 53460 171 56639 60116 25508 15230 37585 30539 43086 39177 23846 9529 21841 1788 43777 15548 42184 16078 52011 59428 17724 590 38302 55947 16470 50171 45002 51377 1540 8584 1685 43571 34255 43843 51332 34990 15539 14560 42614 31327 20558 22432 38790 3104 19076 45294 6421 41403 30726 8181 4519 1831 21195 62255 39664 45929 6275 55683 24383 58116 42750 1080 46851 51432 42433 11193 5205 27558 23761 31738 21696 19850 60047 41638 8388 64003 4239 62254 6512 8130 30872 57573 52743 43612 31435 2114 46463 19218 33514 52849 49811 22023 59318 12912 29440 10954 42239 12920 33536 1858 42845 7412 22424 63342 55031 1666 58623 40124 61017 52452 51155 16368 29554 7116 7683 39403 7925 13517 43305 5406 58668 28218 8732 36884 3885 34269 49316 43257 28614 44087 60528 18122 869 10985 60080 37178 23962 48086 5214 40659 16171 51107 26856 41954 55155 32825 50933 33106 7183 40442 9027 46131 63235 64220 43526 49331 26896 27607 59218 36510 32950 53541 56052 16079 4442 17409 60113 61437 47253 30586 38134 46746 57058 6816 61372 41842 34507 33965 9577 39377 22082 39326 62178 16723 33648 56682 15174 22386 26916 25028 55394 7376 51224 31323 42608 16409 49119 38360 27209 29507 33913 193 25011 61225 26663 12175 3549 51312 39854 9827 19455 4439 62699 6858 53392 23576 60693 34186 26513 27813 2860 34113 36231 12947 44829 22708 10186 18396 50699 62215 20884 29876 3145 27856 872 44866 103 46147 26075 61929 15327 8214 35322 3538 53162 4810 52497 33448 8185 40107 59282 21343 14852 7122 42192 23463 61300 39320 45189 12448 2647 9400 11562 8621 38966 39723 7228 52092 44581 45932 58738 5947 9212 17503 4660 11967 35509 58591 21864 22861 24846 12704 64464 29474 60906 22412 39839 64288 51451 40010 8112 56295 2570 39520 12193 41884 2575 31612 49757 19248 38235 22837 38235 55533 46354 13665 44696 26336 19854 48597 56480 32991 40409 53015 34419 59444 48781 21705 40650 54984 27784 28356 44013 43421 13899 23017 42849 33820 52595 11913 45385 23418 35975 60095 17229 16120 50015 60163 64158 39111 59668 34759 6712 47012 44288 41211 13728 23495 7848 44507 27238 54270 54896 39789 52994 14418 58782 46328 43947 60670 33995 34219 58627 53711 62495 44348 59454 30682 24714 7109 50482 4620 24364 12661 40882 33851 33697 56519 60912 39682 62770 43831 40242 9658 24226 45938 160 38835 9672 64316 57516 35150 62153 2224 13653 13550 47617 29738 51398 4850 11753 58223 44854 46945 36929 33586 27337 34361 61429 61473 59224 24088 40208 59521 44671 9246 11375 39775 38213 13764 22737 40399 17605 38997 16976 9136 62236 48248 51439 26009 13067 35310 51588 61881 42699 64000 10502 29568 42231 30884 34774 58561 12123 62997 28826 56631 14926 11276 8949 60021 2279 23404 63071 11088 52770 745 9487 41874 47504 51140 12521 14899 49306 38783 45415 22954 23003 22 41213 62162 7789 15510 53018 21885 5840 29787 48545 23254 35701 9459 36150 40957 23788 40192 43763 60083 45097 17983 28930 29461 0 1334124374 +1024 30454 31268 18119 52166 23825 30329 47632 54345 8658 13815 53349 21142 27640 29680 24809 48473 48021 20411 81 47118 5339 54906 17188 43220 14127 40049 49587 35246 36509 54498 686 27358 19283 62946 55622 11171 29739 2191 46489 8483 44240 6414 24792 366 13608 43055 35923 47711 50790 57460 21822 20752 40833 20521 62374 28271 42107 60015 25266 44779 34975 33793 9058 39833 39607 14199 32823 43427 52929 21615 4457 15937 23304 12866 9979 1610 11997 63517 29983 15227 63414 24953 18660 43943 39808 45242 61485 38249 18621 30905 43040 18459 19754 60859 9707 15316 46128 63426 61025 20582 43701 27285 35294 39157 25804 63271 57127 37971 52910 34624 11497 21481 27912 59235 46841 59805 9580 44475 6062 50447 37980 11560 23397 34072 41283 23922 55425 57619 92 7620 25152 52535 39870 55408 456 62808 12078 42283 63276 63017 64239 10984 11397 43894 16982 56005 27243 31585 55603 2855 51613 10426 52349 60950 43927 29474 25133 36894 46357 56244 21498 27404 8254 23310 7356 12514 57911 7434 40647 55777 63065 61069 7641 50676 31337 33777 49071 7560 43624 61906 56676 43049 52132 42206 28383 25169 43844 26107 21416 21769 26197 23500 10190 6265 29794 63156 45626 34877 63277 58072 8832 16531 19046 19076 51835 61403 43449 5485 7722 2999 35821 49966 56714 34396 44561 38475 56347 9972 194 11872 27609 30430 21079 17854 9127 40479 54315 46035 26539 3788 35398 57509 44273 43671 39957 1096 52421 62726 3993 38810 54608 22876 36001 18270 38374 2779 15333 677 39025 43115 2210 9504 41212 46092 45474 51098 42906 4424 42513 15265 19688 27912 39413 21708 37305 57481 50189 56301 8218 13050 31091 8540 21893 15235 39867 38813 59464 6184 28176 47058 24232 62934 1710 58839 9138 38957 7378 63077 6414 42404 15405 49771 27678 61501 34784 5585 21713 34800 60077 8711 62197 52932 26706 58551 4288 48085 13139 28603 48387 8762 61802 2561 49539 2215 47315 48220 30775 18106 27308 25002 48511 41951 26755 56064 4162 7624 60374 2353 47868 3737 51338 9569 52592 12076 3018 55572 24015 13397 11533 11326 53684 4367 37420 36837 53692 8796 9021 53334 2298 38521 44321 25134 6621 36002 4528 42529 40701 27461 58081 30571 41899 4013 47707 14508 45653 61291 20539 30260 14560 59458 11867 456 63742 26703 37262 30708 52303 16238 58717 15701 58373 6337 3947 9862 50517 33652 63436 61036 50118 672 61538 24220 12718 37434 39607 11430 17072 42435 63539 38256 47015 7074 54671 11879 51289 63193 22223 45310 62377 31380 35311 60755 26928 47138 57766 35084 7115 28354 6979 31435 21050 59698 56485 39252 48159 63714 16142 24375 25732 24585 23707 43688 45155 17782 15887 2733 10403 53524 43781 12318 20480 1339 16106 63675 22902 47647 16506 36022 46928 38966 23208 21605 10448 45158 59542 60970 35068 22224 14567 48580 63136 40604 52124 30353 35811 31267 46738 53247 5113 30310 27887 18099 855 18234 54596 37038 17339 7180 56885 38800 16689 11306 58493 4001 1866 48570 23643 5549 7393 18429 11606 51087 15992 5060 15006 49449 1190 38243 14846 4809 39751 5356 25563 47969 28483 39987 5917 29544 24550 38857 5497 11568 4072 58980 24638 42324 16900 61676 51372 54115 14550 17582 16999 23284 60961 23876 39453 22100 48597 43116 39055 50417 44441 20634 41524 48764 60094 11568 24720 11429 8531 34450 9867 63059 57040 13064 45237 63407 17300 55535 45772 34389 867 58802 9438 35744 16241 40030 37003 54915 42601 47817 16352 21005 11344 31231 23589 2346 55826 64055 36354 56770 1478 34253 42852 2973 30213 25970 19915 22454 64217 8352 53453 20 39596 340 17916 38000 38148 26661 19939 13240 12278 41862 47554 51835 27533 61498 47400 2661 5726 18999 13039 49552 13050 40576 17374 22242 13387 40928 50617 61594 52909 44775 57781 37187 44580 19168 21278 26604 47788 9432 8240 21693 28563 22493 57887 30749 53717 24058 16718 36709 5601 18525 741 54127 35899 16803 12271 52880 47486 63260 62618 16072 33972 27705 62497 37067 23188 15866 6891 48454 27766 9436 36582 61381 27233 7072 57307 9972 30623 29378 47560 42943 39830 41865 25415 25809 18 22828 59771 56587 25564 41718 11949 60242 49470 8400 63684 64261 55555 4322 36454 41993 16233 26036 40315 55626 12135 12841 2235 23931 21379 8239 6271 19372 24533 20453 3383 19499 11517 21429 16462 20569 15017 47994 26279 56965 60025 13338 13597 19152 62666 4535 37364 45799 49612 57064 6475 14010 20329 7035 44986 29597 24957 17886 15530 58643 17654 22691 13502 10872 7812 26166 19026 5017 41914 57925 20211 27039 225 56191 50427 6 57951 18849 14313 46093 58479 12917 8200 33192 2120 14938 58457 30338 44382 24577 35887 10933 50090 41548 56912 43128 18795 11878 47779 31525 30752 9552 44334 23129 31069 39415 46772 27753 15850 33062 6388 44220 10332 3339 62612 56868 36088 30663 44065 38334 21075 58862 23092 13793 3686 4786 6993 33843 57376 58904 3790 57031 13410 1657 4998 9342 20517 11758 24441 39630 9612 46562 4391 41112 2921 42241 148 38796 25104 17871 46269 50526 36285 51606 33466 36742 1936 27685 19037 50369 23363 32881 34786 17748 49431 23531 57079 44607 45474 60919 58160 31700 30221 24670 29566 13918 9073 19843 42770 62818 61594 56227 50758 39789 7886 14048 5991 39875 57041 62000 24224 57461 39994 8379 39903 54989 30807 40504 24170 2516 34522 23078 4838 3974 26917 40125 60829 11918 3074 31312 39684 9798 36822 40315 16841 18464 37979 61421 35626 35463 26702 57117 56050 893 21544 8798 12374 30094 14387 22188 11087 3922 23620 26644 15557 41054 21239 31187 62270 57421 40091 13782 49105 7157 40915 44596 23275 49839 50631 21277 895 15012 4503 25979 37471 63708 22200 34991 61083 51858 45870 36793 28641 15175 22351 56657 18859 31034 22150 12005 6445 16934 26615 13823 55710 10691 21979 11406 1335 29199 18349 28845 45481 36283 62681 20173 13478 35026 2528 59637 49153 54502 38334 13231 25984 50187 16257 36555 48933 4854 16048 1969 1817 20444 62209 31529 47999 9193 22420 20078 51132 48505 63344 47582 52070 6102 56560 60689 31349 62893 41653 45037 62212 18492 15388 45297 26893 28050 41471 2010 19380 28138 30411 15780 1536 9614 47570 2405 17437 39932 8419 26905 57356 51206 12998 50317 50969 60214 26051 45389 9067 4160 49975 26933 62090 18805 53819 40563 31351 63190 21821 51686 35142 33139 13656 24880 22291 17456 51471 23207 52562 53236 34372 8061 12478 57726 54046 46429 14053 4770 30868 1878 35583 8759 41832 20529 21826 20591 23783 64307 9087 31364 46439 17219 59577 465 61485 38795 33498 26992 58726 22735 17565 45773 35359 18926 43909 13796 57779 2469 19263 15622 63725 46663 63423 34628 1195 15905 48190 57860 60841 33633 808 55629 28990 17249 13403 13963 21485 395 52854 50055 30807 60822 50410 42218 6602 51372 3447 50165 45398 38136 43882 45893 51882 57864 52634 1540 52600 52664 28378 8615 40626 23691 31722 58311 33390 19812 62515 57127 16292 100 19618 35261 31557 15561 46936 30720 56496 38305 53595 63067 51307 1863 16906 55238 48680 53686 7172 4703 44232 44217 28053 13327 52129 43534 39513 55450 34027 62571 50983 24007 60974 30353 22219 64057 1108 46741 3862 42014 47751 43177 29788 61636 41480 31490 34972 15351 60008 46012 51495 8201 24302 34604 6133 52889 52592 42454 28493 48629 55732 61989 50060 61004 37447 20173 55382 19425 3125 47493 20633 9845 35705 17139 57470 47148 59040 46204 33417 24543 27799 44552 38984 58251 63028 61810 61556 28972 49204 15267 48196 45058 50980 12368 35920 40577 3674 38535 34104 21205 13841 23703 42048 12773 1168 50337 54178 13987 2379 17163 51799 43784 40175 22295 60725 41010 8141 23837 41371 19059 30259 63995 21440 14669 26310 40433 34900 40886 24591 41286 28735 43511 26477 42434 35559 43714 5004 46033 53394 30544 17510 24212 1667 61590 2537 9760 5974 20831 59061 17837 14229 36321 27400 48182 22467 58704 2503 38671 62351 41841 42583 27594 37060 8041 47090 4269 41626 46781 30553 20609 12846 2311 37829 39173 55184 22481 63516 38345 41747 24394 14795 27353 42797 46999 26344 11390 60353 396 35009 47745 47889 48921 40349 50938 60328 51351 26235 37384 898 57545 55449 37099 63485 48205 45684 3091 25281 24075 63757 51199 9349 37720 35738 28819 30130 19120 45278 43684 59977 28056 48153 4645 33868 12214 7107 29295 34401 48415 43986 2354 18035 25992 18493 26884 14743 56305 30366 57460 47840 28268 40548 31652 14587 1301 10864 24831 36475 21866 39031 51232 41675 64020 3171 11333 3568 53215 6004 17733 38326 55158 48184 40961 26715 38666 51950 38498 13076 13981 37877 40625 39777 11621 64328 4633 38062 21448 55470 22182 12346 24803 21596 54435 28751 29226 55650 12549 55406 23760 14076 61579 22723 51105 58531 11877 33699 9742 31507 53214 27626 60889 57300 563 6117 47882 63858 61632 59333 30666 46753 51927 3383 15611 21418 17139 45254 19641 34269 24886 40705 15902 49435 55314 6353 55928 18491 59501 14735 41171 18112 31674 51894 16921 24242 48082 56080 49541 9527 11008 11642 24279 14661 34540 25989 28771 18723 22803 20148 40360 5690 20380 46552 56987 50704 64023 60319 22674 35759 36165 3044 45451 11749 53985 5262 33755 62549 26830 36016 64101 47998 25933 41149 8001 41648 56028 34646 3597 381 40129 13226 42951 47193 19110 35337 35835 63784 13039 54480 56613 9275 56850 17169 14135 21052 30425 49018 48276 49067 42305 1146 11568 11310 40837 16897 50429 46016 60099 29495 29549 508 58832 25311 22506 7665 31154 41625 38833 25194 57571 56830 30548 30941 1875 49770 45794 16885 2100 30845 24098 54952 47464 43536 64122 55992 17912 13706 407 26139 12939 20155 55804 45811 59858 21627 60625 46040 37546 99 9518 12014 12729 49108 56609 44585 55457 1777 13242 1922 23839 57465 2585 22284 40360 61703 7746 57306 7206 47895 27826 38218 30817 19481 27185 61620 43558 63169 23756 18930 53751 557 26358 35571 136 1408 36292 48104 39494 50067 14045 48799 47643 14970 13657 12484 47535 19056 11501 39059 17938 13450 10906 24174 134 46092 612 20971 1863 17608 21925 54336 13613 39858 16755 15795 808 63607 2423 33881 61324 25308 12110 28348 11928 57519 7122 44745 47701 44290 62149 61063 45467 56265 29312 44624 61291 16589 1164 63945 33530 35717 26149 52418 8109 56267 37355 5404 31315 21280 51649 21451 33809 13669 64441 28390 27994 43390 23141 18787 38111 26750 21027 42388 38514 34323 15299 34707 42099 11228 23164 16285 8970 47250 59605 9646 63157 52257 16365 43208 20923 2542 5270 26301 7967 44779 24227 38335 7049 30070 17727 63101 1147 46674 39384 25121 19024 37523 37881 47717 51764 24588 2178 5508 3612 27720 2529 41509 35675 41218 64203 60342 63073 51769 6112 5290 25029 6729 1311 33130 33174 29116 46842 56866 30770 18174 49883 30824 19260 44046 8387 22794 19902 13776 54628 46114 63973 22625 58322 19856 57690 7323 51688 11719 20778 18151 6730 34067 30468 24007 44388 62828 41950 24939 25319 56960 15147 20418 3630 24852 21329 4509 17006 46532 44573 63607 29190 58307 3132 3673 22970 39918 7151 20482 47431 26308 43891 30678 5882 23767 14252 62168 21403 63114 58450 556 33428 3028 11064 43544 10086 55049 61573 21952 46802 10454 25860 13264 37142 33800 4528 37911 34800 26106 58177 9014 42672 12610 1417 33732 16886 16938 51088 40729 40015 12154 44518 55639 18611 39001 12427 49597 2475 48803 5147 45237 34190 2658 47544 51153 27232 42064 20096 27736 42370 49517 55434 14228 30266 47682 0 25754 15946 13141 43146 12275 25871 58450 63207 39919 6511 2284 34857 64474 267 13239 58461 34037 38813 1003 18439 19715 1174 2848 44698 14413 23409 13856 5044 64466 8528 6105 55199 61173 52429 517 51876 64422 39407 17323 1624 36552 21111 2180 454 61726 9791 10327 23601 29441 49439 21084 56522 12198 17139 37123 35877 15925 10269 64198 6918 24930 13032 6160 36230 57101 61779 2070 37004 22517 45914 8361 6907 17236 55687 20568 60571 47173 29005 60551 25875 38177 48488 13299 1069 42463 13628 753 10291 7016 56490 28522 2895 8202 60793 23671 61284 2504 48314 45373 59228 30753 23460 42979 59427 25340 27892 18701 40554 52501 61392 24021 46112 4619 20610 11132 59957 28572 32969 37259 2520 63252 53746 19347 28358 55434 22890 35563 10664 12069 25883 35060 7395 14178 4046 4130 42143 61441 64353 10510 18891 16939 64475 7066 19301 53817 53453 35653 360 33979 27982 7052 56870 5560 64289 384 15638 61278 62029 34257 57713 31548 6391 29268 9162 21677 29252 62386 13423 47866 23544 9315 33249 37469 55518 55143 21841 34433 59901 2440 7233 64023 35254 0 1333716982 +1024 56840 4626 30787 57865 50344 27213 64400 54610 11370 57043 30106 27013 27375 60045 46057 40104 53003 56525 16033 7683 9678 55034 31214 11309 9945 61019 53071 60863 49408 50432 24292 54194 53129 58858 50781 62051 9650 51311 12662 29752 35746 54239 36674 25870 13545 60982 35269 1349 35423 1858 44229 29209 14396 61459 57767 7047 20231 27898 44862 53419 59785 38080 14298 40986 45617 61144 38063 61822 28621 60886 14618 9037 60022 20283 53637 4398 21376 55517 17557 20679 21724 9606 2084 58847 11497 38372 18754 26013 50803 29395 10385 56362 36569 52667 11624 27487 40723 56234 53095 57225 63984 9441 23650 30329 15137 63972 25420 28101 47047 39816 27615 13546 14649 55458 54539 12975 41637 57866 3959 7939 43507 29386 9254 14083 60785 18101 56371 41641 21193 41591 25894 13304 44982 49509 32962 38671 6932 54530 54925 24752 33909 22839 62859 26797 26966 56762 62598 16794 52730 8080 48823 14401 49864 1898 7486 48531 27948 2882 4733 38835 57989 23886 64347 50836 42105 28559 40327 40217 25697 12053 4161 2358 25178 8615 47633 12320 49901 44431 15226 7629 58609 29299 30878 17818 63986 26728 38647 45515 42033 40617 30471 41468 45223 54942 33594 26723 45079 38006 15210 47708 4043 48982 62592 10915 25714 33657 55283 52362 8704 3117 27119 62221 57668 15236 8908 48871 51671 33000 47589 50359 7947 23577 4953 21922 44761 48276 55469 26814 16944 10010 55113 35511 22387 22573 47311 25123 27122 61948 51329 40179 55839 17790 56364 43587 49616 41874 31360 2281 12304 50716 46972 36898 42827 4316 44188 30029 54129 53017 25708 53301 42471 47922 40995 20735 8867 42517 36740 43156 39805 60144 40161 27321 11941 26878 14963 42730 29414 27872 14163 33870 53942 50722 28987 44259 565 24231 47751 21321 19865 64505 60123 12825 14074 51580 57834 4935 13600 11554 24068 46901 60751 23990 47895 12226 688 11974 57881 53855 14651 57722 40581 9063 40667 5000 31110 17803 6181 52646 6428 11803 15820 6583 5453 44241 53539 52223 29945 54878 44457 1873 57990 48704 14181 14927 16687 33501 17724 31473 19742 63683 40933 28944 12741 20798 5178 20127 44834 45737 20876 60192 7590 64131 34191 22090 33413 15294 47889 59304 62483 17994 12538 60795 48516 18205 48896 42635 37903 39441 12095 47188 31321 57851 17545 46600 25946 2147 4749 6569 46214 1374 58660 5744 20605 28300 21327 30378 62542 48794 51700 24894 10901 40931 43830 61636 42092 19129 42171 34770 9469 60334 61679 12751 48986 31686 54429 18790 867 26288 57155 6466 8864 28606 46301 54421 18434 55919 284 41991 19820 42293 49655 1909 33420 29665 37264 36716 52323 50066 64337 41050 10931 745 41449 1025 8986 13812 23011 14340 28688 14293 6748 15190 40458 6059 40018 61692 24030 22997 3753 14104 34924 28429 2924 54425 41934 46272 25874 33414 47465 44802 20317 57948 28423 39863 28802 39757 48979 57491 1143 47044 30563 29418 7957 62140 51120 15656 62313 60443 22182 36004 15127 41419 23872 30314 47122 6107 56081 44599 15076 11923 14520 11715 46412 22997 1798 46828 63590 45987 49189 51055 18271 11235 43599 58878 60320 40421 13741 23131 46699 53132 21897 57824 401 30928 2506 17640 11974 50459 10960 50345 49073 30416 36495 7928 58549 45874 35131 59442 55501 49979 36837 37290 33996 8304 26710 33028 18372 44591 42587 52104 55756 57401 59435 28300 7630 13357 63505 32991 20176 11920 18108 57986 22014 33554 43879 21603 30630 60357 53069 3101 34117 5990 24085 16338 4496 58227 6882 63533 61156 36590 51901 47806 9626 50063 28232 14554 53004 44978 15830 28386 27947 25304 50730 31705 62921 36141 11231 3552 40368 3569 46172 16003 59717 50126 35422 31414 7536 31642 16402 4868 50395 60755 28442 14119 23707 47350 11577 27661 46203 25725 40586 50352 3240 49367 17102 46180 33513 62724 15537 52168 40477 28242 62638 23603 4050 8205 30483 26748 2701 12346 11519 9859 15972 15107 47519 57525 48053 51350 1633 12625 43480 29292 850 7401 38333 32996 62574 62500 31136 11082 52017 62815 35176 46037 21749 43715 22368 23815 38014 35351 56554 35734 45143 58755 41406 45625 60595 17791 22257 4580 45789 18214 9340 33135 10814 2650 24865 19169 18489 39559 23824 61727 19490 25143 59626 50982 2946 24768 59153 43923 58534 45564 33475 9785 11460 37768 24446 430 6209 48123 54273 24627 28319 34672 61082 12517 47499 48994 11724 54096 17005 24267 3198 49157 9583 60693 34912 47743 29357 35861 10905 27682 24192 36046 28917 15148 17522 17554 30127 26760 47910 54634 3984 48590 55712 17615 7720 30604 24895 5807 11354 25044 20285 48956 54540 28456 41901 47577 49653 28343 59 37305 55052 61265 9510 14678 50784 59654 5197 20930 57995 55825 57519 36851 42703 56069 49521 762 47752 4744 63908 31270 48859 52061 33756 15800 38314 15030 13800 40766 4092 18683 52829 47849 28463 7101 26633 17405 34512 15491 62914 42771 38251 27179 41711 50632 33089 49426 6371 59134 47316 7867 32789 52516 10768 9488 24495 33871 35119 9338 63904 50276 58808 62248 6746 1195 44130 46852 31410 59059 52469 41206 28342 31054 62016 45744 6375 7772 50961 42792 57379 114 40419 11153 52372 59260 22594 44758 7989 813 2273 31386 49778 54334 60077 18924 51738 47990 62670 49215 269 36654 4027 56085 42656 5013 17053 62462 12757 46149 12951 17849 5799 28608 8471 45461 45528 3605 61829 20702 812 29404 10115 39491 29108 520 5433 15791 9647 40222 25357 7370 49685 52176 51009 19941 42939 42207 63477 25079 24778 47919 59768 48317 63950 64337 10615 28140 51543 58812 1390 60561 4079 40864 62558 16252 42553 29239 373 43614 11931 20058 46199 62095 1858 5004 11562 31261 48581 52853 34158 37275 23264 49713 40476 60663 30927 30029 14748 30282 54528 14591 37171 53395 38080 33230 49075 46648 11152 4800 36522 24854 41012 36269 54262 29934 52056 40079 47952 11134 58532 15302 13153 28803 62128 24228 39664 36861 60509 1833 29894 16906 49245 27430 40101 37068 1893 24649 26122 1259 12494 43527 19821 6150 34318 18980 61222 2836 16824 39602 51297 39402 21773 52011 27634 53611 22275 9628 60899 8764 46332 25736 41504 43820 27633 12748 53797 17967 44478 44655 45116 63169 52718 5747 29798 43553 14850 27660 29905 62216 28443 12907 62773 15625 20935 41903 60444 12581 52783 31608 60312 54784 7716 60777 28038 62774 45971 47735 20023 35910 40997 9470 53307 60280 40397 35216 20469 4901 8300 21658 1778 13715 3801 10456 2064 39412 20617 21162 5421 13695 25103 9047 28051 63589 25179 18836 41319 2970 44871 12829 13859 9449 27335 60957 1027 17956 22978 38902 37289 42613 55048 16792 31697 34010 1718 27204 12656 9138 16205 38939 3406 64043 14682 14438 16634 35319 51888 22465 34516 1338 14823 33578 43423 51883 22908 12196 54168 17816 26662 2765 27565 26457 1119 42992 20165 28286 23561 13768 6528 18012 3133 42499 12247 54771 43322 10239 6617 4380 18847 19674 61455 3242 19679 3524 21619 42519 41878 25804 63836 28459 29450 33342 59430 23490 14980 6861 21698 23918 59103 33255 20278 41685 13261 16284 10774 52871 4211 12841 35423 34667 58980 48413 59389 16554 28224 13643 2773 63220 35953 18879 51813 14262 57063 5910 59726 5865 27953 29582 8586 25457 41033 8556 18491 34751 27506 6058 57306 40156 53425 64104 3461 63382 35543 10310 653 7958 16743 61077 5258 30959 14268 14467 44127 25269 19494 36347 25994 35483 49057 2683 42560 15005 39297 35032 62527 37795 35210 38651 61549 59361 36980 28563 27828 16048 54349 18348 58910 47813 31689 20973 31311 36450 63962 47108 19603 47429 44344 52696 58899 27324 7734 11652 6253 52058 25968 19345 15426 47910 23223 64279 58522 25226 23353 36930 1796 48452 4798 64039 48619 31418 39939 24204 47719 13271 1112 28729 19343 3836 47485 59134 38873 37714 59640 1676 35111 57697 27668 52732 11057 12015 1362 28601 39553 26877 15961 30474 10829 56948 36021 62157 16796 49173 14258 3300 25603 13705 41393 43001 42641 11066 41300 40189 12591 9008 24057 55605 51961 44960 41567 40755 19250 12989 48567 56692 19997 26750 47074 51483 55478 17193 8085 6565 17381 41134 59041 9088 25326 27914 30525 56392 52069 25621 13964 46156 1849 24008 5933 28814 27608 40035 35311 16095 35228 35959 2309 52295 4396 50428 22220 14342 49939 9308 16603 50384 25633 15741 34853 36404 12395 61970 35434 14811 50090 19804 56769 3604 38700 50427 37781 18514 63359 15938 63418 29290 8843 54801 4662 52950 62841 26511 10728 43293 20777 38918 60305 7771 24912 3310 30847 28326 24367 13196 2841 18221 53637 41330 29000 8623 43824 11155 37891 48506 64113 30752 35100 57299 36211 15783 56973 47234 35592 4898 51505 1377 50086 13024 19652 62874 24712 26038 58725 50780 36776 9710 45773 61710 22494 44059 47138 26683 1839 18803 13642 24294 47437 45446 36192 15192 10764 48117 23686 22726 11500 17256 13683 29422 34712 17644 24180 7992 23539 60792 48385 16832 23342 29768 34921 82 63120 31273 23498 55021 21030 56557 39886 19869 49074 38234 54339 44123 36057 16383 35737 5519 26008 21284 12165 17388 2053 14392 58244 52789 48378 6600 55512 34908 44053 43866 31570 20622 40257 33251 11663 18947 2113 44528 42428 13066 18584 54186 8704 12965 49162 54277 63769 8702 53334 59882 55957 17068 19941 40903 27141 1865 26396 33979 30478 3702 22268 56319 788 14801 50761 19530 28280 22369 61745 50098 30774 15043 3971 5769 32931 31464 17513 43056 8444 21681 1017 43876 54676 33280 49278 16748 46899 17145 20628 27601 23427 51543 48292 3550 47854 34390 24626 40903 3718 40720 36795 44022 4321 34719 53219 49201 7510 33944 6573 42068 21184 862 57562 42999 45024 3112 7920 59282 50764 48382 40594 62749 48115 1869 57098 34454 18777 57281 25396 1897 24677 864 45174 46131 53313 16402 8893 46561 33569 62095 39931 11205 46355 3680 53222 61483 45912 32889 56974 52198 43634 26740 56794 2628 55648 20718 18194 19523 8396 5256 24824 12057 12450 38106 23322 37417 59828 8169 53066 25359 3439 38799 56529 14338 5327 63096 7181 42423 4015 59715 50913 50395 41398 36248 25292 42399 9188 13407 12125 6344 47487 11450 42591 3771 19449 40586 34710 52790 29688 16748 51651 13982 35278 54516 4562 35705 41628 58900 587 55485 61457 36408 39843 30888 18080 38684 63894 6370 15399 8179 40676 2166 49217 30261 19441 28668 53184 4420 15923 11593 37955 10643 4604 24853 27396 6244 19946 19970 42768 2086 8532 28600 14205 39638 21896 9006 38564 49973 35864 35883 11070 17622 47072 40559 32931 15486 55518 39060 43035 11355 42217 48351 21749 9213 15038 4327 11925 1384 8131 43680 2902 39972 37812 6872 9491 7028 25470 23322 9166 28976 63764 31066 38731 43918 54921 50804 55804 30695 62971 63100 24861 25579 35179 61249 22321 19622 31381 27101 53358 28083 26794 16964 28187 53619 33526 35857 39441 9757 20389 61743 51533 12322 62876 59987 6008 3891 38346 46854 39637 23140 56218 42322 31042 55997 16835 27576 3621 48697 45135 34856 2814 13648 30863 55466 56204 51786 21640 23945 51002 29974 22566 17254 46704 15112 38763 19072 43569 31741 6969 36506 13187 18494 63912 56160 55321 44202 56431 42069 45603 2100 20340 11270 19766 31716 62878 31470 44641 27917 30235 6630 20701 12886 35209 18137 53378 15873 45746 28421 422 51027 50269 20841 12866 61131 4186 38448 54144 53952 24295 3538 50178 30860 9569 13840 41999 44575 14633 14466 62581 14293 49173 59007 2527 28370 52337 45135 55372 10218 61201 29006 44608 11669 47918 33748 42645 49062 26836 42350 58834 11491 24075 34776 55776 2843 60587 2189 35704 7991 43533 3792 19362 4633 18910 28666 14260 12678 12311 28519 17378 21201 3719 18582 51975 14185 30058 40809 43422 44424 52681 22518 52009 15668 60971 50052 20420 20801 49813 54282 46997 57836 53358 22299 15241 16342 41090 9681 40008 61401 10444 44698 30497 9229 47209 30501 41439 56646 3456 6988 44926 37520 385 10069 38601 7816 22183 42370 48116 29003 45048 12963 1834 60177 16762 30020 51678 1979 18502 58028 12209 16819 34429 642 10158 45988 11990 39916 16770 41442 61446 48379 49894 56062 11043 16153 60924 638 46318 41760 4222 43762 9228 60422 61099 14966 25649 49944 3221 18982 42599 14955 62429 9536 54572 29591 46016 40827 61470 53095 39524 5015 36529 9229 56973 23290 22276 14257 39256 11902 20722 25318 54145 17599 31191 59469 25487 23854 38653 58491 35731 11244 29607 25113 24087 18420 42439 6174 34994 1543 29990 46352 57830 27361 42676 30522 61224 2396 40039 53429 4582 62398 54761 55336 52086 15075 59374 9061 59823 11432 47852 41025 33115 57612 55019 4342 21321 43650 47803 696 33268 3696 0 1282728292 +1024 54574 39840 51408 24928 59836 60513 15092 21200 35441 58201 29041 16949 23748 60507 1981 14132 60479 570 54407 37378 36781 63722 24843 46361 35793 42975 50556 26489 29401 61731 25582 44129 4542 41270 260 27962 46902 51547 56828 59827 22146 19260 4184 2074 39134 14354 46614 1848 33070 17399 617 41413 14045 4814 45897 27965 62683 1707 42371 59790 30382 2488 41971 12131 46891 23666 37744 48266 1214 61418 43237 57732 506 40065 29873 57048 52432 26183 41465 36383 45126 39870 2034 18610 42253 57313 63877 5881 41439 27372 61343 51442 59820 961 63118 54279 57085 54282 6235 25795 621 46309 11603 43241 54314 4707 4427 55429 43192 40203 15990 52403 30941 32987 7639 60309 57676 28891 6703 35406 6644 17620 7179 40450 7645 33969 31544 23464 53873 20522 18279 9221 22651 18415 7570 6874 57178 49501 21761 25893 4881 7760 63162 50 10979 39712 1725 62590 24704 45751 23204 59998 18892 7298 59700 41896 52328 7683 14623 4297 32837 57921 43255 51169 24435 49733 8782 30749 61190 36861 45769 40692 36968 30741 53101 1914 35322 36140 35970 17645 13484 12425 6066 38240 12298 22327 26755 14695 31699 22164 7396 40245 17763 1120 3448 48521 53467 25229 23484 50393 50552 5807 55584 59919 7059 45790 25457 19018 25493 41168 56220 61577 30159 36868 64421 2829 329 27043 26951 41289 17218 19604 47617 37781 27482 10780 58769 20281 41305 59712 31094 30105 24083 42105 63877 9911 35545 61645 16749 48852 25521 16604 53988 9930 2389 52063 9974 49879 46705 22421 39765 12446 52028 56307 30946 52447 26364 63572 58170 29277 3712 16154 18070 15384 1392 10469 17247 6737 24070 62440 29774 43944 1996 40577 48454 36338 9343 11959 22989 27400 58979 37458 58018 6548 48568 12308 2451 50539 19342 28305 41404 22014 43300 53710 9937 42853 53083 47927 12576 58807 27965 49620 62269 23918 44083 33367 47803 18346 56181 53943 54182 37131 36043 50454 13086 10981 63048 28205 177 57095 21175 4489 19587 54033 63914 24654 47512 45725 21779 9081 63955 53291 20129 57673 30670 7427 52279 47242 29975 63228 13459 41288 27527 17952 37076 13895 40916 4808 22868 36464 1468 41499 15262 36791 46646 47432 43322 18570 53430 33656 50820 53448 45834 7723 12425 43782 53431 42783 14021 50559 46782 23948 30039 52512 58376 34367 19460 2802 58245 18474 30136 12690 22083 22854 48288 52539 29702 38127 43404 54289 60424 53459 53729 35342 1891 22545 54914 55514 64110 24388 6067 1021 48737 38995 12715 37233 54112 17874 56212 26496 14264 8616 63969 8475 44027 46829 27148 5270 2507 17976 33397 53675 21002 33505 13831 17472 62952 44923 19264 4732 29896 6202 3171 59766 14119 57857 35766 44392 41341 2108 55000 53173 61435 46633 23359 62944 16901 21112 16744 12896 40016 17071 7202 50551 23548 27874 30986 13603 27188 23884 11862 36799 22077 11128 5286 47634 56947 27645 42694 37285 22706 14864 61842 24812 5421 54147 42828 41674 1959 26326 11501 10332 56007 43364 32915 3165 51476 33369 51317 36794 22255 35088 55450 47617 8632 63102 38772 11522 43835 57819 12175 13390 7413 34475 29721 16138 50769 22986 5314 22099 10059 2522 35911 64237 56450 52183 27834 34430 6384 4664 55757 56371 15091 39190 59694 38881 43366 47907 45617 20648 59950 1414 36254 345 21637 28829 47002 56313 25488 39980 21610 34068 11535 19772 58766 44894 35054 37986 3582 38036 44397 61390 44061 40684 54791 38862 4530 22254 58337 12165 31392 60426 33840 6287 3650 31189 5450 16943 3493 23068 5178 7631 11558 35472 1514 1595 52017 55685 45570 19678 11958 39612 16901 1370 43360 29949 50929 18380 4972 22609 33661 8743 4612 38103 59339 60886 37679 9380 55824 2905 61143 13843 15459 9458 16368 24134 51795 44439 22707 39807 10597 19886 41254 33972 8377 8796 63180 27626 36722 45122 25632 59158 36580 13970 489 1323 39401 20613 28221 5233 29740 43264 44514 10721 45815 45519 61203 25814 19956 64463 14569 7501 49865 18210 7919 54253 17388 56145 37450 45799 7752 49134 11687 53524 18432 5241 16428 62334 63398 11425 63450 6413 7183 30482 42307 42511 30316 52248 40475 6458 41583 40504 46419 27277 25667 7438 16758 56664 7262 47288 54060 59072 20191 2639 58089 9430 57104 34376 40647 20508 57086 66 7112 3264 21786 4682 63882 45599 26427 61315 3016 38947 26838 6558 55012 10224 53193 44960 20886 22051 5548 36932 63938 41171 15824 59505 30155 26243 3441 38942 15083 10821 33385 27317 12890 61531 9470 21873 8642 24673 47888 53712 56702 49113 9257 49913 22768 28166 46739 46872 46089 60018 28303 49056 18410 37374 9966 58416 41249 36216 42270 35590 12972 5390 43105 6956 22821 63605 16553 49156 48015 52639 55784 15604 24296 49919 41466 44704 39953 19600 35627 16163 46142 48211 56097 58589 15227 20771 26932 57178 12069 20209 37007 14570 13579 59740 57551 50619 49200 30366 55632 43437 7811 54976 31334 15159 13082 54011 19911 56530 39028 13098 17571 24956 63877 8855 56139 36298 34627 17655 2124 5931 49916 36559 58655 35014 43161 19759 27595 64131 21869 22382 38450 63046 41357 47935 15372 47803 25358 45239 8758 35107 30905 58721 33073 48847 61039 1440 56177 49865 12615 41210 15277 5847 56258 50858 61017 58119 17968 45456 24047 28176 54901 33919 27244 37895 6999 37988 7355 64234 38063 58070 55605 42651 18338 42793 12850 63541 6629 60967 62340 62034 9498 49028 31369 41834 50649 62133 19332 30849 37806 5536 50253 3124 30996 30370 15429 5167 15291 31014 49232 55099 43416 61029 62199 31661 38025 58777 4792 35167 24027 55543 55355 50993 51481 1007 63776 6213 64224 53762 28845 60120 51296 43514 2745 28915 24731 48903 35319 18490 15508 20480 53139 36728 15904 48967 42629 17308 14946 25373 52579 26557 10804 40874 17719 7823 43014 57617 35975 15398 23206 43914 23427 54680 18239 29373 10740 4698 33223 44559 5905 55237 18957 57656 1676 38145 12219 12678 43644 16934 27323 22663 62829 59666 10009 21226 4033 34654 46301 61505 9176 26708 36349 55287 2040 37544 46081 35636 34590 37970 35122 36999 6060 7598 41361 13083 25669 5057 31048 16204 49164 39627 6153 20577 16149 28453 49747 31013 17732 56898 58485 5653 50437 57975 12268 2754 51220 22703 50958 48120 62328 21511 21195 47919 61380 21882 46687 25001 48104 43750 36764 44812 15095 53389 18964 42135 34294 55825 2394 57521 59593 6332 59643 15598 42303 19400 54340 47078 51672 44377 47267 47121 6287 43014 5843 35630 36164 22523 23739 28958 16763 1193 59399 11369 42116 6802 53710 24338 58982 40101 26879 887 1352 37898 10576 41678 24985 148 46744 12631 47076 62611 55962 11351 3984 3333 40527 38887 12192 35800 51714 18769 25971 38329 9462 44532 20498 52429 18699 56658 25460 57445 31212 60979 47141 63796 5120 8070 1633 49927 2625 36680 28809 38158 1678 17066 7725 339 24962 55494 57051 2856 36707 27205 33763 24250 58224 1762 18265 537 52495 58419 8976 37575 9624 21354 56281 28918 41301 34111 22890 51684 17916 36046 40806 10889 38811 57296 17573 48301 4372 34101 41567 36382 63376 28623 23019 8551 26624 52823 8577 18466 18549 14607 2701 50136 44246 60227 29845 38111 41883 20100 21117 691 29325 29425 13745 33083 29925 678 62464 61998 26511 53890 30422 13761 4633 31453 21000 48392 61382 62755 52991 17219 21878 6974 12181 28707 34819 11387 45716 7596 7127 24778 16878 11506 19420 41636 33867 11432 646 51898 48468 29787 54731 45109 57706 1004 61047 27946 24630 6273 102 14446 8588 3147 62072 26949 23755 55971 42650 36052 14980 44961 19926 47362 33730 17462 36276 3610 22029 49086 25651 62150 23935 35005 25768 50686 46109 35480 19068 34792 13157 38601 49708 62567 2152 19630 59959 4542 22124 32814 12357 54800 7393 55559 11600 22713 45801 7111 48755 26495 21592 59823 21635 34839 11073 14400 6949 46709 8847 44067 27731 9432 23418 62878 38055 50984 39773 29843 45881 49032 25681 29114 57156 53592 57749 39709 22873 2340 25102 54851 38426 30715 8102 30614 64486 53174 41548 19173 43569 31539 13583 606 55696 51669 37750 36300 10781 52068 61650 23806 38649 34699 25348 53594 45110 58877 29177 5590 43230 13279 58275 7345 9020 36610 59231 30772 48309 13728 33814 60119 16413 2506 62612 38028 56954 34070 19452 43736 53745 53536 43120 46401 11437 33436 48150 3596 28171 1579 57937 45958 63126 10828 10788 35960 36558 53797 22557 691 43414 49177 33423 25646 16737 17964 18611 52869 5709 3670 7141 56970 5238 6452 13322 22968 16835 53324 26702 9542 5143 27489 15957 207 33316 61604 20548 57670 52985 40014 63109 48170 54257 28809 40105 53822 26761 18306 58486 35481 1001 59647 24391 24069 15516 31260 51800 40644 58566 51616 37007 24704 19948 39523 22529 21680 60842 47392 44640 11649 13533 3633 22083 51710 61301 6363 57544 13000 13553 46118 26394 11535 17507 25582 57025 50830 30213 37189 9300 62901 3057 22398 36834 4969 62221 26179 54627 27249 8713 52037 43714 46508 49578 38177 64105 56941 48637 16135 46350 11573 28938 52193 23901 17838 43094 46896 39759 64416 49879 52687 34144 6240 2002 64360 29743 120 1176 4604 23140 13317 49699 46055 43290 49813 50748 1805 62882 55639 8623 46499 8813 57689 45858 17775 25916 61554 55364 56232 1377 29885 15952 47236 52132 54607 4144 54196 25750 61658 39862 21806 23390 4738 19500 60145 20736 55580 8484 26926 38598 20516 15767 21050 11026 17435 35036 47546 60449 53158 16768 6697 17765 16319 8919 57392 59297 21359 55252 20235 2480 55061 15481 61177 46690 28666 61232 35461 63627 62811 57608 16647 53640 29780 40900 29104 11329 46307 24171 5758 23748 25091 24161 50951 50455 19458 11334 6764 5807 49757 52738 30201 29220 52735 4037 49062 17561 43854 41695 62815 13075 6969 44331 18066 36854 53230 28162 40965 55509 29810 28601 40776 10051 27686 13077 30227 10406 24575 3340 47778 37621 61604 25606 51409 50734 13911 1277 12642 34157 29609 31444 34652 42109 37182 62901 13611 29088 9541 27971 54591 62486 14724 26335 35290 24406 27191 16450 38266 60933 36481 62346 14610 56926 41093 50264 1628 26098 35859 63494 62357 61680 63654 22490 2061 7946 21908 14844 36521 15522 7702 46343 16558 60265 53219 26936 51701 49909 9261 13482 7949 31666 27507 18004 57039 38074 12429 1159 3485 36587 107 53699 16503 6490 970 36588 63958 934 46166 48806 53008 36219 28191 39259 44628 9916 25298 33863 62058 52647 39 29636 2738 38322 7233 61806 52683 43847 38080 50141 42189 43506 63508 56283 50626 64284 20551 7214 53571 4526 43338 38711 19142 59521 3254 27490 62769 34044 6103 45112 33261 48289 21621 64281 43972 59551 41540 58010 15510 53808 11467 12604 21321 61311 40314 59107 50878 27870 52253 53868 52534 59126 32856 35953 33522 4863 12932 13401 3378 62252 11994 5688 14755 34503 15602 59344 43562 9915 48290 40366 17736 46806 44383 15048 49659 45075 57219 31346 27617 52067 49246 41559 48154 60616 17522 17861 5155 8289 38624 21957 3438 7887 44123 25858 17369 56474 46340 20582 20437 15716 51965 13091 20252 11054 58985 9761 33614 7103 2612 1824 59383 16798 48659 36141 30157 23289 51150 48129 2308 57109 31104 5650 27358 24815 17214 59885 55212 39174 27653 46333 19028 34467 10143 60037 18163 43324 20340 20205 58061 4032 14847 4825 18444 44366 51916 35637 35187 60739 43219 8526 4584 47441 6716 44735 12536 60743 22267 58746 10516 21332 41769 24522 26432 11320 47841 30713 23466 48644 36883 45684 42298 35077 50071 22776 6967 14242 39809 32912 45179 23076 14058 63521 57840 19007 63028 52451 58020 17600 51965 52705 36623 19505 62736 55512 30540 56495 28986 31492 23784 47542 15910 1840 56939 4968 11178 39606 25288 45607 22160 11334 64254 44641 43018 51639 61675 906 2613 57541 54804 50937 45550 6712 7969 35145 60730 6395 921 1317 37739 10435 927 6855 63662 4955 35628 34324 47036 19152 9228 14090 20878 61097 4792 39606 3397 33328 48803 52140 62313 58263 56092 6024 21 1076 36183 51468 11345 13161 20820 15866 25070 62314 60833 12895 62359 36164 27040 44815 11231 18220 60960 52232 16261 52869 15153 45760 5173 49777 51472 10564 7030 11523 25911 46079 55657 14008 21418 19973 2128 58707 6636 58115 20791 56320 8800 8576 26593 31151 29780 30300 28003 42506 4448 61193 28440 18814 57324 2639 35581 53301 2815 57825 60375 56464 41725 41132 48290 48891 57329 13572 55854 57366 38088 55656 24658 27913 12592 15640 15374 33551 39670 63327 42176 2233 59837 62079 39731 36427 1285 33217 39134 34630 4304 4089 60128 34919 2701 7342 22159 21628 22524 40610 20085 63411 58204 40852 43663 13769 48104 10243 25043 3315669341 3474648308 +1024 18746 44450 4780 47990 5694 59455 35327 44632 58685 57592 2740 15093 48213 59417 60908 49533 19949 38667 5532 58483 56073 25564 9719 22836 48599 3713 61252 34521 43536 52230 60010 59461 16238 62913 4072 28558 42516 11971 50676 43859 26896 7361 45996 19844 49481 1825 13378 57147 40821 55707 58553 57981 8223 16058 1156 28629 59430 12793 8405 47940 8020 49681 14439 23480 795 45356 53002 35367 22053 3670 5447 19746 60772 43617 55051 53885 54029 23043 38945 11680 5084 35808 7169 33676 49315 28668 16308 25757 34462 7334 63187 60727 8014 33951 38036 2785 16247 4185 28996 6473 8350 1150 40834 2829 5803 8032 20394 36705 26363 62640 6250 44590 7721 16107 14358 35970 63465 6097 31398 52676 62807 26096 25312 13643 30596 35182 29981 49047 52864 41318 57835 50451 11919 13118 56543 45826 48930 40467 37325 42335 24384 35717 55585 52258 15266 30770 33662 16482 13687 30146 21369 1626 56519 14252 57048 25695 15187 5980 7483 48182 8051 44809 47259 13511 10522 5086 31380 14954 1384 40590 43973 1141 55534 1492 3816 58265 32848 11821 34490 56734 53379 60843 33300 37493 18662 56797 23537 58572 7802 11359 38212 59716 59312 18568 7175 39613 1796 4082 59122 25613 38128 58227 47998 52514 46500 28253 10309 57035 20311 2031 63550 176 55684 7660 882 16508 48193 957 16776 22283 57759 44184 3581 18915 37246 43747 48999 42569 15448 46025 20450 15613 43918 26975 27659 23937 59318 62961 41485 1325 43225 16412 5958 51392 47999 11417 15840 46268 27733 62853 40155 9099 5608 51969 6739 59496 28221 39268 43134 4520 24876 44942 56513 51724 15539 36845 2831 6171 10506 14242 12503 6013 40846 33414 19385 2599 35982 48932 18685 58857 13318 13621 22251 33000 61183 52653 8792 8590 54880 18279 13892 62517 21351 48151 56304 60076 12071 37702 39706 17226 7929 23954 49150 47794 43341 624 5315 19050 62272 53544 1378 42279 44643 16858 5110 44149 37863 22197 29933 57165 60531 45977 15660 36626 9063 8618 46820 9975 23831 39933 24818 59044 43507 51850 2692 59978 19168 45565 44315 28077 20649 5498 14705 16101 44225 12849 52123 59541 44774 42431 3439 42081 3493 51792 36217 48079 49765 43916 469 16049 22900 44423 25268 11379 23767 4828 9629 22021 53746 52525 47668 18998 17439 9014 25748 6099 22648 24286 7694 52804 27689 13009 53973 31073 28303 3354 34311 12094 44711 62745 33786 12430 5403 57738 58169 34971 13840 33061 8901 11581 1254 6474 33161 34546 61382 15070 7079 17202 10166 54387 19701 4018 44821 41033 56887 62725 47395 38971 40062 33873 59435 52812 5117 37579 39622 26252 33985 42641 40544 55236 559 1283 58019 57534 20575 19122 37548 60810 41486 18681 17955 45302 9374 14969 59504 28587 25549 21961 55541 47208 46374 27044 53781 56621 34072 46200 29346 58005 64262 24355 16692 28988 43222 48396 1571 56147 5089 12224 40375 20095 34459 35277 63716 48486 44749 1390 726 44777 23470 59877 58131 42517 26842 31102 6738 56573 8711 18191 49261 14507 17645 10190 23926 47736 37369 27989 39342 40801 51410 37539 13537 16983 12107 11143 2659 26031 27639 40930 7333 30116 21596 36294 53115 8314 46099 28726 50054 21844 34905 62279 60532 2627 20144 64167 55078 63948 2637 49560 2365 53832 10880 39560 52237 23335 42634 39301 33499 46238 49803 54675 12573 46695 15256 46470 54897 57197 48280 19367 45184 21772 20699 62068 49512 41919 8356 7068 33552 22561 18729 11787 25206 38617 62710 21136 17044 37130 22642 6820 38973 34293 15234 20283 14134 50997 3200 64204 12695 17465 21995 22944 6895 59888 19814 60943 58131 1497 61192 3170 38775 57772 24275 61274 1120 35184 39067 62856 43346 34065 43463 7320 33904 10717 60996 16927 54487 45824 26984 28643 55021 11724 54616 36881 40882 23711 43628 20258 11708 27014 43841 21068 57545 30738 6597 24646 49701 41501 20582 60049 13606 30576 12256 2726 20519 4071 61587 10818 41099 25236 10858 58444 63709 64055 58373 55053 1189 10804 4965 35638 25191 38087 28622 2782 281 16023 43182 44582 47009 44990 4046 53856 43743 19957 35925 64291 28775 10306 18042 46938 36898 55560 3715 62677 42679 12989 21733 33220 30258 29843 54053 53131 44805 22839 59532 3760 30189 16685 45918 2151 64375 8256 39630 9266 36584 3972 50644 26537 60434 24600 6282 26758 22823 879 9736 62384 11405 63447 3833 46002 4508 30324 17900 36525 15491 25329 7793 30752 31273 59844 42053 63456 43385 62530 6607 29905 39895 14514 42430 30132 27004 48777 34103 36704 60243 57948 51426 61210 8593 2453 46659 44807 1994 17938 21244 28936 13596 30303 30075 43446 23985 2372 35520 40151 24993 29096 18947 46306 9410 5567 3608 44332 45722 38358 9791 40171 24141 13356 6796 36641 4571 55151 39204 61587 2829 42596 3092 56583 46665 63566 20163 41948 58828 51598 55206 11519 42150 40614 8586 24003 51505 33504 40003 23090 50351 1144 13936 7579 1613 10714 36458 40687 42884 24757 36021 42609 28401 23590 2803 5681 57297 58299 53712 56284 15244 3888 20934 24898 18833 40662 56548 24539 60534 55455 22187 55304 50450 27103 39385 21508 13811 3576 10394 50987 44295 33584 40353 26157 41073 41377 59367 51826 37887 61154 14757 61552 63488 62429 38854 51232 10470 48612 1831 45773 57139 60406 27920 11745 52361 58928 30789 64090 63299 3602 3910 63896 41354 12964 10555 45861 45199 57257 50592 64261 14977 2395 54004 27525 1700 4945 1456 52663 10055 51804 30461 7582 28254 7794 1423 62391 57611 6273 21130 64499 20064 33498 28041 60671 6790 46921 46511 3986 51913 58703 37832 58485 36258 58863 61264 16358 10799 26863 24135 58953 23487 22851 46197 10429 62369 45578 51475 43771 9597 17184 33 11325 46625 33968 58410 23090 54494 4775 36412 55064 26532 5448 36874 9776 63531 55927 38579 37425 60809 15260 13886 43643 52638 50757 56763 43257 48446 5329 18371 26110 52969 30948 15513 11805 845 28121 15305 36463 35745 7727 34568 4766 38570 23340 17481 35185 45299 50517 42229 7122 60471 3055 48610 47021 55876 40536 17122 30354 37834 42828 11048 27264 33377 48347 35709 20535 54321 58411 48403 11997 41953 55292 24008 58148 53555 8797 36725 21166 36180 15573 35204 27290 12346 35763 29556 4429 31339 60583 46135 23946 25349 307 61040 10192 43087 18498 52123 42065 60336 33239 25675 46867 52697 15897 47534 3811 33499 29809 60941 47982 16788 44530 54061 22717 21094 9501 27550 14926 7113 18855 47291 45908 41129 32880 3365 56925 45010 33627 49917 41567 48073 23687 26365 11541 153 47256 18837 38553 31544 51997 21480 36218 38278 63374 1712 27584 3658 26634 62319 59216 657 63058 44214 27103 41763 2120 22518 49829 38817 33772 43739 61229 33877 52866 32997 47417 42385 58302 51901 61182 6210 6387 41139 14426 1633 57585 25118 8179 6983 34443 2797 61606 62452 52895 2675 61043 35764 47277 37437 47990 21817 63540 2182 57929 26541 45668 5455 9098 31379 35877 10570 6160 63293 59104 39085 62440 53035 38873 44445 1159 25311 39778 61596 58559 25333 23349 19575 18686 533 19387 64342 45533 8224 24677 23094 41170 14287 30298 34508 16746 28908 60756 555 63857 49128 31080 12987 59718 52817 29510 48277 43275 15406 29930 44508 64127 60887 50320 55912 3343 46858 33428 47191 27826 44676 21901 28534 55464 60135 23412 56486 58343 36330 36809 5178 55658 55853 14300 62144 4190 64204 17889 10937 10762 24149 40467 25227 17180 61440 18393 59769 58483 28589 48843 54439 15812 43124 54934 42932 6949 6744 60967 57511 1053 16610 21395 58598 61612 14387 9361 27476 7315 58073 4559 54187 24402 46123 21908 25357 19952 13148 32875 55156 56696 63718 52444 38971 2184 18387 49387 57750 41983 55479 57052 19158 16532 56549 43432 58896 21505 11392 19658 27296 3631 58849 23642 40214 28066 28986 3100 60596 39923 13324 24864 17552 5036 39071 60519 58301 41122 52224 40397 29104 14770 26179 54997 11950 61366 31439 574 60547 42343 10879 2101 37183 2791 5372 11172 9106 52130 35105 2083 44515 54924 5195 13312 42107 2159 36290 64113 4417 18402 766 36789 63978 19700 762 59526 14529 8467 48819 55170 16066 21047 5562 46051 48155 56561 39350 13991 9218 35020 35997 35371 53922 37078 7064 6051 19261 2445 7721 58539 25848 6228 32894 61366 152 50274 61964 10865 26726 13541 39981 64150 28154 2076 45468 18350 23718 39232 3779 2911 46572 12160 20898 24374 10277 55305 35833 33388 17249 6350 23509 46080 62462 15727 31267 27805 37894 25993 20567 47038 20066 12662 31620 35840 52151 39685 32910 8234 55976 43048 27232 53288 12184 22984 8449 36534 43443 39096 60858 25904 17849 27166 3297 54482 41942 2264 59708 58650 48596 63356 4267 60202 34900 35962 57720 35973 41791 52105 12963 42867 44888 20121 44841 38080 43108 10618 23721 42591 14024 34409 19293 9146 54215 1182 29401 25869 45129 62561 16425 58778 43268 13077 32846 54240 18348 16223 1262 34898 26702 17329 47504 39340 22678 35236 9860 39414 62076 43150 51361 50941 55575 51425 47790 54625 28126 62041 17428 57608 50623 37532 54302 15365 13330 13690 40035 62147 38471 38036 8388 28811 34095 11321 4612 53531 51216 62036 27068 25988 3919 8677 8748 57746 20304 19176 43671 5117 32788 51042 25375 28406 56714 7895 60134 26949 52501 45457 19473 4323 48609 30946 18175 48871 8522 48991 55209 44381 20677 23702 33349 4947 3896 47945 23021 15817 38270 21840 25261 45196 60563 55427 43634 44780 32883 40695 42615 38492 59095 41941 21253 34339 25906 22510 57442 38143 43223 12713 22773 50246 55561 63138 17564 53041 28744 5164 13639 19827 28767 23173 10393 17079 23689 48822 7240 4661 4985 26186 49414 30675 5350 38682 56404 41617 54947 38508 49151 48991 53502 2784 26478 45176 39766 39691 33711 16833 50246 63478 31265 40805 26376 46497 62827 43610 49327 48596 55638 25391 35663 37342 8156 8592 7681 2377 40447 36380 5080 39885 58423 13896 62739 7665 44964 48131 24806 27403 51887 29280 27837 1256 49065 18805 59119 17123 9848 5783 2156 4232 43875 52490 48456 46101 50531 41970 28294 50144 55372 5936 13054 6622 29684 37325 17418 46252 25181 14 45014 11507 56003 17588 16745 62907 48849 58776 35373 29394 47328 26813 43669 28248 18069 34846 54522 49033 54741 8929 63093 44744 63544 15735 46831 41289 61003 23029 5204 21752 29435 4121 63029 49980 4395 13869 33635 57545 17067 33428 18275 62979 36298 38051 61298 47348 5801 61165 18084 31478 15511 42739 12529 55580 44284 44361 59487 26135 26469 63163 6495 58237 16962 20759 52406 18177 11144 46343 16868 1431 59334 11442 44309 30971 13433 46851 18593 27140 5236 64382 47167 47470 4775 29758 16887 53833 22456 50227 64026 41272 4462 16641 15378 46015 24620 56630 48907 53305 12706 38286 28540 38752 58681 35925 7767 37033 59920 27416 10003 43498 44999 45538 27010 22616 6841 39199 7651 11375 7015 43510 60156 58924 39336 3222 55072 10996 8833 5146 11015 63830 41827 34721 19616 39310 10494 59706 50689 56322 44133 40097 64154 1401 27866 49284 41049 42262 4414 23982 42089 27446 11608 62975 14840 22232 48483 5839 40700 60010 50800 30569 5500 40685 61576 63020 5876 36926 52673 1104 19700 60723 5972 38888 53997 1326 44673 58937 62247 59745 61328 49988 57022 51986 34781 51900 13435 33041 1919 17435 52518 15190 20236 35956 5987 56214 39856 27820 55764 46843 35494 35812 46741 54185 23813 27763 11852 53023 51010 28727 36271 53113 6656 15090 45104 36573 26427 18081 23910 6766 52903 10392 34292 11388 7798 51130 61848 49958 43927 15013 9393 40059 45808 12641 11380 27650 33178 30040 52902 52161 57645 58683 31555 23934 916 10826 37569 38868 13744 30700 54821 52591 38640 16072 31136 22296 64025 46935 15868 25785 27373 40082 60343 61361 31508 58937 50652 13404 45109 43627 37550 6419 54701 29799 32940 59148 43720 8026 62109 60951 27527 13364 38141 60378 61562 54692 9131 37217 9113 15183 36012 25583 57386 38879 28044 15488 3107 64001 55949 61571 21697 44055 35660 17174 27010 51919 38481 29143 61302 32807 54355 20848 19898 51179 5887 26936 51601 53755 59166 671 31663 63079 43973 2449 21778 37548 9532 4370 4610 60875 58996 33089 46714 36159 43579 36476 13609 22418 43388 48542 40711 48729 30301 37990 5865 42589 63117 10025 53626 62512 5653 47591 62988 19493 1917 5366 63781 13152 20478 24241 58013 36233 61814 44746 55030 12305 11103 5063 49422 63300 4064 49296 16579 19331 15545 58964 7989 5416 21100 47342 45994 19649 46171 51233 20948 26755 27799 24366 37536 51729 36293 49835 51674 9788 11776 64048 10703 25572 62112 9395 2478 1101 42002 63027 59804 59311 24250 21120 1632 48769 39360 6691 0 3483804812 +1024 7945 11893 15905 37758 39893 6450 2565 53458 63451 24501 41855 49313 13492 50595 49002 21609 61731 18241 21464 13567 34928 12202 28198 1795 5502 10711 38474 11210 33604 12997 8855 49889 24285 52345 7715 3928 58287 53482 20830 43682 13920 8976 3538 10314 48885 7549 52106 6133 10625 4887 61227 22567 29341 43372 11207 50339 4665 31679 23582 59788 51646 23471 11950 33460 40378 9988 39658 8214 43235 64401 31697 57093 25868 60893 35120 34591 40026 21444 5591 61241 13882 43762 8312 60579 50004 14867 6419 3760 63261 39392 27093 28370 9751 50674 53193 20742 6364 60713 26318 20505 57926 26339 54282 31223 43855 20115 35516 18169 64051 59438 63698 20008 37989 55599 35867 3974 23414 17234 38537 30047 43172 28122 13548 49465 36091 56328 59677 19573 58717 58409 61194 33373 43538 55274 33714 54914 34227 16291 16403 20680 48259 15853 17771 9436 61388 49478 20230 16902 45235 57544 60781 825 18937 564 39913 45006 30620 54400 49643 64283 37470 59947 36325 51390 5454 14585 36166 796 50818 307 28359 7877 63260 52057 14471 12161 15904 42375 29264 19754 2778 38787 6581 11338 43222 62972 52799 38839 2673 32845 48864 22418 2967 21931 6835 51647 15054 27051 1170 45542 8914 100 26532 58737 19759 19483 55799 8354 13681 10619 33505 5593 47197 49318 18145 8235 17978 19726 21858 62394 49196 30125 5842 12689 33328 39785 48032 5148 25610 63815 15770 19738 14267 50638 47966 49906 51503 60902 8444 52575 35478 57998 28846 43400 35793 56404 44587 10207 3192 10093 11161 46293 47254 3397 34400 58708 36126 63228 29998 4542 41504 24621 17428 9528 5220 13195 43045 55893 59926 12167 48656 4420 41133 8347 47254 58517 17088 24484 49599 59876 59667 42977 40421 62201 19393 33285 25130 54986 64303 41125 55933 52594 61516 56860 11228 16654 16552 41134 60185 27322 38409 12180 26502 1974 40953 44939 57790 11073 53625 17658 39275 58716 32824 3970 27906 7363 5607 61224 62580 7688 8980 3542 60882 19861 23348 25428 21081 20216 59173 37724 38644 48473 29700 4672 27571 24886 29339 33533 32868 14414 56633 52630 46235 43149 19158 8192 63608 35886 46257 57151 2987 20361 59879 63681 22716 36316 3472 63331 3536 56332 58361 39341 49768 3782 3281 61493 26989 56749 18681 48617 40804 47596 10317 31293 9582 24688 56484 24635 62573 55969 12049 41580 16894 30070 63346 42372 42822 51761 56581 37022 52331 20892 26536 9949 30106 46582 4812 29366 59996 9674 61465 48194 38791 16277 18066 57366 2882 39724 27983 10057 57035 50845 43812 28416 41224 43559 8140 57634 43111 26210 27908 1975 25440 46841 31627 23791 27175 54311 62938 58094 9189 39140 33223 33275 60805 56262 63291 23608 43838 63197 44943 28114 30537 38463 5256 11333 63113 45625 30061 40267 30367 20313 33788 20462 43814 55908 17212 31469 39479 17322 4984 16503 3476 51566 46927 15990 27105 59093 30419 12077 9330 35405 43140 57729 37727 48908 26720 53915 18032 44589 29148 35471 46500 56965 42816 206 35719 6562 50462 27264 11476 29557 7010 26069 16453 1626 62417 51469 2304 46081 47143 59691 43301 26496 46340 39764 15573 42387 59663 53073 3838 45157 45169 33516 55250 37357 41240 38585 14328 33077 7517 8990 18400 23714 50952 19695 9812 46697 61991 9760 60809 53866 28108 35099 40850 36710 9608 50455 3693 59724 22275 49380 19536 34767 5541 37234 50096 38584 40556 6430 2559 28986 22499 5297 43173 52044 26204 52974 41003 3233 26095 50583 50144 17780 35718 13432 56226 17406 42242 29194 57948 26146 2507 572 57019 19100 22369 39263 52671 60082 7053 58008 50155 61949 34061 6722 20599 62386 37160 1111 23699 60532 45370 43917 59418 59338 1592 14314 3170 1558 3131 19710 21628 52387 56308 22086 54061 35639 27923 9740 39449 57111 63574 36216 29781 18103 35438 34662 17177 1790 49602 52940 23343 42966 46412 59897 63794 15674 25526 24480 1160 38637 508 5661 25598 8288 26498 46024 35010 27772 288 33633 45126 27610 45683 2922 8507 40846 60609 13990 23282 24435 44068 32882 47605 39721 52114 34660 5077 40584 46218 27609 20883 7712 7756 58012 51496 8653 16297 43691 1371 52651 62575 58687 23252 53271 15105 12619 37894 56090 12123 58107 57734 7657 14791 15019 5906 2705 10818 14781 60789 23165 7474 16488 24604 41552 13161 53604 9983 53404 26412 5141 39767 3999 57627 60193 3052 59879 9068 41741 20563 16175 54787 23888 5193 50304 8433 36180 57815 24361 2575 29517 8684 1855 57916 15228 45852 603 37377 11210 17452 58604 52155 27826 2352 52024 44761 56091 16207 9620 11763 41567 17168 53974 41795 39952 56769 53599 46097 26601 25605 7576 148 53086 50863 56782 52132 52393 43300 47979 5965 36895 23778 12807 61286 48507 9613 8497 46131 61952 17905 12063 50377 61122 10703 42635 27142 61040 28321 12701 30353 18264 59557 1980 12025 215 6307 47964 24370 8152 37207 5211 2894 17400 21215 9810 55990 19993 62046 52082 55931 40703 1029 24065 63693 15596 47274 5979 1609 51859 40362 18166 61274 38835 59251 194 38512 50983 10464 63450 3442 39089 22518 22116 26464 62957 46626 30432 34219 915 2854 26358 17910 29713 2582 20239 52618 4085 196 1674 54124 40996 60000 7337 34906 6145 28031 26773 20505 4045 28998 44179 6239 7199 34464 39659 32948 39114 967 3276 37758 14246 41234 9205 32853 42589 64152 42946 43377 9975 4118 4028 4031 47855 19899 12830 58344 11868 51150 30706 6872 48197 26858 58313 14163 8740 54675 43496 45089 63406 22623 42493 30186 3485 15162 27535 43454 50060 23215 40906 59336 28169 2671 5795 13093 18357 5700 11407 29724 37560 19331 44279 61660 24519 64213 22382 61690 61992 2881 30235 48006 3415 17916 21731 46854 10649 16269 16585 43043 42355 59123 58170 44265 34203 40240 49329 27891 33182 26029 23132 53859 50587 16858 1361 59450 10305 53495 8268 28389 29876 35226 52435 34916 11844 31549 36247 36326 34203 57203 30439 3400 47146 24110 33273 13069 21528 38541 52304 5840 46868 59595 8953 13885 26068 61085 31449 8876 36235 20221 8600 2086 15715 51616 354 46959 28313 48554 8065 38368 22300 45714 59352 25616 3950 14444 30302 2236 60999 29686 14668 11955 56496 60208 16602 36609 17959 25660 24619 53128 2382 52269 17621 22636 50063 6965 33188 52201 54206 62120 25530 36905 49463 48610 62249 28279 928 61338 48711 49660 30746 4363 20193 42150 56193 48955 27398 51361 56100 50244 5829 29643 28595 53868 45175 19557 6976 2450 39856 42001 16096 12711 20035 28890 60795 21259 45075 39914 11804 3650 20017 53577 49604 27939 20810 14530 16666 60352 33015 41054 46164 52732 34475 37884 29257 34893 8929 24552 56360 21811 17790 6635 4743 53902 26250 25959 16387 44849 59089 56417 38931 10360 19030 45100 58201 11892 58189 21409 8194 491 43984 37932 6551 2671 33020 42149 51347 27322 60302 3352 17446 30428 52286 43565 22271 6494 31135 1539 7567 62845 36038 54964 56920 9234 25969 26113 7440 5182 9921 35405 11981 48890 39193 54851 29433 6271 50504 5859 63568 4593 45940 33271 57165 55518 46656 61937 35257 3269 21673 16867 24203 24812 53976 16453 19106 55465 51249 27861 57769 47957 52509 34190 18240 5794 11419 1613 19075 8738 49684 49685 34207 40153 27240 36803 42283 24157 13079 61529 49060 33278 49079 10590 2771 2427 27338 45355 53246 3009 42166 34962 3959 60892 60721 47814 55472 28389 4734 29541 31545 57599 46937 7612 34425 25223 47060 33098 16784 30123 38121 49559 20450 57901 9471 54949 32942 55216 35466 27995 29529 48627 45454 56794 51961 36713 3179 11858 50302 12632 46523 27159 60961 7928 39333 29822 6549 54261 233 63524 54783 6488 13166 8636 14968 569 16981 51208 61029 50679 2698 28625 52328 29381 11766 50095 7325 60361 25581 49358 20813 1168 14579 59349 2236 13023 37840 57073 53742 26982 25917 35709 9056 29043 10336 53350 28561 14375 38350 43660 8983 12764 41880 25396 15494 9570 45996 1498 11629 15813 53891 51687 8867 52913 3913 8161 16448 64447 31459 32826 56386 41608 224 43075 59539 3215 18077 39403 37067 13727 37539 58044 35473 8523 43390 31412 48532 57479 61097 64271 62441 63002 26974 24923 37674 56565 8295 3548 23107 13405 32778 1693 46363 38167 16831 62907 2251 26974 62584 28358 43736 8129 11438 18316 12725 45912 27402 11195 4473 17183 52976 4225 55342 26742 52213 39667 59379 7007 15682 60374 36773 49303 40909 9564 32855 58762 35141 38766 60655 34936 44667 52848 53964 28922 63441 10455 18187 18710 55268 6771 21463 47980 30638 57125 44091 24251 53550 35474 23093 16604 22953 62990 48599 13338 57266 35042 54527 11718 7183 59308 12106 20628 62703 4591 64377 30129 30524 25635 27178 56845 31319 57630 36349 49433 44761 45140 59279 2593 17163 7937 54110 12616 53172 62076 31327 27100 25408 6280 57931 43253 37589 54702 22210 16599 39980 47399 37500 38317 38997 20453 5235 55564 19361 18414 25195 60679 9757 11275 25460 23585 4928 52248 48612 49126 16202 21351 3882 15264 39267 26904 19444 7700 7331 17624 23223 25085 41455 38236 53485 45206 28301 3532 57375 29047 47556 13286 55329 63097 18107 20225 50712 23789 51682 43654 18095 54658 55667 16893 21845 39092 21432 27423 52385 34685 38133 63954 41115 12709 10054 38623 20791 39870 21127 10594 12855 46842 51284 34334 19447 24305 8741 9207 19365 62798 19623 35498 18509 27631 60436 52728 12485 37749 43917 23994 3402 29039 59202 62719 4340 33878 53306 22232 43175 37669 55359 11331 60311 63686 38245 42046 60179 29922 50028 21536 18654 7343 45340 8990 5852 42244 24185 16455 35157 26106 62266 3641 49345 17491 1054 5590 4717 36626 52246 38123 24327 25113 15793 35556 5139 39227 43822 3892 6984 801 29232 18516 46003 52894 20805 29446 43334 13389 60903 42990 11329 31260 6938 54478 2608 5101 37266 742 31484 35998 39890 30103 18766 16446 24279 30458 7744 55152 63684 63635 51594 61147 9991 15286 63279 27657 40996 4620 25458 45993 49088 53906 35823 49225 40928 56301 7971 47945 20604 18593 611 62588 20362 17170 11939 771 897 35845 369 47972 34377 33753 43171 10024 46485 13533 50365 9376 129 6566 61463 58700 4179 10408 45286 57934 54784 19694 21014 18308 56291 40691 50899 59514 2941 50796 1244 12461 62970 29377 2897 61125 19819 42783 55729 3182 12540 37394 35523 13137 45837 20324 46750 50389 38023 850 62530 45679 6911 47893 37896 53548 41205 52832 63795 42599 8363 5039 49437 64296 7382 16775 26781 13836 6625 18003 13972 49073 13546 29443 31356 51422 50901 49155 55279 57646 27445 50606 33488 17966 13939 37714 13426 6319 31532 7314 30281 51533 63221 4005 7617 18358 3767 43391 3003 19180 4195 40104 3623 20427 56809 22565 53202 22825 52080 25591 52488 45512 43086 36983 20288 45121 4332 46169 29415 38527 24624 52760 20395 31252 62833 16828 43351 56620 39048 50254 43536 1785 58326 56682 7502 44249 56258 61617 54546 46645 57931 55986 34990 4736 14730 27683 26807 57524 4145 55596 43119 51019 50224 31493 16689 6740 9957 24394 39296 4814 4514 24107 61965 61085 483 52320 3242 17986 52125 59427 59964 19511 34178 7427 57406 26450 8696 19897 20048 12185 58191 20664 26112 27193 38543 31278 31241 50012 28561 62823 29110 31489 22748 50377 28332 32930 38831 22977 13689 50242 25456 5507 17829 2516 16189 28972 5596 30230 39155 23508 57421 54111 29515 26023 16223 64013 5581 63614 41242 16735 53308 45447 43547 38529 39294 50546 580 10815 1460 27472 31394 33751 9744 4036 34871 45272 52349 47111 58244 35778 16803 1671 50629 34641 13684 22485 30384 25951 13001 3341 58903 44767 14621 43278 55776 47544 26711 51934 53211 40478 24656 53194 19787 12935 23504 40660 7557 57177 14248 59434 33231 15826 42043 51057 12424 37401 44027 4327 19841 33484 25686 54289 16160 13749 27256 6116 42444 40137 26482 14549 52666 8735 28171 28357 1993 49617 25128 26687 44464 58215 50499 31 56378 44140 61788 61363 64417 13954 31090 4468 36056 26210 28897 37445 43838 18085 44941 19484 60834 57671 5934 50749 33094 53325 17619 11559 16087 54645 48872 37203 55247 10252 60407 60133 25840 61644 30846 57544 20046 18727 33716 22033 54502 45223 33747 30004 26393 58167 34519 14652 10288 50502 26219 63451 54082 61379 59011 30864 13552 34853 9019 42581 2465 2602 56504 22443 38768 2053 14925 9562 47727 2667 7563 35149 22218 53804 25887 28627 2003 29906 21629 888 44181 60551 4562 37097 43619 60764 2014 5502 10895 21445 15926 28739 807 14615 53666 47370 1776 41458 5768 22264 45066 34027 57686 42701 39254 34198 45149 8583 118 50288 3811 5081 23717 45918 26592 18538 51377 46420 22937 0 3478709707 +1024 11606 39165 58233 36484 57617 28880 7379 31078 19419 41976 44200 25938 1042 22967 7295 41542 19503 50017 25444 38039 21301 55972 18125 42369 63686 22055 44697 8531 57019 42609 37129 3184 48983 33963 62339 25385 57526 20046 6541 30783 56354 53644 57684 19065 3546 14482 37968 19440 17911 31427 31392 23380 33731 43628 5672 51281 11373 34577 10961 40845 9886 49764 27713 34279 8003 46321 57270 34620 19621 1467 52815 29647 47717 50306 29540 3112 57760 10620 21292 1185 30281 61038 19024 12940 53158 16201 40812 25735 58293 29255 59875 9775 64409 53741 63017 12654 62442 59635 24112 37882 2128 47371 59984 37364 24313 9697 7862 6852 63081 3221 25991 55553 1338 21957 14180 46861 51889 1810 35411 14635 49766 44060 40630 36063 56752 21130 46643 32786 6182 454 23554 7529 48904 41696 34950 58792 61542 2636 22020 26746 36289 45149 52729 224 20588 22114 61628 44119 11121 5461 25121 38375 28811 5264 6793 61835 29993 55163 34130 52794 53614 49771 4606 14660 25932 53280 59039 52979 19711 54333 13430 60689 43137 44395 44416 50080 58049 20210 33225 39515 24769 41755 6861 23077 7498 23535 60483 6704 54147 25769 14695 55198 12432 322 27704 2197 53050 30879 49987 55820 49578 39757 14837 28933 47841 50643 58516 4019 21139 60395 4340 30505 55697 13777 44852 27899 17115 48020 463 57577 51491 6782 1940 12513 53980 31224 62966 41242 61452 39652 1216 34451 38149 55918 37412 9165 16150 55377 26988 6566 37744 23127 1966 42317 6141 26022 16933 18780 12436 18493 50555 40402 54100 44823 44701 3830 56725 5488 18052 17823 16308 36874 17325 56074 33331 7122 35767 48976 5751 34131 42407 37385 48782 48483 33208 27326 46229 33059 49801 14804 4956 52644 8657 35653 7423 42279 61426 20720 26454 2703 22047 45096 44093 30819 54813 34817 11196 27249 18517 41272 62153 11747 50233 7142 59600 12367 59075 54748 10954 34861 61976 43523 30274 50009 22265 4280 8018 52696 24921 43674 62821 1485 53601 8521 18085 13605 10906 3696 37267 39099 28154 42414 29126 26307 7797 14989 12333 33278 30185 31169 42983 2173 10929 51395 47731 18635 34487 28851 6437 30380 19724 27276 39492 16109 40449 49242 63076 37887 45596 25015 1929 42790 3224 24062 9088 22259 17337 62956 31105 7841 40968 27171 54502 1712 33598 54306 22380 15664 62736 37377 41189 15791 5442 1063 1169 50020 144 62866 473 30451 43674 62616 57764 22144 9230 14703 52891 28497 56439 29715 54068 34972 14429 25520 1669 51656 19905 55316 23157 1923 18497 27697 17508 27395 36657 60957 40767 50084 9752 47075 44906 54224 41888 60313 38764 62088 29348 12331 2737 56548 1748 24632 12996 59611 13890 45660 7457 30238 40860 15773 2000 6357 59481 25814 64128 45116 40460 6067 28970 1540 3037 23086 13899 38737 18228 25117 53221 21901 59808 55957 43730 18155 63388 58182 29757 61034 45969 44931 18873 37644 59363 18260 11805 41696 29415 54788 59991 46047 956 1424 54624 39845 25738 40041 14130 17869 25922 19914 30331 38397 17885 63886 46317 57845 31477 6109 16071 61025 42436 13718 21049 22068 53949 848 36636 34884 50996 44849 42738 33874 48992 23825 6676 38202 51657 16033 12364 37334 25210 41420 9423 42500 44712 43998 46370 33166 26910 33004 26152 26465 243 3302 7633 38062 21703 5295 7845 43270 37390 36376 15819 58444 52156 28214 17226 23078 52133 30533 33956 29877 9810 56231 37710 849 44827 35703 51514 28354 23104 25290 15102 57538 60071 25233 38657 11878 480 12477 1399 22645 4450 3510 31615 35604 40763 38795 36133 3812 9718 47127 4766 8259 54000 45442 17314 51149 23232 35383 4281 37568 44207 58610 27208 47505 47132 20893 35659 60365 41365 57764 4399 30005 26309 35337 63986 4278 16810 30027 2248 61538 41555 56474 46384 39375 45560 8429 51368 23086 48102 49924 53829 47898 54433 25631 18537 45639 2898 27673 14451 16623 42336 54166 42645 186 35641 60068 62067 29891 12783 50081 57395 63159 29200 28810 46268 29280 2145 20643 35667 3010 23096 52454 31525 9279 40321 49348 19816 389 16740 57332 735 62648 15627 41225 27986 26261 14221 44616 41552 27358 22730 44036 60137 12178 42398 7316 61703 36896 55882 54953 10469 30142 10536 58081 39676 3321 33536 56633 33644 12206 13656 45512 63915 5109 53171 21163 57055 1141 27461 63703 52701 26636 32860 22484 47731 12818 26718 51629 15574 6890 15023 31716 56442 46713 1353 24375 14911 3907 13279 58838 29744 39362 30592 25237 16910 28 25258 10169 58678 56797 52494 28641 23329 18403 48085 64334 42859 11788 44527 19975 26569 44560 38467 64374 27493 38042 57652 16624 34014 688 4313 8642 25813 26669 10289 18032 14877 42825 19482 22910 15479 58276 1812 27258 47942 43185 2834 12412 60658 28161 14917 44560 50052 63746 60551 13975 55061 26195 42181 25851 3587 44428 60507 63052 53750 41692 33611 38188 57727 10165 24209 12200 21321 37249 14481 63224 25451 25256 18759 7375 19307 3070 15090 45003 29175 58577 48111 21311 3288 37945 23506 52150 62587 17218 33881 33702 36044 8693 38553 61973 23684 18463 46945 45284 28232 20125 39530 5322 59895 50036 8772 19729 24778 35743 55344 28546 25822 64197 46033 22770 35494 60248 14134 14085 51484 43960 8828 50312 54225 55420 47356 45848 40889 59910 24271 56763 27738 43974 29488 25647 59852 9046 58687 12481 12124 29329 12706 159 52533 53790 24764 11650 36553 10173 37690 60069 54781 51734 55371 52049 4100 48481 33537 47190 24933 50482 29576 53855 10142 46861 47644 59440 41218 23824 20057 49945 4564 3641 57649 14138 41855 55018 54765 1292 34346 11765 63878 62724 46582 55890 18597 61119 25612 33469 38075 36052 54508 62454 632 12514 18936 63706 31658 39532 10538 10813 52292 49711 7350 2709 50306 38818 28261 7320 54009 47352 63802 46601 16960 19452 57855 32802 41870 28560 30511 3158 34777 7690 11975 59673 7282 6837 8473 18673 51514 44187 30448 52793 15362 10611 27069 22574 47387 58597 33186 60276 16229 11447 17713 36333 47478 34029 31190 40650 10899 36707 47469 63531 63893 52675 32936 16123 59477 26846 30138 26740 6475 45680 33618 63147 26751 7373 54829 8265 10695 62314 47487 57124 43476 24444 47033 38622 39549 21770 43896 11915 24432 39979 30401 54677 62961 27100 26424 20306 11993 43635 30359 25646 51749 42758 7399 14557 1811 17311 58835 20263 6976 23926 4941 54699 29086 56777 15674 24580 30477 62565 5831 38936 4855 31105 37979 43762 24114 57773 63308 39550 8729 60398 40015 41325 49623 59798 52703 60577 13551 27967 6744 50274 42617 19909 20799 28838 10380 49146 58296 51351 44487 53765 3536 21211 40386 55649 16527 27185 57031 27059 57869 60861 23666 27695 43693 51829 1096 28403 62811 56890 33427 2197 25638 21356 18937 62997 49312 14050 40720 50035 63085 52439 8020 39479 20414 41941 15218 28822 62417 59917 61534 18980 22208 9710 62218 16011 7883 26664 2819 40746 65 64046 2625 47917 8165 3705 25299 49892 19970 6744 35499 35868 49758 35166 4240 35630 15761 38735 16547 45865 716 18658 15096 822 8540 3262 39427 6027 52960 18992 51928 42328 49795 45164 1977 61363 16013 6330 142 55424 34589 35713 3934 25192 41370 10355 20080 52173 13595 45982 29852 25251 14279 6342 46476 52523 10112 20254 24414 54165 63829 7307 61254 9923 37494 59920 55164 60750 25868 48316 22125 45726 4416 33066 55724 47839 48631 47001 19246 2503 41983 19499 21581 21787 43986 37339 35165 13502 63411 19436 52525 49450 24610 10394 17063 51827 26483 31296 14980 26719 27720 40779 34726 64442 24901 15716 58269 12918 14462 26238 37197 29120 37208 12627 13550 30491 49558 51116 42090 45875 22977 7851 39242 54404 36842 50927 50405 28321 24279 60193 19863 35960 29454 23541 50846 31084 46193 4060 55234 19195 34069 16058 21486 21856 20646 42161 41629 31134 19052 33064 28725 62239 648 38206 14880 2802 2155 49589 24375 53217 38608 16302 7420 39293 13941 15705 48860 325 12921 45134 27123 49049 15612 5730 48423 43585 26449 6021 19736 35569 60879 55579 23898 36951 28008 26586 24422 34223 33231 23398 41789 41907 47033 60779 32793 18016 53778 1200 17072 26807 46324 8990 7564 16122 60908 52610 12238 54666 23326 30444 12077 49337 9313 64030 38229 56773 58256 26681 59682 26624 4258 44699 2483 49912 14267 59726 38660 4474 19052 63037 54655 58833 63915 17379 51477 49727 34722 42767 4384 10105 37844 64404 49671 26031 22228 29521 40503 57049 35153 30125 30172 39186 29409 11390 29117 4925 22785 33517 20801 4770 1022 5229 3885 23503 51330 23970 29284 60358 8703 38628 62464 12844 1644 23393 45777 3938 45555 23022 41136 62079 52492 43695 45355 34398 28861 3702 11822 54003 58762 38633 4018 9733 4824 36577 23906 50 44524 43333 56653 24431 3857 29870 46881 33594 15668 29017 34103 40454 19622 6387 59925 19869 43473 10403 35110 56237 10902 26951 37334 14378 25725 26298 7648 12167 13392 35702 4456 14418 33178 28646 56902 27067 38714 46124 4068 19618 9034 21801 38156 60946 18405 19634 27219 53370 19498 44327 26755 16099 17308 5812 30505 34831 18125 8800 36293 26949 15193 16832 23478 10619 7600 36123 16291 40076 13341 53068 20230 54040 658 46313 16086 20396 57256 57964 26232 35779 29218 45337 16388 14216 64087 44407 29943 20909 31729 29218 26153 35214 63137 54255 56683 2970 16175 39411 26215 33852 9378 37183 17714 30478 53598 794 24304 24301 16715 31565 21451 39972 17679 22853 18235 13218 13657 4956 7885 57000 21534 37427 20393 11393 11029 40708 28507 51143 21739 10366 50818 37742 29525 16633 58100 34642 5385 56652 6818 47312 50874 26527 43033 12341 47674 52456 18800 30072 33422 5464 63391 49985 25786 54710 55788 35258 19577 48478 6674 43362 20573 19507 37670 64032 20441 16664 47856 46935 30121 16871 45743 9924 25033 62194 35765 25484 52658 28696 57223 103 57633 46236 26258 29898 7335 17053 15422 30464 22442 45901 60662 13132 39919 47538 39612 25544 46957 18623 42779 11418 17725 24142 37357 2688 35746 53465 38311 1120 33764 15571 25790 21133 28643 57130 31668 38642 35885 20026 5882 3303 64255 12586 28701 45513 42531 848 63158 34077 11166 23679 30431 15820 61990 51520 12809 38182 845 50462 3008 25285 43054 225 59322 11557 62518 44423 22957 20884 44475 30249 37028 40376 22995 56854 43924 25835 23013 11000 14659 10176 2668 17390 48912 48472 57848 25524 27680 35653 54366 54451 32871 31074 26620 34225 44628 57501 43307 35887 22824 17672 23155 8991 15694 42472 15505 13535 14207 30345 2451 61506 3026 11773 11550 48176 1588 54468 17947 4563 52355 13599 13358 21260 7297 3746 13123 35575 24436 54664 46668 34877 62668 27255 26721 35096 5803 56523 29230 18288 12989 46870 62524 17969 38341 7730 2662 41228 59475 43840 21323 48929 61570 36652 63428 47251 23750 63146 43267 10003 5896 58444 19156 23271 10247 46314 21108 8319 1181 47325 56327 39867 36913 63417 46309 12878 11911 3596 61357 44584 39200 59045 39927 55029 20739 18157 5048 3221 13009 41938 18120 59101 39736 21749 14567 46294 7786 62504 38367 9524 39960 8190 25546 47115 39013 9098 49300 26432 3358 60900 20397 7540 55914 11179 44249 30272 11803 31294 36084 156 52137 9496 3662 12920 6977 59024 26467 44440 44593 16793 34811 62529 11569 42039 63560 55316 33664 50905 44691 16184 43314 7914 11381 40827 39778 19236 12926 52092 50499 11732 3789 8462 20008 58252 21754 23553 28317 1874 19995 35295 52684 6636 24824 51354 61024 1457 5646 52393 54878 57463 47603 20415 34132 10426 52950 39165 12176 56388 42789 2503 14281 61539 16087 28596 9152 37377 53434 35218 38607 6835 46265 4733 38383 15115 33444 52833 2017 48233 25757 55840 31275 15503 982 54406 60688 33890 2329 31695 45264 59686 55664 26870 21633 63181 35312 44722 45427 61850 42551 24398 50828 62148 29269 59776 2223 17575 6122 1056 4407 12696 3787 17326 37910 27980 56998 29314 36399 18033 24347 14674 13684 38711 57109 40399 24753 58284 49740 22179 27194 4197 342 7194 57967 24300 60124 34068 1011 62166 33947 61426 1107 765 10909 17524 11246 36726 45820 48316 9373 42888 17943 64133 56237 41280 45249 8537 11380 19518 50614 7220 52524 44068 11216 56984 64413 51085 8466 43844 27959 28480 12922 28496 42649 28490 60806 35162 49295 31095 61982 15995 5226 1633 34008 63983 63000 6304 58975 21220 4651 50397 9588 53352 24776 58557 60844 27140 55654 62286 56409 28768 63985 19032 15722 55036 54874 7197 5030 64389 1979 52116 63476 29333 17458 48360 61595 44113 49157 20728 51772 42421 30742 25269 23811 13710 50645 47822 15838 148 29912 29003 62937 46132 16445 323 8474 51985 28616 49116 1034643816 3482132906 +1024 12130 14212 56255 22764 42436 20158 33964 34177 64418 38613 40001 29286 55787 42123 34690 13443 40726 36802 14946 41681 12971 2227 36746 33355 9071 18264 50338 60270 21621 30441 5118 38739 48957 28433 63127 6113 50190 48500 47342 57847 3888 11482 1378 47868 30466 19255 43888 1905 25271 39864 40100 25209 9951 10054 56792 49929 11422 20555 62750 47361 18202 58810 51465 60707 11051 29926 55765 39098 38480 19797 41801 60878 4185 17030 6031 31249 33792 23057 59724 26273 21664 14807 1241 61181 33002 7279 17701 2716 21301 19294 39505 44173 56802 6542 57576 23216 20139 27113 7142 21072 56175 22090 48798 43509 43651 41430 55658 18218 43042 8030 43007 14482 42075 33656 30813 46182 42797 8772 16718 8754 37084 41132 55670 41061 51824 25570 60026 54923 19298 24334 40377 45696 50529 18039 30286 64347 52489 49741 30444 39229 55326 11028 39751 13989 63526 28968 7889 21326 10645 24986 5854 46313 45726 9330 36339 45105 17309 9283 11217 1293 7714 22634 4722 12387 52599 60646 41675 48042 24472 24514 44019 30870 62472 222 56419 34965 9538 11987 34369 61380 60141 48422 40902 55753 4614 9642 43427 53688 62761 26213 6359 34087 26475 17714 38257 25240 62853 42600 19209 16024 15822 57736 48943 34444 46020 14372 57370 12473 19987 16082 55278 39512 27803 16648 30054 43330 46223 59139 35974 44661 25815 51204 23317 10229 51131 53202 63227 33604 16474 50223 61567 33803 52966 57632 57902 15238 63720 63819 57314 20482 49523 28376 39351 10926 36680 50392 5309 39735 18042 13751 17485 8372 9912 18070 7588 10693 13991 62224 62207 4135 51240 53681 31281 3578 44131 54560 46174 27430 45536 8552 56713 38946 15705 17724 62642 24082 10268 42543 33041 50736 35135 40431 34117 11961 9075 26757 15091 29245 60661 542 56982 28740 14652 26242 23508 34661 12249 42368 64464 52480 57428 21044 55150 6818 43391 61438 40740 48959 53599 49300 4370 52998 64225 52035 30883 5932 47649 62590 15976 4613 50813 41411 41888 30544 2584 20060 40945 42880 22430 23796 8202 19689 5171 22950 5690 42965 27771 45196 13371 8791 9582 28468 41547 23037 39706 62584 18639 48904 42703 4680 3523 35946 2377 4372 42549 46272 26596 16176 33222 40240 36427 39450 38808 62742 14725 56922 3596 19452 15157 63060 34381 54039 62722 47022 44002 63012 17284 47301 18694 26791 17510 38653 32893 9017 20773 22791 54026 16731 18997 27936 42959 50867 39695 32797 19770 31169 10626 37222 37004 22067 53468 41517 30454 16939 56638 6889 29562 26959 14616 51354 35755 14436 20429 23868 19602 28732 26163 33385 38122 64381 21906 54059 59645 33881 23799 37094 52296 55912 2251 7628 15668 9379 45416 63522 34433 57147 45402 12362 63070 24869 14007 38436 64495 15786 64325 62293 26525 50380 11193 19781 23080 35756 6564 46299 19704 43612 5838 58038 52580 16891 41720 44775 53369 8548 50560 43977 28667 30347 35246 59290 15053 29549 60855 58546 59121 44748 29540 31515 30253 4692 52490 55437 17216 12778 12093 27381 37339 59873 7262 59573 12827 51311 23441 31392 11239 50854 4412 57043 51285 17908 16820 4096 2332 48678 25123 30438 37447 59098 44905 63396 20373 4109 57052 56150 39063 19618 12405 26698 30112 46837 6822 41479 57922 25586 24175 18089 52482 49441 53998 15641 34546 31739 18313 29758 63468 645 17351 3760 41943 36231 10973 7039 49797 61499 60689 56239 8475 25931 20184 29585 15030 30616 12383 28221 37129 34351 21242 28822 58696 56937 44498 63247 46066 17669 51355 41495 15704 59673 17676 13862 16494 52281 8131 15200 16128 47490 13178 58 40209 48193 210 24064 59088 40037 52085 61997 6936 23419 25213 14571 6170 22217 44626 47855 24789 16363 9705 18671 33731 31611 11189 53207 11907 59597 42638 53343 28671 29702 16460 60049 6003 41070 47503 55811 45050 27493 5829 64294 30589 51757 24446 49939 17266 47397 56496 7716 41762 49507 9391 17986 24478 14471 20747 55766 57587 36280 20772 23848 33811 28310 26998 21160 24946 277 80 26242 34836 25050 56884 39947 40902 4350 58977 57413 44426 48461 31490 24926 25187 38583 14843 37325 62404 15238 24564 19815 36957 23899 28813 62925 23002 61917 55948 28055 17546 23943 33094 29444 54882 12419 37110 31546 16730 43343 22770 59408 8577 57889 48662 53175 30654 49492 43502 47895 6360 16963 14482 58652 44878 6921 23906 1773 15233 3588 14584 61204 24851 2748 8039 10854 64125 53763 10090 20651 43062 62861 36517 9267 27812 8820 37181 53909 26537 56371 56453 26583 34510 61978 9054 54831 35717 25240 16557 47938 59632 48921 6004 44144 18080 6293 37952 57895 37819 716 51621 34133 20173 21345 12761 62534 56371 8124 35623 2492 37291 7990 24780 14297 52587 56233 14660 13371 33286 59599 20351 29761 59243 28161 21552 13295 17364 6705 38852 63101 55949 13816 18444 45802 11100 58318 5470 11031 4517 54868 50243 18179 55935 25720 17516 55318 29182 2895 17658 59174 22174 1920 51937 54034 13992 29595 25140 13205 53397 39083 4721 12818 27829 37488 28219 49417 44190 18844 7760 21127 10649 14137 62633 44476 17078 31640 35082 56436 55354 23434 7822 11364 521 41814 36147 48988 2967 3791 11627 45393 52204 52802 3495 38265 41967 47100 49007 24267 57290 60096 1966 5896 44481 25340 12401 29652 38736 34126 53190 25767 17701 703 28160 14570 38105 46004 51023 48816 13291 42131 12044 29756 35518 37795 15576 49691 36801 21997 20790 52620 58804 26 58653 53922 31359 33438 57580 43895 60564 11441 3005 51674 42259 21700 25931 47345 24749 4020 55885 6090 59304 25043 15701 53078 29199 5918 35479 56414 48702 33344 12237 18237 44497 33140 2028 5888 3159 46122 17645 5869 696 52272 61060 42810 62502 55754 46973 12352 23499 49852 4622 40118 61373 55450 30583 63485 7698 49194 19692 57205 16167 21437 15018 47327 62598 48749 23243 33006 7206 17485 57782 40065 54081 36033 656 20909 54765 22162 12834 48689 35797 20483 47006 42364 41563 9340 26393 44049 52883 8299 14688 14347 61578 60860 6458 18994 18560 56132 39699 6193 19935 40341 41589 26199 55246 36389 30044 45255 6168 54437 59828 48044 13697 14075 2220 35120 4906 53081 30014 42125 18268 22764 54959 18836 38268 49857 60683 6127 52639 9513 27286 56111 52411 54312 7164 53653 24833 45282 61368 7709 19679 160 19482 22885 14070 41277 641 36622 27053 2824 12877 46558 15400 54669 26596 35022 17434 24350 20972 5745 29012 11335 45785 39432 13395 31011 15835 39533 30424 3241 61713 60503 746 10150 31694 33670 58788 16745 59695 45278 21320 45473 33185 34568 1987 36416 30861 31568 59767 2494 5297 40085 38230 38586 55496 9720 47241 54442 43740 52718 30837 54734 55534 63316 53675 46389 30876 9926 53000 39526 46518 14770 54988 35395 34269 41052 36364 63265 19021 43128 15677 51749 27267 30706 10395 1569 37830 55089 38181 55354 56039 23455 24105 11195 3849 18392 15829 49385 9021 29946 33395 20061 23830 20050 55083 56419 48575 43335 24467 24486 49870 10801 21876 19776 40922 7599 7971 34481 15807 59889 25905 30480 58657 61143 14789 57731 49696 6228 1205 45556 27667 46685 47815 41930 41773 61194 42421 62823 38569 51035 19395 51623 22826 45833 41658 52257 20369 10186 54737 11751 7098 19277 40600 12096 46654 34859 20667 18057 25812 7763 58372 18693 24069 15609 53308 50068 60854 14115 22164 23901 338 16261 10562 6115 1729 21272 46124 18923 24174 33067 46933 52127 9130 59426 50605 29032 13815 12496 26324 46288 47762 18717 19278 37440 50596 8669 34711 8475 62038 15299 34948 40561 46221 16052 50710 24335 50672 30136 48145 48996 46009 64485 10382 7151 30565 7952 4714 45439 63455 5470 10441 4649 7701 29958 13704 24884 38845 54690 26918 59393 12276 7736 19642 3998 25514 37958 62234 11392 53579 61333 1397 10514 38998 60859 6141 47757 36665 24786 52678 11435 28303 36698 487 49032 20365 14730 30836 10029 62304 43093 10463 18541 13355 41861 43211 6850 31645 11705 39247 54203 31150 10019 9210 43601 1142 42571 34813 53694 44587 10765 1871 26423 38053 25828 55545 49938 5382 698 29947 14843 12509 16675 19730 24260 50536 17293 38064 57171 16853 19719 57050 11869 13119 2446 3810 48221 11889 60575 36530 45032 56373 45340 45522 59877 62421 44914 34344 59124 4583 3993 28616 45852 20093 57902 62856 42563 33143 31686 37371 2223 38192 26654 22708 55033 28274 10830 34484 3121 43232 62717 57782 18819 37810 735 18820 18801 36787 18286 57130 35683 10674 21706 24340 455 29849 2580 24153 54615 24137 16448 45087 13841 5610 40927 10917 33672 5786 4556 2966 2549 32805 43629 26488 52401 36112 37426 20981 10302 51913 682 37740 33679 40729 62813 62113 33232 2444 701 37421 47979 40306 57542 29803 10268 7930 11023 3757 14095 38282 52447 6906 16884 5569 41204 17259 54216 147 2618 51585 26499 24750 60574 34410 52429 37023 15071 48557 17019 9830 30922 37664 25729 53516 39151 29136 45817 5854 39765 6045 15292 58056 47508 59572 24731 38687 5354 53711 44455 39337 10114 45534 59598 13333 50922 48516 31010 48859 23652 214 7938 15608 5260 8907 10378 28212 60382 16604 23354 42189 48687 59774 3161 16851 28555 56991 44361 33180 10229 63895 43842 63077 7880 39684 64467 45256 49700 3980 55822 19194 25432 23661 580 42578 45336 54551 42765 21990 32993 23914 9976 47267 58350 19894 39541 17186 25461 63209 16623 58652 34966 4931 7517 14458 4892 29667 9040 59641 58615 50313 18630 39365 17870 4784 24212 20427 51935 51467 22208 20041 24619 22877 49561 59281 22245 15245 60322 46036 12502 48708 26742 2216 30540 12778 3253 10573 50743 27977 18940 56299 1422 28865 18239 9613 49825 60235 32780 45501 52720 7003 327 6921 14965 54946 3182 20258 34894 31693 35158 20073 20293 61359 39314 40176 50407 28577 36344 1731 20931 56815 52533 26322 30162 21279 50972 60453 57969 890 58201 45441 5328 38781 8182 60890 58277 18185 19710 22854 35845 42107 18687 37534 51456 44466 32977 43730 42802 41813 30165 37547 50091 5228 19426 21552 57082 4457 38723 30058 51880 56004 22014 13810 47188 26761 44075 1680 20627 43905 10619 35415 60828 63980 14894 63274 242 31163 19012 28492 13498 18016 9993 43541 50722 14596 42647 62894 41788 62501 7413 23165 10863 14951 48310 57523 37827 12706 26053 59215 57252 53954 1744 41307 11934 12491 5608 1201 41065 17683 2549 11526 56966 4501 39871 22215 9736 30650 8424 43196 62430 35075 54660 36932 12028 58354 52426 47449 49936 47044 40385 54126 13638 41954 37029 7290 54047 13650 48493 17610 46273 43107 60762 918 38135 41563 31244 20223 49213 35214 31462 54287 10129 37776 7994 58708 8631 61765 44547 55017 10973 22919 22487 14492 27318 9313 60294 13607 11551 58272 19570 18892 26595 29034 54102 24828 17988 22805 55122 52155 15331 45391 34865 54477 33112 37650 48617 58470 5623 64206 6470 9608 48626 1755 55109 36011 59567 49972 16657 49997 51810 40970 46141 12842 49243 33566 31229 16647 40959 29828 31317 13020 16059 16139 48864 11406 54839 52555 6077 24397 38995 43489 7871 9497 24014 25639 15554 24178 32967 59032 37532 36409 31203 6647 42195 6944 15110 45003 37582 26557 35556 19304 21703 28692 9730 3526 41301 16375 21183 24769 36049 51874 30965 64478 35942 15980 16214 8935 16356 17453 32908 42046 17216 55907 59417 54946 12182 39566 37943 55754 14369 56008 10941 31371 5896 17849 28661 23973 42927 40690 41945 43693 60314 44469 49321 23914 41281 38985 62380 54581 24469 18693 34422 2880 3510 271 31521 17792 41961 15537 11487 23173 21485 24206 55120 44256 57217 22669 27046 52996 46263 61616 61106 19051 13546 45202 47873 1854 63416 46406 29970 62601 38700 28808 43373 14566 47887 3312 41985 9277 48450 4432 60103 9430 747 43178 41875 14909 30825 11987 24578 46369 45993 28415 47777 22780 10945 32992 31574 56211 8996 5815 43525 2394 55510 47725 7904 7627 38686 31704 19992 61587 47091 6440 44281 47061 26641 58162 24931 41746 40795 10620 24789 38154 15138 17442 13378 53939 6684 21216 8647 51240 56099 47913 20243 41014 62094 51180 46961 56520 39537 28972 6463 43162 36628 38400 3292 9255 11886 21005 52795 48107 17382 25409 31725 34029 39985 28650 7119 31512 29002 25307 58799 31146 1627 35442 14415 16338 6668 40607 52867 58732 24607 27615 29900 11453 57748 39518 36906 64188 52338 30332 59568 60315 6277 6951 59867 54566 63540 724 41460 11118 36308 41636 7779 55546 48710 46513 43594 18251 42865 52457 15069 8366 54428 49888 62068 8169 52728 9063 63919 29261 47134 63364 60250 49366 53341 19472 55737 38595 33768 7202 53488 7481 4235 56293 38499 57440 57109 26377 17555 3398 33916 58215 17770 33520 49321 0 3476659889 +1024 8879 1486 19858 11140 18830 52402 37076 62517 20780 64468 50162 62329 27005 30331 12130 7780 487 51032 13438 58991 7295 47487 27937 30048 43784 61921 48479 13264 51505 55081 31135 53994 2764 12916 9226 32958 8243 4018 39531 44902 48500 60770 19074 25752 8007 8884 45025 33944 14364 61584 41448 61001 49468 39672 50623 15442 24412 51740 14559 37238 38161 53078 40184 5051 12685 61130 27491 34798 10083 2077 45360 58726 64174 28603 62073 17228 21954 45953 9559 18030 7745 2948 43800 30823 18414 17876 2582 63656 13728 62512 36305 35411 15483 47658 19066 43440 26936 52567 60102 55160 58028 53467 20100 14590 33830 18552 13864 63299 6048 24300 21484 14738 10856 61932 55252 31054 7258 52586 33992 15901 48690 40813 51332 48966 37740 8037 45236 31350 61719 2052 1544 61962 60263 64102 8731 44910 17065 19550 42777 14726 16278 36642 13306 52718 21922 46689 3022 57118 29689 55431 62986 28407 2185 17633 53739 45572 43446 21275 35077 30428 6402 7215 52694 64381 55238 25530 38596 19607 13956 58542 11301 36892 37652 51084 17597 31542 59518 31091 18090 59316 48234 1016 15537 32775 53848 45470 59527 18697 31694 44945 62468 14172 8234 15574 55980 37010 57637 3817 11527 21827 3346 61894 57888 9503 37069 36954 27904 24040 38185 62415 22789 37592 34226 41269 23406 11558 30544 62819 60203 16652 50268 3408 14610 9836 17136 64257 12370 19861 35173 44051 46344 46557 7453 55482 50410 12308 10009 27970 45313 54314 9063 4143 57251 57523 62943 5838 37297 19657 37710 62976 34937 6627 63309 50763 47447 7114 42806 52620 43538 54726 3292 58750 7898 17438 48753 36805 48133 42832 2788 49949 46295 5165 53027 45755 24953 41549 57718 9554 6048 42150 51990 38811 16489 51264 7953 42901 38972 9318 15231 6297 59877 12431 37660 60912 22420 6758 45842 37630 38130 23948 4623 41661 13663 28620 23711 35553 58851 33752 17243 19228 39189 46094 58936 52221 59028 24430 19248 11552 47997 16174 59546 42073 36202 47114 59006 3033 6044 23135 53608 11340 30414 55717 24067 45000 11673 36460 39690 45721 44363 19467 24968 2197 30681 17707 30744 35640 15376 36543 61808 44031 26689 56569 6647 39109 12811 9771 44133 20345 28430 52974 61285 9460 61899 4660 51441 7163 58244 27797 14937 25292 14202 26700 4612 6456 23568 18990 57429 51829 17896 1242 46579 25818 45646 59671 63064 16219 48435 39264 19305 57548 18141 50086 9256 62944 17899 37183 8546 52736 20115 8147 50908 14758 20198 47768 33131 20843 30255 7035 57183 48647 53582 41245 17237 45875 35281 62121 21949 14284 9301 53272 50406 11706 53194 52450 33465 51504 48240 8931 55855 34915 38631 31246 5490 28183 59389 50474 50220 62734 48030 18655 17674 1573 35443 27055 8008 21919 49530 19590 6776 51576 34877 5864 49231 29324 56165 17481 62582 14561 52939 12862 3145 9456 39132 5199 61946 20205 24427 53389 22891 16453 16139 39838 29428 63010 35204 41482 1403 28026 54202 5605 23267 40198 34890 35162 46354 47671 57652 33554 42792 30800 18717 8717 33900 58644 7391 33740 3318 49614 5479 39939 27394 54282 18136 41186 59562 60266 5566 26924 11643 16380 56700 58798 41834 55303 11289 54071 48850 36760 10977 37529 17180 46760 57429 20280 47906 37555 7182 57509 709 13176 38313 45239 27276 28510 42004 9162 21396 28627 53923 41554 14449 3082 50112 18008 62569 5841 49157 63769 44168 56297 19157 53137 27809 62345 37836 52203 9937 11681 25247 27004 14043 51706 38710 41932 32815 61001 45174 28038 10421 46944 14671 23500 21890 46266 40144 51294 28890 45835 35109 41916 34998 13796 52197 57062 25197 28993 16979 60690 22706 42329 42445 11360 2293 7640 22698 47855 56614 37635 10360 61993 60677 47637 35245 20661 39879 30636 45013 56337 51331 61639 61121 333 33955 54491 26099 51929 37307 27480 19064 1274 17358 33174 2763 49973 29151 13779 54379 27279 14375 15652 54734 59466 25235 44694 63196 9409 9742 15492 37910 36337 7803 52920 4410 36119 51120 40749 52216 22004 1415 59059 28108 64060 42438 48368 19244 44555 51012 46275 8811 5818 64372 46672 48025 34179 59789 16044 46666 127 47562 20375 11067 20928 49911 57814 54779 25903 3952 57093 62400 18475 37219 821 11491 49639 25341 5552 45610 57924 17538 17378 6667 39560 24268 35064 31594 53824 4311 1828 51445 57658 15412 60682 49959 32959 32776 61350 24529 41372 11820 12610 64351 58220 51211 12295 18341 55417 63238 44384 59669 46860 30039 21260 47787 58616 43357 12826 3744 33103 25643 29003 12778 12891 40633 46964 1208 18859 52512 46048 51205 50897 17666 11418 60050 39379 57929 33334 34024 1255 763 33696 24765 18057 41502 43551 10786 30337 42022 43606 7204 33510 20322 61831 18728 48260 18335 36811 19780 58334 46598 64504 19305 21823 54255 11717 597 41394 39955 7902 43023 10092 49877 28276 9822 60743 10834 39740 17404 40227 57283 51110 56912 47633 58850 4 44141 19733 4485 37431 4578 44145 52502 21084 25760 407 16856 15558 61142 27618 51118 62442 54764 31583 12293 26623 33723 29252 39710 42496 4277 63408 12560 19620 14784 57766 63438 241 11615 30924 55745 32947 59041 30061 26394 2057 12432 48234 52553 29253 54100 40273 29141 23265 63186 718 8382 28006 62125 54187 59968 3045 55527 64006 38905 54072 51991 54115 48320 55656 52578 60429 4160 18046 49274 37812 49436 46574 16265 13800 58953 5984 48320 2236 36576 28623 11602 22011 41182 6956 9204 14124 49848 62008 55542 52033 9084 45867 38294 23203 4215 10611 8751 11459 37927 50786 61207 26980 63840 10643 5181 45014 27836 6000 41545 54727 54406 30409 62042 29826 53407 10401 53733 57890 64315 42266 5271 15771 47342 30014 9092 14063 50990 40225 35761 29512 60994 46024 10016 26700 18859 40898 15166 11385 47109 27274 24437 30301 13619 51982 8949 18960 44966 60712 5548 2961 48799 20797 55808 16122 47311 22367 36815 55273 61697 27676 53839 15383 43466 35412 11060 46151 42199 47901 29107 53365 9584 22356 24009 4334 5181 54817 12849 57572 36682 29378 15860 9881 62075 20806 4855 4703 61628 17455 36066 26032 23755 52301 20534 52879 58861 21380 4099 40393 63963 63565 23085 46948 20850 10597 2711 49043 12431 17304 29939 16110 742 24776 7646 51458 7700 14648 17245 60763 19480 19783 17544 6382 2701 2361 52620 32864 19205 27354 22218 27449 16906 60758 39242 60745 27189 5577 47152 53485 3763 10881 62738 57614 59327 26288 10740 60171 55427 13318 34529 46814 10908 44065 52928 49431 11052 37280 55334 53837 58022 20359 23125 12643 28504 42616 37457 5498 19104 5524 57078 46110 52909 39736 17473 7106 58977 6068 37442 8342 9562 37899 41633 48461 4504 41492 2863 25498 45756 53264 3103 62121 41264 62355 52868 34350 59982 17489 28586 16250 18751 52842 61882 16724 10131 41298 7552 35584 60634 23665 60778 19598 60141 551 12376 40520 7801 15638 51027 10270 59830 35085 43050 39497 51248 59430 53767 26745 18531 28929 54095 1854 60045 41352 61422 2603 49561 58085 15183 28179 2703 44489 56891 18503 51239 28992 29859 30279 54228 44506 53449 55112 25487 44004 15557 34555 12462 12355 36403 49169 10182 38270 39801 60312 50369 43300 11573 25854 25247 56584 2468 18887 44966 35883 12025 56243 2751 8376 50544 15051 3178 60792 34267 21359 62958 6435 18671 44278 38678 42436 41617 62741 16879 38597 33686 52154 40462 45315 51918 8480 55514 47660 14466 49074 25796 22758 56413 31142 15708 48895 56780 18801 30927 7272 57874 1342 12674 42922 54339 62180 17213 1026 59084 54609 20410 18139 50272 59700 60703 24584 40384 16404 24884 6235 7446 24554 35636 29842 16491 16602 6178 14105 42653 57852 14147 59522 27701 11344 56242 27342 21301 63777 40870 61141 24981 3463 26691 16154 53909 5925 16065 21861 53682 34894 3471 33068 52053 38443 59081 500 8338 25742 34663 48170 2225 63751 36798 24239 605 13226 53776 3143 7647 61625 9073 48339 45827 4414 60366 39346 35775 5310 60678 2528 43794 14410 5601 36784 49933 15596 8649 5350 37874 42726 14098 61892 24590 4580 19733 50483 301 47865 57439 7577 19552 4854 53053 15461 58175 55826 51333 56812 20318 45746 62619 64090 49894 23807 26364 34436 35148 59720 5067 20173 28208 15279 48926 41189 53233 49576 62289 39096 36680 3908 1758 26579 20799 17755 60802 44710 40428 10119 44084 26775 22708 8572 39332 44742 883 37147 46966 23066 43386 30135 45668 53503 8724 25202 46146 15209 22734 718 61440 39448 52385 63492 53425 2747 64068 16151 36895 52830 26743 56269 17554 64474 12074 19368 12436 4345 60831 16053 25094 56432 10254 6469 45363 19790 46043 55616 16230 47700 62144 34364 63643 20214 10104 47276 1613 23464 29817 45264 33963 12557 61962 1543 18253 16596 21378 40184 52614 10637 42381 50762 33396 56424 28945 52791 48139 30607 48705 46132 7395 37078 28541 29520 18561 24543 45650 54095 19887 47295 30467 16387 45404 39863 32846 6723 62520 21201 10693 12600 21752 9042 12530 61827 312 49366 22864 46589 29698 49403 20848 59538 30453 36361 9792 54918 58779 26980 4605 23460 13737 20472 64449 19000 46040 38098 55473 40132 48268 47264 18273 11391 46204 30748 33534 62393 8852 1749 4564 8340 53159 44770 43325 18430 1834 53113 22355 27327 716 27274 34483 3842 44632 39667 50022 51403 52202 3519 16262 6414 58003 43154 50389 33055 13603 52433 52435 57974 35370 709 27703 16520 38500 57468 23230 15617 56786 43071 62843 17965 56856 53254 20064 4909 51510 47088 49871 21969 29457 28857 1851 50442 30245 2539 63148 59724 47705 28974 9888 27948 43428 296 16526 23913 10251 2669 6509 49145 11307 49821 5689 29364 14893 40319 36747 32850 47387 39476 49303 56161 7344 23991 58379 43869 37262 63356 9559 50959 22390 38717 56361 4660 31109 5262 51268 42113 5063 55817 47879 52435 14603 62271 26181 64143 6830 12241 34496 12508 34720 5578 43606 1234 46860 17428 28579 58833 42946 10459 183 6795 39933 24988 23414 49279 48560 26466 52336 19829 57420 19042 48324 29907 58715 55866 61326 47699 27606 56631 52843 37651 9851 12720 12133 52585 13754 5778 34594 45757 58676 10857 55690 6526 34975 62187 25919 13896 7845 60640 24855 33482 6 15675 50400 61010 26064 38042 16309 15112 55414 36882 16423 48535 1871 22494 25984 40601 54447 14125 58317 24941 62965 7214 223 62821 40215 19664 27104 24021 8182 6972 56756 6562 46850 11949 24887 14930 50181 28452 15113 64469 63986 52945 15580 487 23408 54816 23006 52654 60049 62318 4178 21509 13489 29251 10836 63046 22837 32918 57330 59281 33479 12558 19854 13752 19792 40643 53782 5543 36958 50809 8535 62334 34536 43309 14020 36947 43 45750 6093 20000 57032 59180 27814 14208 25159 14846 58714 45156 59589 46705 6256 58634 14963 56440 9497 58501 4925 43089 25011 24964 6468 19944 19239 54054 60218 14523 21858 45076 51529 52185 37157 42501 17921 38439 64091 35210 54303 18188 14907 12189 17275 5093 19137 60306 7121 2827 40196 7469 35521 17081 27666 27538 5883 48637 1890 41691 21291 42704 39916 28795 776 58304 52280 19469 52314 59817 58496 5392 19978 12736 18881 19101 37915 24562 43548 61057 22086 47921 22326 8507 20233 30149 23774 4377 42860 33883 59515 44186 20305 49177 57490 30667 16501 38519 34026 5354 16000 59127 53191 62922 59829 40490 50770 24950 4513 53919 54574 8432 12187 64011 35217 16555 30751 25044 62077 51120 12996 4859 2247 56650 25382 4112 56272 37128 5476 10599 27893 25380 10965 40850 10487 4909 22164 7519 9263 36659 61658 54402 21604 49925 29002 51173 14560 31019 3538 55034 51144 1593 12245 57205 2122 23140 45069 17555 21580 66 30801 56448 24375 39589 39879 4764 14972 29501 24819 40329 41541 21885 34049 17691 53921 42455 51620 24650 15763 13962 28149 53209 35941 8897 39779 1692 56081 62389 12837 26602 24736 57280 57605 18281 41101 39934 42554 44452 28898 47658 4515 1417 12035 49201 14612 2873 34807 40170 12772 42293 25159 44334 17282 48035 26343 1336 14088 61149 53081 13804 20607 58559 35144 27736 36584 58172 40754 5826 33259 28829 58067 37422 2261 21763 39369 52222 38484 35234 27075 19843 56247 34030 27234 5157 6902 21822 20317 45827 60389 33957 45606 60655 30727 22642 48586 39066 58150 63444 54427 5257 21083 44124 5774 25030 10005 54936 10083 8808 5456 24100 7857 15492 35086 17134 11738 26378 62808 57333 50594 30065 18846 53588 4648 33427 1187 62919 60309 17944 40652 20717 19851 53090 20347 53710 33887 9947 57511 3003 43122 25263 3433 41526 48104 35651 13442 57165 52034 237 40822 56022 3020 27976 9004 25132 30145 35406 48412 47858 620 55405 763 36667 12656 5390 42071 24171 51324 7007 0 1340386534 +1024 38133 31266 17829 7783 61533 36532 53620 34513 54058 55588 43097 18234 52726 24939 63918 33867 38951 2497 6819 44059 11282 51088 17345 51569 16103 8054 3138 13487 42695 8353 13185 39117 28314 55288 18518 55316 21839 45681 43569 46663 50382 45454 25060 4907 14251 53436 14846 14718 57327 54860 62124 17978 12108 37574 31548 3888 18001 17298 42908 62335 27678 38857 3809 19089 31035 24769 36631 59740 43579 13670 5923 60232 21459 1175 9696 37019 10406 16661 33075 20972 39294 51350 31194 1068 49953 52896 5475 57463 41730 39093 7271 6066 43038 16975 19654 53603 44387 9430 33624 7283 5283 18637 11939 3193 37914 51402 35011 38261 25838 1023 19641 56368 12731 34481 39775 30082 19375 1883 9663 61462 37951 7825 26337 48957 29333 45748 52656 5617 38852 46190 19443 38481 17477 52417 45823 38031 45732 10463 56733 18705 35428 53998 51988 7323 11928 46622 53390 1579 26866 17610 29844 50309 51984 50167 49212 15083 53648 31473 3504 58483 62965 56065 39277 18276 30456 51251 35539 41522 54821 14524 43375 24521 13983 56259 543 63090 58824 51096 50035 10992 4175 11485 56681 173 9560 18732 13432 4897 18652 7677 40018 12276 24519 2288 17637 16118 50138 14984 62242 29987 20159 38141 8640 23267 5266 22072 21521 36174 20237 28727 7826 30934 60299 18852 37083 35937 46125 31429 46413 20809 1940 31338 48579 64447 22788 7041 13421 50014 62440 36467 8819 21803 13349 44222 719 4054 57287 38087 16877 37302 16865 6556 53092 62451 15788 43683 13347 14867 28340 53929 14 52719 52400 21943 51597 24672 50738 61364 20902 59262 49694 28131 62014 16228 25454 7111 5874 34277 38472 63871 29557 34622 26144 18604 41706 55124 46009 60372 38452 26425 16618 4745 34562 42952 37249 9532 64169 58641 61860 20919 53205 45582 51288 43370 139 35086 46565 52546 60432 27787 43196 39860 34788 11950 18531 44465 61846 46351 35082 12996 32823 35055 29528 63763 14258 2542 12394 38625 29533 46956 55597 58231 40306 55865 5284 46196 18849 39181 59241 2663 20982 15562 14694 16449 55656 5862 41912 38004 41986 49146 26415 34485 59049 43367 25435 37049 47772 31227 51997 24116 8327 21852 43573 7233 56404 30367 18521 36045 39213 40386 16733 50629 44510 25679 52102 13848 57584 20931 57729 29202 8394 46317 43207 35002 49378 47413 32847 64475 38959 31008 16714 29881 17544 21903 24335 31223 47443 10140 18929 42734 49198 42387 60433 31552 22359 34280 55677 39371 1465 55859 22683 28233 12903 33115 8737 21120 35516 54301 25487 35875 43823 48546 160 14223 25563 45483 15777 16652 41126 31525 39552 42919 29856 33569 10907 61899 3062 39620 37834 3253 26337 61702 14202 30270 16437 58439 8077 63019 11834 61480 25979 9310 63346 3009 36763 22755 26948 14682 4456 15623 47480 20263 9840 5099 57810 38772 11097 30454 16327 10115 496 22137 13717 41265 8052 38456 50488 40009 5600 575 7908 34835 43467 60367 34985 53316 44874 49775 53952 17793 25947 61361 39662 47676 58104 59681 33677 35260 49034 1983 28413 47238 49253 24043 32777 24189 7811 48237 45908 13619 48031 25110 9323 54024 59383 43799 28079 18634 50985 43830 62762 17485 55534 28790 50281 15168 6826 36916 28784 47534 11447 39993 59228 29963 13341 59547 25431 58748 5179 4876 31525 36830 41558 7594 58816 15199 46459 38804 60213 18324 35326 18055 20649 16676 62442 56528 57285 49790 19640 61738 14046 19677 15825 3501 19202 51204 54077 63977 7098 30760 45374 45018 9061 37458 31446 58024 51174 10252 3344 63690 63452 23285 2421 20228 43159 50474 63417 49658 2944 44066 50902 30852 22057 54950 17898 42734 2734 11561 61767 61340 26545 61646 56815 44603 10688 57132 12652 36807 12736 15938 56439 39183 50950 42075 3190 52869 45779 10991 3139 45424 55703 59297 11341 48989 25818 60939 11227 29258 16496 38223 10008 55564 40731 17955 14835 5618 27227 36065 22812 4509 55239 11348 13122 59595 28891 11651 15179 14541 37892 14337 55069 11228 33933 28177 44726 59026 9408 20432 4128 16879 47434 63258 31688 34083 13919 57609 59436 55057 62646 36875 52542 2749 62713 7642 58099 33398 59977 29381 12981 22389 51454 7695 37887 12078 25542 25524 2930 64435 33316 7395 17680 60213 49464 5331 40244 25988 61784 19546 28323 4304 59335 57220 23937 3171 10469 51147 4722 16895 54918 13982 40810 44756 5485 43120 39469 52204 15184 35865 42863 47836 45599 37013 63052 40877 5840 47193 35019 40824 47140 3705 43628 14330 6532 54094 55585 60565 42396 23694 3415 28696 52048 51794 50575 59498 26386 23857 17384 5089 28676 52020 3493 25245 60370 41591 35309 61546 58312 55136 4212 14334 40747 17821 50413 24785 30280 5564 35966 40763 46705 64226 17653 14445 39898 49773 33465 12868 58336 1983 391 59707 24058 41576 34981 55396 24937 47036 53044 30359 53463 27103 51157 47583 7582 36794 17305 26745 42758 29612 62315 23421 19331 61918 61066 7954 53168 6376 59429 4473 30045 33522 8987 48362 57416 2327 41509 39404 6778 12729 1842 39967 13645 49884 27348 17650 19052 50937 64087 41125 37901 54492 36358 37787 38757 43918 47254 35199 7971 8686 4365 34197 23789 62941 4790 5276 5122 7010 7285 16292 863 37369 36806 3915 50489 39908 25293 29628 17 6173 54658 33961 55895 36747 17348 58279 40328 49789 52668 9475 23512 64301 56949 22022 49808 8545 63560 43826 31617 46176 27110 69 2512 58237 19571 23403 6253 36101 42266 62849 5878 64428 2029 19051 55927 39325 50082 51065 29388 21983 60067 51905 32937 34252 21593 28599 53538 26605 59810 60541 61359 2643 22011 19102 34790 59597 3038 9630 32981 17238 348 18893 10234 40765 53343 29830 52263 42834 11871 49454 57712 53883 44579 49719 55280 39138 51196 47297 61785 47563 44701 37015 4816 54213 2899 370 9542 37421 8369 38158 8505 3418 11107 17606 16681 23851 58767 55278 10173 39811 14530 28090 50195 11498 36723 56040 3866 36126 60051 19211 15438 43483 58386 54107 19148 5204 43371 37527 13411 51740 51957 15333 41376 47327 13734 5539 19149 31485 19536 10743 8282 58331 56228 911 29413 56730 54855 13414 26723 14096 50330 35841 51278 59592 19632 42497 22950 37383 372 1161 59414 55843 63113 55933 14196 36199 2729 61322 51908 52576 49863 15557 26477 8513 24543 6909 3406 59651 26305 1345 43393 22146 60861 15704 518 20354 37088 4958 5494 55099 40302 49228 54653 53153 48872 15695 37423 9543 48732 42883 52158 53303 61284 47451 18377 49493 8609 24304 23794 62368 11926 57165 52424 29153 9900 48148 24026 9261 10221 44653 49346 35317 31626 51078 44201 9237 33635 23611 22288 15021 36074 27112 48374 30812 12657 63138 26996 35764 10174 45706 10875 861 40369 30111 31163 1582 19502 24176 14425 40871 41261 51991 30156 5142 6663 52997 3292 29030 12126 26774 8490 59905 23789 7037 51598 21124 58648 60354 29224 63111 64021 3032 19918 63886 14438 53764 23047 7292 50683 24858 16068 37105 17339 43434 40771 36573 14731 22445 4426 1305 52250 20735 24813 8396 42576 30748 60278 49734 61163 56369 44785 22868 19715 33472 40445 53048 59993 55790 41779 39656 13578 51013 48692 16287 18894 34300 17561 25477 2126 515 23606 53705 62656 51478 4496 55570 4396 52042 48072 28210 5950 6954 41633 39590 45436 44078 24081 45007 36598 3802 61842 31334 17570 17614 42619 55265 40415 16525 37946 47012 52667 3884 30385 19235 57123 25876 41751 14945 13298 9443 3622 57503 41037 45647 3948 15003 21901 7679 12844 4362 45391 20312 3041 64440 52997 13019 57825 18843 28182 45575 46935 2874 36503 20165 62488 46693 10678 52752 45496 55769 60472 9957 20205 25593 6178 47043 36632 63568 39210 46614 28277 42500 45460 37615 61834 11483 41477 55900 28551 47285 60083 47790 24150 61689 17440 36002 64035 7615 7824 14721 8983 15491 62273 62771 852 52964 55291 17702 34400 41517 10490 58258 12799 46050 25120 8620 39880 20590 42130 47052 44145 44381 19290 56913 49843 25400 5408 55797 58830 56302 50780 64321 17391 26357 20356 35425 29854 49905 59101 56551 56043 18457 178 63122 41659 30153 63104 10169 13345 26721 21904 46313 41372 42305 61095 38165 26170 40416 28659 43959 32794 40510 18319 18233 5392 61644 15426 45147 58040 7051 6463 23269 20401 38073 29187 33305 40561 63088 41309 6145 8200 15285 7605 17179 30765 39405 48410 34354 27965 19728 61977 25428 40292 52067 57200 46085 57558 50954 28964 52948 10276 59119 33458 6489 25909 16925 35553 35281 6257 37782 49780 24487 61908 2946 43078 18247 350 7088 59659 64113 19919 45058 60231 2886 19555 8945 36095 13745 24638 50101 48315 41369 20671 38870 36698 116 38957 58913 17807 7513 15903 58016 2995 2119 38596 12364 29957 49717 47559 20617 20243 44132 1914 44962 25451 1438 39239 45444 40538 44880 14530 53228 27198 52684 56957 4362 5971 37640 210 57846 56743 14481 24284 35892 58343 29802 22633 57539 10633 64102 40276 51469 2284 48144 55349 34941 43729 58937 53866 34447 2167 24424 45831 59571 57817 18425 38311 34041 58143 30921 3550 2923 26743 29919 46166 51005 63120 11872 4009 21009 17036 23728 58547 24889 5577 59460 47197 30347 19368 56363 36426 18923 42930 46373 2576 33259 50752 11213 52683 252 26732 4985 34253 52081 42160 5193 51545 49951 18803 21725 44171 13578 55249 43659 36621 36845 50345 40130 17452 20542 38175 49799 28852 28696 6669 9515 35525 41928 48357 27661 51715 23531 41002 26964 22530 59318 40548 43385 8570 36227 24701 19864 44596 93 57192 61053 35300 6429 42440 35212 4914 58703 59735 18670 14303 38942 49186 55520 61787 27088 47243 51644 42595 18168 24353 50683 31093 48145 52793 16590 40010 21942 63676 20215 48824 14292 17259 39562 52411 42943 35282 37920 49804 43323 35523 24559 13303 40515 44485 62165 62689 46584 13693 52037 8060 56044 59975 60327 52539 42421 35701 3438 8808 39351 45635 38065 7547 12486 31635 7955 44658 38935 13713 6868 8408 30291 10913 5177 41212 52912 35128 17766 44964 20010 13119 34894 8592 58611 62701 39513 42146 242 29113 34864 35845 40404 48370 6663 36219 20282 45351 40560 55320 64107 61694 14428 38423 34254 15988 35125 58253 50432 18173 14250 54370 42737 59349 62597 8908 25855 419 59216 53344 60552 47637 22050 16896 57167 45903 62936 5483 43058 20901 20299 26378 62429 51268 40684 54807 58318 23473 41657 20373 36010 53928 23392 2423 51748 58177 3831 8911 48466 677 2644 57971 8499 12802 53294 62433 37559 58685 58351 1189 38704 12206 25114 16691 24729 5294 8937 62817 26066 47898 23938 46345 36478 919 25770 1222 2391 43780 30472 25594 1147 17764 25043 12124 46975 41839 9548 44069 19132 62061 591 22874 52022 63132 17784 38221 1547 24829 19204 22800 3229 21953 57662 20775 62199 38775 15316 46280 1784 758 61522 56368 40702 48843 33747 5999 56925 20389 15259 53877 1783 49601 27859 38751 58994 42448 13704 16864 39810 59107 44195 37437 34963 54680 44942 43290 44300 14896 45087 26850 47836 6006 4809 40123 4107 19266 44527 10773 25963 56712 49998 24864 47694 34935 56209 45854 28493 23331 11612 24772 1389 57267 47405 36134 38387 61139 3839 54288 17628 11479 38532 49778 1974 33221 46273 47810 57969 20652 2065 7159 469 6722 4059 63564 50403 18005 45965 26177 56433 20705 33938 60431 59681 1198 39868 26451 24153 5970 25943 59617 23581 29931 50362 21720 38751 7892 27811 27600 10260 29473 6782 34190 51803 28948 42240 21706 24891 4527 54658 53526 36409 55910 44731 56565 13650 52048 54950 18029 5758 50643 17577 33129 42345 13996 29430 51960 14360 63681 53699 11913 9586 11403 53483 57778 36492 16454 47890 3755 42534 42531 57519 35717 22579 16296 21594 46350 55662 63649 58832 42975 19837 50986 64180 18021 6845 55262 17797 25266 62403 21964 27090 26597 16825 39281 1293 3165 48405 26098 22205 26704 25191 59819 5411 16993 4532 47938 44945 8048 27993 38535 61172 33407 50459 41345 51857 9195 63361 37104 13821 35458 3138 15826 47334 61253 50173 3440 58828 61343 20540 16118 57570 45088 17640 5461 12598 47356 24726 23707 18291 15054 2945 8868 30847 40447 15038 30720 1673 41976 6924 2301 1061 15738 46851 42097 4663 26306 62432 36718 56588 1588 10377 22367 25174 55923 14663 25208 20609 3324 61097 42866 53049 21607 63854 18222 27763 55067 21206 61386 56298 45593 40859 3285 12580 29263 38177 57768 36278 37933 38206 11755 20 3315 26273 50352 681 1295 6315 36173 38836 10158 41000 12509 16569 23337 29740 58861 40574 5203 38756 8169 38249 56203 958 63778 25758 39200 45160 52661 51475 10728 40713 19533 34479 17532 56254 7333 24001 32801 17458 50536 64500 45583 53034 6355 22237 31178 10535 0 1336229442 +1024 60998 59988 60687 16076 44070 4816 12608 39759 55130 6236 220 3688 27367 18257 51646 2539 44241 24214 3669 50600 7721 33379 400 101 15065 22627 59070 41541 44954 27774 2173 25601 30984 14366 19331 33465 44266 40190 32842 3557 23258 36462 49918 14115 51380 8500 39265 17794 60272 63261 2253 2206 46670 49154 62338 55649 18646 17451 56156 44947 33126 22753 53355 41610 6274 20489 58545 51713 47896 36854 52599 41890 16228 19697 43799 20378 11669 5742 23883 51992 60458 17293 26294 64204 47271 46451 17170 29431 109 61941 52094 17336 50971 44848 16989 13437 3394 7505 42852 19207 61956 54353 14576 59815 58652 61679 49692 18103 12081 16650 25558 7335 52347 8545 15269 9765 21181 44899 9284 37641 61184 35770 14539 40851 7273 42868 45640 63211 60026 39792 34443 35541 26207 59601 46563 47556 50131 54150 62678 9070 4825 42735 948 28058 579 4206 63056 40387 52411 37823 55317 4999 22522 49196 38900 41818 17767 9339 62526 14039 12573 63376 60221 44681 9710 61885 31449 16317 12085 2318 62793 50883 2841 12290 61796 43981 41948 911 12652 62972 51092 9354 61918 13548 9617 44785 59590 51172 56392 54723 36306 27883 17986 35640 64180 34077 61370 22051 34294 47207 24607 16531 3231 24291 28570 61347 63873 38706 3106 45471 30909 9261 22790 48066 38057 52081 2932 9861 34322 23707 36199 45433 59979 51769 15296 30832 60048 44640 43859 12561 26363 55908 48479 14750 63397 37059 17928 36474 13825 51381 29041 15157 29312 27760 24572 35726 64019 3843 44952 34244 1288 11939 29061 28125 46044 38649 11120 35477 27911 55551 27452 13595 20454 16356 29761 10232 19354 63801 12935 48324 827 38309 19569 22931 22704 52595 17268 29424 57481 23944 25920 22695 59096 10206 31003 42317 23820 30992 29838 4385 5713 28180 37190 7327 1070 56081 54225 3989 42285 33103 62225 23510 9785 47337 14344 29500 62447 24826 49508 29010 26209 27623 51990 7995 60998 34103 54655 48043 50410 38097 33941 13696 44496 47177 33788 40749 13204 27223 37825 13727 33865 31071 4420 30609 43674 49431 61281 26595 61139 17821 14505 27511 25734 16916 8784 8971 22292 30020 7806 22560 55121 51456 45335 10344 19033 29147 14057 23949 33849 9729 51682 47823 54876 31225 19276 23690 24828 44700 858 1710 20041 55897 62617 59478 410 18142 50254 26514 16456 47954 18059 12492 14644 41045 38349 33993 30731 9110 673 20734 53502 50357 42059 36177 58389 16478 35308 57741 4082 26413 62644 42188 33973 39333 7432 3880 37559 35056 8573 31266 14179 24629 5023 21534 61703 51781 42850 36512 13658 4714 64403 26210 10802 39494 34242 31233 6587 31484 2218 51612 33832 35194 18786 4819 39106 22047 48511 57377 28884 21184 47069 49966 31388 31244 6622 36013 46776 38700 37890 30018 49711 24490 12034 40968 10419 11754 17964 27668 48071 17291 12354 6894 49481 10330 50816 51719 23187 57219 32892 55732 29248 37842 44145 40380 47896 27445 56511 62251 53116 49119 6863 7516 29590 54261 54870 15890 56396 14153 9051 33958 51369 53427 40009 2699 42112 44216 36954 16956 213 58919 88 12902 13445 53327 39172 24800 7562 39567 5490 34610 62965 8881 37493 29936 10699 61584 61102 41655 17532 33358 40941 63995 27578 56387 30403 35794 45698 62211 4713 1455 41100 20152 16431 62008 34282 20017 17937 57519 54349 12257 9589 56985 1395 31451 11205 9012 34339 2977 42367 37743 179 17352 48331 29276 44097 44138 3126 8298 42859 15394 39557 35676 35431 43572 6983 58518 29488 30880 27452 33394 45261 22405 39123 1334 63899 14071 21112 30294 21346 59242 27607 48404 22356 47863 33040 59511 2135 48006 55596 25894 50607 46841 61303 39140 19083 29970 42199 55165 24957 53870 17915 47359 21808 10516 41887 5625 756 36671 2234 59306 17896 18601 1791 44007 9591 55912 42919 12242 19214 46525 32946 57513 1872 63055 54214 2854 21965 45431 4943 30649 40097 55086 10034 47405 61750 34252 2790 46488 56544 54852 40745 5115 53508 44201 10056 41000 49733 8583 21835 23231 9714 21897 31060 42500 61415 48614 3510 49708 51695 56442 1290 55552 3909 53769 161 34901 58098 33603 13275 60179 58165 47086 25263 30825 11659 11781 15821 39287 63742 16005 6838 16970 4415 11446 24862 3362 2506 61755 22993 23045 41978 1742 61956 4350 47469 30053 42856 47096 43869 16113 14734 5508 41094 58973 43440 44975 31333 34803 56206 11663 54019 43607 23682 22738 31632 28472 11626 29267 5725 24252 21942 28177 52458 64083 40059 25740 52576 40235 11019 27202 4259 39649 60909 33684 42364 58467 36074 13547 6898 21457 55522 50162 27932 31148 17092 15737 49459 34146 31224 41286 18546 25993 42641 42614 7515 18686 10404 55705 49395 35753 57347 47122 54204 61637 12474 29004 51763 13843 62231 53646 41893 4623 8301 64190 26314 18018 61565 47779 56123 337 29747 30171 60646 50321 54047 62770 3878 2200 15001 10473 21505 63482 34848 7534 21764 3117 21585 16248 61983 9560 874 39164 21876 48673 51645 13304 52674 44809 38224 16611 8724 1952 19505 2488 39925 16155 41832 8723 61664 11660 53904 23719 13434 46620 40663 63033 63037 899 57545 6406 49517 8306 56657 54695 39001 31058 5407 50821 42621 13219 30520 2601 42810 30935 52440 6772 46005 26896 40072 14842 50266 59988 54562 8921 30176 43150 59162 29418 58686 16397 27401 3737 43467 11673 59878 12849 38154 62874 43672 44788 47721 37416 8085 33500 21346 53459 836 22895 10006 16141 9530 59411 30382 32835 19423 11450 24398 40370 35876 58872 38662 38442 59916 6019 27998 34407 12434 12799 8697 34468 44740 22962 5091 33220 18732 13601 1342 58293 60702 26916 46983 13593 9755 5284 45153 9916 20690 43655 53933 28228 53590 59336 26641 41409 61378 57565 45653 28986 23191 36698 48395 31394 42156 23903 48717 8550 45402 24560 58020 6044 50749 10588 50534 16533 63948 20165 12370 58946 54108 28016 6768 54473 11465 26380 55298 55518 61675 19379 25636 34543 37898 27400 35124 43100 60026 40157 8602 30576 2124 5274 49281 59366 29887 41889 29547 14466 44867 32883 57652 49180 14056 29622 22701 5096 59431 56663 11668 35863 21397 57313 50007 56551 23188 1791 35972 59218 59426 58277 16915 30929 22640 34963 45872 13433 57563 45444 18943 61904 60961 58658 16498 30056 43324 20739 26564 24069 36178 7943 11216 62026 3239 7400 45593 43061 43960 33473 673 52781 60946 43936 7275 2890 25906 42181 21551 1376 36676 1119 62619 48351 56203 31143 18413 2708 51610 35970 25253 57465 52224 13811 694 45114 36194 16247 24938 16934 57599 24192 54002 44346 8043 9640 64047 21460 49270 1316 32990 63695 28398 48012 14722 43351 29108 26790 38692 28928 30964 42820 60311 45776 45419 58364 20675 54882 31483 13816 21515 20917 2140 25750 36861 53312 58660 39118 44750 46736 41393 30107 38203 14085 60765 57943 39463 27761 14399 43482 61666 25391 20297 52673 40436 15558 28586 13863 7072 53421 7707 51359 39831 30144 4367 45732 51976 7333 6078 64316 63819 18058 36797 40660 53959 22785 26385 48679 9376 47490 28411 36700 57868 62005 40031 38803 27750 431 51828 62272 30442 58025 19755 27399 48677 47016 12729 21777 3422 44771 58417 9824 17025 13752 17298 27575 14126 60626 58531 4235 52877 39394 26036 13607 27350 41545 62724 36087 23380 3256 26591 4777 33747 7654 875 50676 52307 47364 26697 38963 39630 13380 11588 38806 11853 5263 58360 43193 49815 64081 15922 39516 19690 22120 24104 30381 46345 15483 56882 59833 8750 7428 46080 51347 12183 21371 46824 12784 16312 63815 28347 4722 58049 44649 48315 21252 43890 51127 16148 7717 7420 57855 2217 29762 30694 46326 26212 55205 21679 64250 16804 11387 29565 14281 15233 49160 51415 9010 53707 57300 55769 36756 13586 41680 24933 50184 56456 6033 6752 34322 26490 23907 28428 21240 10728 357 33563 34910 47632 30886 29235 52724 48458 33896 49515 36089 54461 12603 22724 41581 58366 18788 22541 1624 62540 32903 59790 14957 15070 52621 39273 24715 27707 2081 27516 14825 43198 34288 10959 13937 19034 57578 52382 40239 37413 44770 37755 9321 16330 49257 8891 57327 25949 57447 40444 5704 15069 39824 10211 57059 27193 58941 18915 32829 29694 15436 11230 60779 5134 30862 35511 35370 53122 64061 19033 19083 62678 33087 45129 29008 51055 61790 60708 39013 33315 29069 37839 53029 26325 59752 63108 62684 56470 22637 9793 51762 31443 56092 45765 25509 22256 62223 63596 35566 22481 21028 12163 289 70 40410 41481 29925 48474 26096 28444 26239 44032 594 53064 24218 10691 13022 41459 35844 42752 26186 41743 14326 37533 20376 34701 29363 26305 46901 39681 48330 55899 46681 6879 51110 22273 46666 23860 30340 59517 8631 45381 18609 39605 24670 53024 12078 50532 18172 46498 29378 44715 36240 261 53011 61282 15757 26996 60967 10877 25003 56848 9973 3270 26635 40446 24779 19643 33566 25932 1184 63280 26307 46195 43941 25670 56710 40647 7247 56039 24610 34704 38961 29089 1319 11639 62227 50005 21660 42165 58804 49976 55741 48343 1492 23956 53757 5908 41048 50255 59168 56954 51632 33230 60271 16054 5343 5713 43314 54027 12620 45744 34367 61681 37568 55002 45973 53152 64307 14410 21089 46002 11156 20158 54270 57380 2443 21052 57996 6428 25725 30874 33453 48048 54078 47936 24218 58085 19818 51334 17907 54690 12291 8595 13586 1422 46915 7684 61340 23446 34977 5940 39360 8638 60868 10116 5606 59646 62856 40507 29785 10112 12514 790 19422 10927 18653 6542 14590 16456 24148 45189 51268 44118 33915 37740 42212 27468 52770 43264 64208 31347 59342 16073 24858 40290 31059 58546 8618 90 52169 10277 26619 23971 48513 62738 50796 5574 21724 23056 34657 35352 21115 48758 22428 16338 4148 27869 43860 18936 13381 38843 20912 34204 62694 10798 17886 56029 57145 23911 50546 40177 63096 12168 19076 27328 7846 55101 3529 33506 39164 55313 23423 34814 55338 19803 27348 27756 46645 3545 177 57298 58814 62570 37469 27702 4999 22424 10879 5950 19278 30138 12026 5216 60343 4874 60940 11126 55907 44020 11368 2147 20051 44807 49641 21294 60509 13746 28224 49492 35779 29390 42067 7744 49890 29073 22308 8426 37993 49051 52614 56980 39073 57461 45483 54625 38318 4929 61839 33627 4688 3474 29287 16090 23707 47826 47290 1317 55446 48637 31317 12354 51746 1198 30896 56705 21570 42610 15251 42777 16214 21518 5682 52911 42548 15899 54534 43764 53446 11253 39769 28132 49551 46880 31386 63 63919 63944 22835 3896 47106 47839 21473 54868 22081 47769 43913 51220 27740 22245 43545 36592 38643 25023 43932 46148 21904 29542 62323 36872 53904 28797 64330 13903 27891 26417 52935 53492 46892 46669 46691 15257 10836 51014 27496 58267 50458 4752 33553 28794 62301 37849 49450 3946 9348 64228 23994 36901 44477 10491 16798 57342 21417 8470 47118 53736 18358 640 59799 19145 17787 30353 34549 43188 12187 55881 64162 49488 33121 58406 30031 40281 2936 56710 25 63051 46875 4312 43726 7351 25443 48982 45888 16726 15423 37627 23018 158 27202 5358 53199 61655 34325 9560 54837 3827 26244 45325 59012 35022 5447 23040 28309 60311 57889 42045 54024 9525 26290 38387 46852 6885 63454 29654 64036 27914 24882 27717 2436 53949 34720 39889 43693 53820 35906 14353 26853 58154 64472 53656 4719 2016 60893 41900 5845 22055 36982 35621 46474 4286 27677 45086 23006 24432 58668 55640 29557 19205 10955 63204 5008 7865 50870 34914 51624 18912 37524 38632 12123 19672 21351 18882 41879 22433 29426 23872 46453 16114 48716 23604 56475 57546 35057 43223 18035 230 14011 60599 42535 38365 50067 8265 62104 1374 43244 57076 63749 31527 51098 30000 17128 51356 48609 49702 5801 17010 26782 57040 21312 62766 61089 13824 23004 50043 38369 29916 22221 25004 63793 58113 48564 53008 11463 34287 13274 30379 2197 51976 16768 48773 38236 48300 41211 30093 29476 38315 16492 35882 46077 37587 59970 55324 47261 64307 61009 30869 37497 42235 16216 35805 51526 29768 37823 20530 25329 52114 26303 41857 48513 53409 11071 57226 41778 26626 17414 2554 51271 5919 676 47185 30053 48760 24607 50733 26960 22840 11578 48469 28212 43753 17522 50216 59801 3356 38994 15291 9630 47601 48097 31692 26027 29288 39412 28995 25424 26596 57066 5216 34133 17822 44731 37474 17266 61442 10355 8751 51351 28761 56755 55140 60069 55841 16470 626 49108 1604 33483 38385 48731 5325 17110 60919 37900 11608 47853 29498 63511 59788 21446 18396 54633 10309 10844 30210 39919 30242 21304 25453 29001 44596 6734 21804 7944 54866 34264 15419 52892 22580 23474 52311 53294 62077 13093 5520 2887 14679 48726 14110 5495 46001 61987 31721 17592 17506 13003 62458 14115 0 3465071004 +1024 19553 16619 43708 14093 1055 44505 35206 36043 43980 34708 40409 41254 9205 63048 20036 7741 53838 21571 64012 20924 51614 60586 47646 46412 19210 26404 8593 17043 21796 11449 21894 52698 49400 46977 43500 31311 35832 53019 29948 3058 19531 24191 26946 44842 40069 46237 60787 46915 16576 37743 51259 48515 61358 60693 16984 25736 29519 56953 46816 25703 12040 424 33948 9199 60948 31656 53838 18661 60093 60007 48721 6486 22267 15152 18933 11753 55659 47690 12896 30656 43147 42089 6051 8409 7721 2015 9005 30973 24882 6828 35102 10198 4802 16217 11393 54774 13732 63660 28516 25583 24667 14546 34972 23365 15534 3992 5931 6324 22422 7190 6881 43387 43608 5340 47723 7726 40776 7204 59122 60469 47290 53749 5472 4851 43173 43577 30676 62417 33342 41201 60956 41209 41541 63833 52598 27281 28836 59663 6119 54707 20752 29654 44964 27695 55498 15683 10744 27987 51713 10156 8560 43151 35576 58303 33683 5696 57614 21233 64077 37149 6907 27683 34800 20458 36585 12201 1170 44041 22018 14159 23905 50476 20628 62905 34894 47237 14869 2871 52109 15551 52236 37298 35788 31653 36978 19433 21044 37688 12596 29319 49867 7317 16461 57274 26204 60693 57055 10262 29335 22178 44811 11605 54505 52923 63215 37983 18150 13613 11589 34319 38539 56933 10712 29130 12123 24251 1268 42817 63690 17458 55949 56350 63310 63151 37741 57010 29734 17923 26196 36793 26770 62975 47025 28670 54091 54293 50003 25012 53353 10498 50641 30801 7596 5233 13237 28741 5539 1600 6492 35591 18853 17491 24621 685 28476 62204 23378 62093 35257 58767 29991 54000 41070 13197 11400 26311 33261 1481 38619 1099 24000 44477 15699 1071 33292 41098 56556 18026 31150 14753 62032 12146 21507 34614 58761 31505 44959 28267 41419 49341 46101 58525 37283 51274 30706 60884 61042 54910 46346 48355 51461 42179 13342 26527 34504 33164 21055 13630 31462 20401 53968 41172 16338 46716 1156 25973 58007 7428 29925 52879 19415 51429 28101 50615 33550 20934 33867 18223 37385 61130 1442 34903 29895 42447 13051 28920 19818 29730 62748 14487 5734 6656 52370 20512 54836 26383 6213 35729 59994 62968 24993 40982 4752 27302 17056 19005 35726 51734 5973 25856 46238 58427 45023 57414 49908 16527 52010 2632 1119 20022 49803 35063 41588 20283 56552 12045 35830 58575 27592 19050 51184 33290 22488 16191 2167 30535 39688 4525 42559 33944 35083 55745 26937 27062 8557 31313 11539 63214 5064 39430 43052 16600 48902 12766 13698 20687 55490 1892 35547 51111 10729 38178 37592 60195 49250 54113 42608 38904 63280 38251 23598 1629 42973 45890 35778 16621 49844 40033 28950 31342 5817 248 16121 62102 54700 58536 55441 40645 22611 5966 56865 40279 5681 15139 2228 2585 35639 36881 13884 9979 46425 31634 10743 22928 47512 13284 37004 57475 32833 8011 41022 56849 9090 59319 42557 45144 23632 51222 54100 49015 8564 25297 42911 45989 50656 56976 63634 41675 4409 47097 30281 7218 23395 61768 1741 5793 49474 35000 30733 29135 56041 34565 37150 10657 48400 43362 3131 38661 40501 34176 17614 639 57625 21260 28342 50351 6275 34878 18005 30960 62356 49970 10508 20989 62994 36611 3885 47135 23978 40905 52788 59608 36439 46797 1889 19694 30496 63820 30828 9771 27062 36219 47277 25968 56134 33176 26008 8617 32834 50882 39277 31462 33321 50930 42116 38421 23434 34450 39800 54778 373 48007 29598 5552 61328 37845 1244 23559 63093 42751 6039 43912 12620 36741 6679 52815 22233 45448 45067 9544 45558 19032 20247 8941 13978 43681 26636 38003 57634 17458 31267 30623 18924 62251 793 43163 25356 36690 58640 60981 26505 29498 34915 59388 7215 60994 20869 49855 35801 3074 58678 29699 5817 10286 6716 9252 44563 6951 60510 3858 29958 7264 43215 19707 58813 21353 26841 53983 25308 43518 34456 39735 63767 40990 15804 40500 45880 40612 27313 28517 20002 7555 53541 31607 30952 49433 41122 37872 51128 4787 49845 24970 20323 5128 14661 8830 48502 36095 51943 3151 34509 13328 55961 35787 63894 21063 50104 45970 14077 34892 22538 47322 11367 17709 28144 52310 62519 47612 21761 10615 33343 13186 44464 62705 29266 11409 52771 40097 2293 18178 7041 23192 24654 51950 13288 37003 62972 47770 36502 53051 52449 55665 61022 51523 42339 10314 45907 56471 52724 62475 24541 26871 40944 62065 61848 37997 62789 10324 39909 45352 14506 56207 43911 10849 24033 49724 63958 20705 31450 320 27356 5178 19756 423 61838 24296 54383 11216 26589 14074 4081 2655 23150 30723 44066 7746 10452 13775 56258 60363 37725 44193 31726 25935 19516 43187 37927 7288 33773 12636 40694 46605 61836 63559 2204 62135 14033 61468 53159 47958 11649 37151 531 46746 6135 34010 62249 40178 34309 51166 12483 723 40335 15858 20444 35310 29762 56144 59785 35648 24609 37962 31581 12598 24686 45531 8042 50009 26372 41276 40464 39444 15138 26954 19059 28549 63135 10223 32960 29010 63861 7891 41606 57408 53459 52604 37245 46051 28103 16740 3793 17809 61649 45448 23741 1744 53167 60441 12111 3789 53683 59022 2322 14816 4920 37287 29953 1369 7671 58694 14540 20641 15513 39270 40217 48218 4954 64149 11970 33416 43329 50273 54104 31402 23809 21701 47834 27255 59772 31288 20157 53471 62353 40564 24700 39555 64254 3016 16879 28195 12347 25883 20569 1022 37995 17200 29942 42110 24595 9655 2201 29330 19137 52214 39548 28753 14283 36528 43008 42290 1319 1351 42018 61888 61369 15827 2977 51039 2738 36098 51662 36501 59459 26826 23927 2621 57069 14296 42241 31425 27655 53948 53796 20237 45660 55060 47901 22238 48917 59068 62167 42814 62424 42882 50348 58333 30882 36271 11319 44843 20796 19530 13454 38048 41066 61345 47022 47519 39609 11858 12248 47171 45023 29488 6917 49623 17229 20297 20609 62446 27841 6398 5749 54785 6982 50004 32912 30966 44499 31594 38351 34369 27236 57361 41208 12423 40727 24981 62233 41054 17943 55922 55116 33389 39053 18301 32954 64238 54736 4529 35044 22749 11631 17301 41449 1160 17686 31138 26473 55019 2618 44359 35430 52821 41522 685 59244 56660 24023 14417 44771 53816 3798 35065 50474 63776 17815 59030 15146 60304 53605 26860 44022 9543 40273 35008 59255 47989 48908 53822 40831 45695 25607 36680 64075 54085 7879 63238 51281 40990 9557 11471 37316 59882 61082 36565 23252 46598 41920 37395 20438 60003 33643 11313 63514 50089 7524 926 53070 26810 54902 15417 6642 50303 61985 21840 25347 11675 37961 31261 21495 49799 485 46043 8664 47966 21209 426 45375 24935 22541 49996 14733 56503 24430 59047 38320 48361 41381 37236 55254 39407 424 44643 46078 26808 15372 63827 61801 21226 59143 27682 58936 59316 37409 46829 63215 2490 48867 19411 16250 35242 41584 2230 5389 59001 46494 22735 60079 47622 10853 2656 11438 1670 62188 18194 20780 14734 46811 15434 7301 884 56008 38384 53228 22198 41895 38853 14550 62548 33730 16335 38764 55505 36261 13812 9089 54786 12691 30157 61394 50002 46961 29554 16752 10036 10303 28958 40466 52586 12001 35871 48425 55982 21394 44610 14659 41292 44297 57086 25989 3109 11552 54667 22959 3721 41711 13612 27631 63929 5764 40778 24743 64198 44709 1345 48788 38430 28329 31598 24747 11829 38187 27915 56507 33248 49244 25643 23447 60460 19224 6429 30729 3636 5523 5903 41029 2145 28980 62675 13833 10856 43120 4469 9017 31324 49622 53604 8499 47968 26785 14755 48460 49960 55504 7866 26960 1158 5293 32923 56068 54384 18998 5443 3757 60201 33926 62955 22440 39122 36906 61816 44481 46339 61023 36424 10596 18505 36451 8669 39932 48213 24934 54322 44265 31244 53923 9742 41007 28015 24757 56578 60453 45836 15084 49735 35025 1705 36678 30319 7567 18189 36718 42708 37908 45297 50470 23320 35481 44153 62409 18676 25591 28431 7637 14997 55363 17134 52069 61082 58092 54859 27065 29419 40777 26301 38407 38901 43140 3516 32850 16755 1852 52328 42619 32832 26306 27776 56808 60618 17496 48344 34490 44041 32991 27343 52574 28461 12743 46518 13527 40102 33428 33592 8692 13099 38348 29821 4136 2334 35716 9729 48487 24759 46830 15430 33355 51781 50987 41797 5895 12472 6861 39136 42390 12008 14329 61860 38458 52862 10328 45839 62109 18784 12645 28308 58311 965 33030 56429 16516 45725 31461 18922 25739 38664 42240 1326 21792 37833 20730 43141 14864 25033 5631 19676 32980 23656 54929 8839 62038 18727 20681 13714 35787 869 34289 45527 60442 53252 3654 11707 8453 47802 7293 310 62170 14158 55577 9890 41803 30694 61028 52202 14602 36487 23048 8241 7037 41889 45328 39098 12617 14243 26181 5910 6390 63572 14249 35918 31456 40308 27282 63106 54830 14288 691 8849 50474 46859 24133 41978 35507 38458 12826 11932 54109 22642 3535 36700 58300 54297 28594 28687 44700 60951 34128 47745 45248 41171 38554 60525 16127 19271 47503 54898 18142 36987 41897 25428 24610 58031 23150 9739 46721 61847 37064 14423 11630 5430 35867 25179 61445 44536 35980 3556 57473 29693 5052 46801 14211 62158 33171 44183 6223 20369 47795 4275 30662 54111 28448 1291 41606 60131 59002 39981 16114 21368 38635 57361 14018 34049 43031 41011 22129 40998 55868 38781 51889 5794 48850 3097 47887 19260 25014 27503 6857 14498 56136 34778 60897 49225 10819 46212 21332 11323 4192 34665 24092 57191 21768 22564 15133 63815 10458 5424 4353 51204 23948 16612 18179 62745 12941 2813 41934 17647 25897 31275 36161 27350 43670 51947 31445 48261 56273 8335 54568 51635 6381 42858 23567 30018 38431 37123 62199 16131 9852 2428 7549 53926 25401 42742 12989 9385 60339 30427 13009 17977 33620 17332 44550 23611 54203 35969 2864 38369 25983 18639 25791 37442 35616 7404 25299 47673 11770 44283 49514 28809 40626 27282 36614 5688 34462 10781 41920 60480 42724 54521 62259 48294 46945 25982 42150 10338 41437 14154 638 41672 4130 9758 44834 63375 29241 58483 2454 61635 56205 1822 62625 1389 21387 57919 59441 52685 25626 11082 47638 50576 4114 27829 21695 45354 60629 20305 50777 34155 27166 44117 25721 39019 48265 43785 38524 44313 60773 53438 6530 11387 50568 18425 17670 58586 38159 19941 40061 40618 38271 5200 12027 17953 21192 35691 39243 34700 44576 16047 11931 2862 18417 24091 17205 1325 39768 44678 44814 20905 10185 53814 62570 11345 34678 16585 1162 48625 9107 57893 54291 13695 27070 44962 15098 59914 14328 34911 57396 13728 3661 1841 44490 27223 34660 47541 51328 57080 11466 7034 43754 63781 29448 61841 17195 59255 44285 7929 45619 22911 11048 28609 29535 57993 41047 47021 52391 18565 36001 17220 4813 56460 10443 61527 36694 13814 36126 58494 45680 2418 59802 9661 9955 34663 42284 29494 16064 62331 14782 6720 45442 36121 14585 36906 8324 56570 27169 3014 8000 40791 53666 50389 37861 50353 34522 15882 62661 52912 52379 46380 40086 31701 42258 20432 45109 45143 8869 19646 41277 13266 35914 55439 24848 21663 8463 33366 34009 23227 6345 34566 61692 17107 20116 58256 27495 26852 26466 16377 5972 21218 1628 45531 35592 3240 11634 6428 47573 34207 33127 41400 36399 35817 20849 55284 33456 61428 56746 44661 51556 44989 21052 6391 45104 3850 58069 51381 55104 51170 18215 16756 9420 9353 9312 29030 17650 50630 344 27518 40378 59978 21975 23724 18796 26412 28585 52163 57935 29223 46914 61445 8057 38950 37917 44538 21389 36900 55166 21765 2897 60514 13882 51467 62486 39553 47537 16927 26408 30453 21302 52689 64060 26261 29458 17127 52736 5573 55702 27495 20788 25163 2735 35115 46669 56139 20027 40642 60676 5513 58254 6328 21812 48371 18988 8933 53157 41305 58511 42513 21788 2247 53877 54673 20268 60236 25019 59875 29846 26321 3191 34818 39249 34007 47696 42049 37540 29576 40582 52888 56183 1015 20210 28796 39531 6643 45603 56393 63605 57901 22381 7116 30351 6350 12941 47673 8194 53660 19368 17919 1632 57536 27176 14228 10835 23046 51248 29395 31109 31026 55054 20338 44336 21894 39323 8113 26199 54769 62380 47120 14312 40113 36919 10137 59685 27442 8282 44340 52297 59141 25077 62864 59947 10455 61179 17255 49121 10227 31366 58069 61987 7128 26868 22923 33061 742 35452 35611 208 8412 30351 33752 52827 33130 52694 168 3550 7765 42473 60168 22340 6836 34494 63777 26433 20370 33387 62431 39376 17169 63625 63098 10875 46210 37533 56370 39518 1277 10201 919 903 1663 7508 8222 23236 17933 53614 10730 57864 47101 52623 45434 48919 34393 39925 15197 32795 17151 46410 56803 20464 40873 3283 38894 19011 47776 58941 10211 43149 51036 19235 10820 23195 38155 45369 40033 12852 46239 54044 49150 4101 49135 16286 2856 0 1324235027 +1024 38495 7428 22456 55500 31402 7063 25807 42821 30425 23081 43634 33012 17215 61677 12272 40222 7661 7889 3970 33562 63288 34949 15036 30997 15583 53504 16914 19830 37672 17519 25059 54513 49897 43600 5778 26401 53949 4898 57855 15835 9122 23556 10193 10803 24192 43347 1425 16451 10106 27207 50870 52116 39114 36801 54536 50268 27072 42770 1998 13366 664 57543 44381 11940 22730 57071 46676 42369 40180 4652 59336 38128 7026 12060 51235 4868 51339 7485 55145 23690 16970 22311 57877 49982 1719 31241 50043 17482 29317 14734 19396 10888 8694 56351 5429 1379 63668 45628 28793 30114 16736 20284 4675 8090 42358 39996 34877 34514 37696 20609 9893 41359 52135 47361 27700 9816 61899 25119 8331 44259 17985 8915 59264 13881 57969 51861 57294 35227 37089 25149 2643 47857 22917 54624 5122 21188 53708 47836 49990 3998 678 52453 42159 49674 3652 25167 20565 22872 6521 6451 18584 18757 10811 50619 37760 59412 4746 57737 61489 10970 6484 17647 25302 1682 58143 56567 24101 49653 23514 9027 47676 46542 53609 49129 4404 34925 39183 38490 27179 17669 3240 50338 12056 48966 5909 36148 27285 7116 16881 37029 21654 9711 58134 63014 39824 34164 16922 10167 20836 40084 27387 43996 1052 929 11623 34716 45347 12295 56071 8590 56739 53613 15506 639 52296 55666 38847 40075 64109 24894 45474 60013 47768 53441 35118 58616 48607 17613 3534 8051 63537 40129 2103 22918 19266 8357 51696 63567 5089 11294 1965 61796 45421 39722 61400 55365 2851 14981 21224 807 50316 21337 54300 31722 21864 15259 24809 16756 24644 28248 40211 44706 43655 36008 41634 44339 32803 55200 24523 57040 33357 2875 15123 12894 22402 56645 30892 10188 61158 15841 12043 49873 60791 46871 38417 34418 7492 55645 40074 45 51451 23957 1995 12192 59431 40751 10006 9090 54388 4308 46431 17001 13045 2511 46465 41915 39001 33784 25026 20492 25788 50010 57977 30478 51653 26631 19950 14330 38650 22534 7202 22004 33048 34610 27679 46674 56724 9421 24400 37376 60825 54291 58860 13150 36 35955 12204 36960 20484 7802 39205 47220 22319 43743 57515 751 18127 37609 28764 45623 9852 55847 3796 35652 2293 44407 17462 9367 47187 25051 35691 57900 58922 2592 35065 36635 44312 30767 16856 58313 35908 33006 10402 15431 30689 16882 59161 26550 8340 6737 8733 26905 8013 13043 2657 2153 43481 63788 43794 19544 4804 16085 30576 59879 25569 64166 22512 51145 10025 1100 38225 37770 38068 57551 51465 63116 40371 55742 9047 7574 6843 8221 45654 43981 16449 25420 12269 29702 9163 8452 51174 18260 6810 32916 48683 57845 25775 55650 22732 16963 47543 52960 56289 11213 19399 58567 912 43860 25106 14479 670 25383 23093 39530 56317 61979 58762 53049 6869 43674 910 48641 52603 15218 29079 23680 40698 60635 36662 47335 11666 47375 51849 46437 5547 61383 62192 63839 20755 21236 41973 19217 57277 50276 33552 8836 43973 31451 63352 22302 60099 2993 40612 11819 9982 28058 13403 39890 62579 60906 4210 38388 58521 1380 44469 7660 19363 30038 28850 30591 33116 6018 42532 22708 10625 53686 15067 7759 21589 27762 37509 29029 55288 20755 62978 10739 30873 38527 51415 27320 8740 56661 49286 19159 40815 63915 18285 7598 34103 89 2573 25438 63799 62158 15210 12208 24028 15496 10069 14598 28336 8518 14561 10025 31713 10306 15868 57233 54291 62156 7986 17232 55659 20162 60840 16462 789 50076 64272 55364 14528 60368 6634 55261 18930 22009 10814 8070 51885 35892 35543 4409 54705 55827 54815 49582 6315 51437 36052 34960 23852 41238 9939 40972 35130 12605 14869 11805 8668 42524 24207 39444 53168 61899 27700 35958 34449 46635 45062 3678 51603 37543 18608 44092 27250 54088 9320 33373 64429 59916 58120 49079 120 18406 38072 18960 51417 31655 31013 132 10753 33214 56249 41322 37736 17220 34137 38435 59952 17806 40030 47247 21828 44554 63272 50694 48506 22850 31195 59573 39968 17993 34247 34825 49283 45363 15956 13682 8952 59551 63359 55605 39590 6509 54144 923 18053 15587 14668 47229 14642 29939 19470 42191 7469 62199 57402 34220 17586 606 13751 46570 30499 50556 46962 11134 858 22354 18704 3248 43501 39263 34350 1082 60134 19924 6657 17758 36651 4825 47820 52626 10587 61950 29986 64142 61146 47763 8404 48906 54404 13586 5577 37108 63141 43479 31336 42860 17964 4356 6659 48882 21943 50676 36716 36660 5671 53477 36103 36106 51221 33756 61272 12642 52953 33179 50356 37579 24569 30047 37711 23609 52128 63675 39662 12458 53557 53206 33650 28366 16065 24483 35381 18102 54340 46432 53763 54323 21162 30299 8550 5910 42637 24051 11897 9452 61585 60704 50900 33477 48986 18783 8400 29211 51022 22102 50686 15141 30663 16704 61762 27140 3031 35007 9125 15083 39843 37180 27925 14925 27757 24899 27897 56099 59319 15718 9414 58112 12052 54576 21610 38243 22102 53195 18430 43535 53174 15825 46273 38331 49324 41891 40073 46018 46685 5514 39324 54018 19989 25628 15610 61083 64003 22214 23313 6334 41584 27470 62571 52148 55494 39981 58567 27397 3185 40231 41744 21605 41989 22451 40716 42148 18451 58085 11954 5282 42354 47582 2527 55434 26202 6213 49620 38494 1519 62686 4379 27624 41128 20782 5670 31415 48382 58356 58941 45335 14699 43233 49072 39315 58868 30459 44939 17755 46852 26680 23335 63922 33649 45458 47566 49320 41939 47359 31261 55399 34971 55072 45592 49851 20845 8855 9682 38298 50876 39552 63818 23017 38556 52968 54249 62642 19405 7984 30787 2035 741 27313 9493 34661 12696 32824 39889 8749 36504 40187 31285 27612 56665 28658 20406 38338 41451 62948 49371 46886 55296 57807 13543 63402 36878 49655 25786 14159 37592 58250 17094 30726 33194 41105 63116 54313 25165 60294 33151 9385 55584 10759 12699 60333 12950 14942 32973 17798 59395 28963 31737 36056 45572 47123 17927 9099 49727 61246 14238 23718 52895 35612 3127 44934 15321 17861 46485 37423 12795 39381 188 3537 51624 32982 12472 38903 51222 56249 49927 53082 62704 39530 46013 19790 47055 31611 5248 58187 21531 42009 13700 15704 23078 29616 35584 59024 40347 7393 20297 62797 4510 15441 3516 60255 20572 39890 18430 63769 10850 56717 1787 35119 38044 11640 31352 6813 54848 49375 60096 34213 60515 48296 27494 60376 10064 35172 31249 52925 17672 60165 8187 6682 54104 4096 41275 30057 25977 5644 60229 13214 16867 16678 11645 584 13650 42304 21303 11114 6283 35081 36700 26524 35596 31352 17860 37689 24836 26633 30762 32988 42788 62114 54255 21151 36606 26455 49898 64258 23932 45221 16106 7642 5431 39223 1522 19476 52715 9471 20242 60332 23034 2517 26878 57723 29611 38662 17000 17219 12041 48782 24091 12311 29988 48353 20343 50021 42541 64424 34629 26737 28226 2281 39000 59596 48903 12056 35749 25330 54007 36654 37995 8836 2538 10885 18433 51384 15554 60049 28101 62924 2989 57827 3099 36209 36364 21966 52539 46878 38064 18151 5205 64299 24708 7563 40297 53244 61977 39257 42492 33090 50045 19045 25767 53034 5845 39412 58738 11047 34278 41685 45438 31692 63218 63160 14048 47176 56402 3315 30366 47476 1688 23542 61823 43866 58069 34478 12489 28079 20569 38393 25873 19289 61135 664 24266 27532 49607 6505 42568 20801 42767 19018 27534 25225 29550 13642 26652 30304 44453 51282 43792 23379 45107 47667 29971 19321 52526 18947 50122 59895 54611 41272 20928 33924 59136 23773 63360 42661 18371 30204 37982 49247 20510 5748 63714 36274 62860 59270 57608 47647 50406 43266 51527 9345 36600 59507 36955 17204 23491 16418 123 7019 17114 11419 23887 60602 21217 53801 49895 9839 14424 54562 10155 39526 64452 55844 59128 30835 38008 5685 59756 37133 45046 11495 30876 19795 16301 50372 32987 38847 45302 35341 16575 59411 41584 36958 21816 52404 26160 35896 63864 13197 579 60319 57865 52433 14960 26673 20070 59506 5083 62586 16153 50084 17925 39921 46074 29621 28406 21714 12248 60173 61653 51594 62233 42390 27365 732 26363 62833 52865 17790 41021 60846 9086 8740 25244 4237 20162 52131 16392 4981 59233 22300 63661 1542 26243 45910 31468 45519 55076 23425 18686 24625 40650 37204 33029 48875 40053 56398 45523 22188 4634 31646 62095 12992 28270 57576 23471 34214 57346 6239 57370 63693 54931 17452 12006 2431 11187 24420 52825 39162 36082 49739 27839 24033 57925 6161 24155 55936 57236 25423 8138 39799 36995 7615 43448 60962 24131 36328 61530 45313 10145 52352 18639 9503 44112 37616 31085 5163 50580 6432 35813 19592 41474 38659 48210 27702 54515 29663 12765 46292 10089 520 55055 6253 40699 22883 14914 38850 37473 9912 6106 57166 52806 56268 27053 29819 53479 11765 51538 5186 19248 35474 40834 24908 1850 46420 10641 13854 3860 23391 36194 44613 49646 54998 2426 53205 39625 45873 28987 52658 49241 43350 19344 56411 15096 36078 17745 15624 4438 62051 7388 10320 25913 418 10610 21527 46842 9401 27909 25319 37739 59893 3844 52056 29839 20512 57597 37976 16047 38743 1365 56823 14422 21280 47152 34905 22774 22131 56075 12436 1201 12478 49978 23084 59732 51037 16501 53390 63690 56937 20667 16022 63287 4400 53627 33287 18400 6213 53690 1433 40360 58262 11917 19814 31571 45296 36611 4618 20716 55542 19888 35438 7025 11026 63929 12896 55157 7427 26876 54526 23569 63192 47795 16452 45259 45615 19707 31231 28736 45593 50300 31382 18226 5474 23762 34060 28329 24156 7521 36969 27546 559 6983 25973 38133 59982 17412 58054 45409 697 8635 39491 4643 60781 45700 50347 50282 46002 19611 61650 46672 64084 16086 46518 22816 41312 57448 42841 35362 28016 23629 16425 4922 7172 38195 36425 44204 35020 50992 11367 27235 39152 942 25628 6953 34376 24542 36362 64043 62012 3844 47043 28175 191 17461 45782 18056 6267 55079 53594 47261 45235 5117 21742 26160 11006 34142 34048 59723 418 59147 1480 59519 22964 51456 54267 64358 52677 20037 44027 51834 40140 44903 27593 34211 45914 12580 7446 46339 14365 3352 23696 34516 33929 29420 56875 34998 21600 36592 51389 52192 53852 28827 36207 13093 43452 25669 47208 36929 43347 35717 13431 7044 24469 60564 30572 15464 10613 723 37557 27413 36906 50146 10446 62213 7905 18559 396 29126 43812 43695 14529 56849 23133 42123 51602 6714 21110 61167 60988 60851 25119 22392 26553 39546 50360 9526 43999 46946 24303 18628 62234 1154 61992 17139 9416 38598 49198 4310 32873 43384 244 29721 6861 23871 22037 29470 14303 45794 25205 43860 43482 38591 14861 50755 45840 63547 62637 264 13279 38992 52017 26610 37353 4207 9380 14466 59582 38710 526 60629 44885 17232 54001 1493 48205 48438 8581 16815 7435 36580 37419 39012 10329 13822 13258 55246 38503 43759 40315 53307 29526 33264 28153 55281 30203 10203 13790 40047 49279 37746 61522 58559 45781 44624 47652 54076 41112 61547 43102 29785 84 58078 45040 12760 20243 23801 63295 27164 3560 7723 29608 24128 54515 1618 8855 64323 28335 10279 60127 59121 36288 41747 9627 63007 40726 53603 39944 17893 22670 61215 62377 3103 35977 64429 53418 24789 25601 3730 62705 5663 43113 13747 14326 2116 46823 23603 15595 23355 23822 46152 9446 12278 49486 33322 59446 23513 50041 34141 19418 52788 16769 14082 18821 40767 29965 52739 52828 12234 51581 23234 3657 14591 46215 6154 43207 42673 38783 64131 33313 31029 42472 21077 50367 36513 58634 17254 55800 63085 9534 60888 54940 3318 18299 58255 21499 9754 24038 48412 39095 13268 39702 33879 20647 10513 22423 20214 36791 21754 48008 26056 14108 30708 2453 52280 11102 8616 45528 23541 38974 43570 20824 55206 41633 46249 6458 52773 51465 43952 16899 21521 8596 42658 8352 54150 54035 5913 11569 6340 48119 55453 24951 19328 19543 58955 33924 19124 44225 9267 33634 36910 57898 49142 63486 12473 7187 63608 49725 45859 37092 6370 17226 38899 13675 63779 26909 18847 42542 50853 2075 17098 50091 58376 24852 51273 58314 35882 47423 48141 16018 60605 2382 42519 19888 55589 22548 18811 51332 6148 47511 1498 8450 46230 22246 20047 33439 12646 29469 17661 47966 22869 53406 37866 25088 8170 51274 64312 35307 36550 4088 41449 5923 11467 47845 55873 34292 62541 3147 33203 50016 22366 53375 3856 3215 25573 60385 26491 5010 33923 59298 5112 603 37760 24850 4931 57474 46504 35595 10292 39384 46986 16757 26152 51926 38615 22217 51482 38269 53404 49001 39822 14177 31218 47344 427 7295 53077 22073 61391 19273 29476 64467 34650 24029 2687 35734 24151 44143 56970 28617 55171 29548 12414 56774 18979 34951 40140 3542 60960 63217 2372 2391 35043 33874 7788 11079 13432 54547 22119 52439 1148689734 1332814114 +1024 59473 24626 4159 54548 13974 35595 14680 19197 53824 4929 55687 2261 41554 22629 2142 50820 30236 60147 10778 44288 64042 42160 16117 43567 4363 49059 13346 34563 52350 48653 43897 60375 54929 35810 61267 55279 51057 37950 35807 3926 57613 42803 8110 44990 26197 39550 62533 59104 8344 58611 27140 27169 52941 58494 55345 18734 29772 36182 28383 45212 42477 45825 22514 18825 304 31520 46551 26316 52916 54794 62966 31458 49394 16993 10500 48726 26999 55129 2562 38213 23638 54596 12237 20487 46616 48709 58444 62703 55066 33247 6222 38367 45963 358 20239 1003 48476 55470 61149 30863 46036 2714 15456 63692 34110 44273 61232 23288 63333 29073 29402 13948 62470 63372 24793 53326 25848 4727 24353 2108 24123 40802 29573 28440 54323 63746 28101 14304 9409 30952 17214 4898 26113 2691 19638 25429 1350 38196 56291 4390 24712 1052 54702 8711 47314 46698 24130 19783 14321 31220 64253 58059 44231 26397 24894 46942 4901 41124 36883 20599 19728 42151 37128 61636 62217 7244 52823 6808 5651 44373 54074 39830 9709 31705 53359 23602 33123 7947 42565 19900 55813 62986 58980 9328 30297 59785 21780 20473 58070 55427 21713 40497 39117 4945 37570 58327 19380 44601 63509 50919 6046 10482 52206 23859 64423 13591 35763 47880 35562 33860 46786 36212 30004 58592 27291 9672 10590 40289 45465 20364 63017 53191 59215 10332 6833 49895 1185 57621 61077 31223 18313 20372 18902 39075 16353 60623 51252 62666 56513 38467 55693 36391 9953 19838 2101 19643 13961 23638 26806 44692 306 38298 54996 7970 25113 59022 42651 23115 35357 25875 39215 43114 30361 36240 20428 1868 56265 51109 16930 24698 58789 22910 64098 17525 16627 59564 38690 6486 63609 37035 63174 9363 42634 22565 31407 53547 52298 6868 31096 31653 45548 20781 11564 17452 11208 7815 11741 40733 56835 6730 55442 49681 50552 58057 4300 12184 53596 26257 7318 12356 16888 13748 27330 40241 59122 21630 18602 13934 53358 6864 52010 48890 40512 8424 60437 30203 14357 21790 27653 26966 39735 16127 61643 24383 12335 58948 31332 45950 11126 57422 42063 13717 49591 34182 9204 50328 39789 21620 26485 34074 207 41306 22267 55963 62422 52769 25515 13938 60915 23877 46247 58353 52803 75 8399 42459 57970 55394 20956 23590 50010 44771 8535 62856 8028 43576 29652 3985 25383 35227 49828 42493 26602 13514 43104 13222 59801 14254 45474 18033 37337 29808 47886 21158 41670 5808 64111 44905 42261 24214 5036 10621 59039 27837 3414 5508 5567 12925 14188 58754 36091 64021 44051 2687 47079 25814 44091 53952 47363 34789 46129 21234 54962 35339 29450 2342 37696 46186 58121 27357 55060 38155 30372 7383 20945 54983 63176 29758 7545 45562 31499 5057 20389 44007 43989 1958 11650 23216 48025 45954 3149 5540 56558 41822 43776 27657 32989 33872 5442 53715 41820 35796 44326 34216 27635 9132 43732 32860 11828 33671 38960 41052 56464 55217 38756 41628 9524 27914 59874 31223 15716 47124 53611 13620 51399 10564 41718 993 62032 32887 14929 3042 26579 50655 19760 53749 63152 3037 55888 63544 18645 54301 26045 40391 7509 50302 37501 23007 25228 38531 58828 7265 3183 8719 61766 34263 17379 55701 50255 23122 26605 39346 38577 15573 63289 13630 9653 659 35122 61562 58432 17277 40938 15052 37626 45767 58537 3012 25156 51048 59379 22446 2126 41660 7825 45092 33920 48896 13684 44982 26270 43685 40419 26938 28920 3789 16889 31509 37861 54505 25308 36414 43574 50331 11852 6697 62541 5438 29161 50583 39023 10820 40857 16568 52225 7423 56457 39053 39091 9714 27470 38586 50906 35254 18575 28293 15612 13496 15855 59817 20522 50681 40676 28345 55588 19460 8377 27777 61665 35439 62412 26289 8496 7476 57605 31169 40823 60370 19614 45255 29901 18658 60196 22416 54326 1533 25269 6145 24328 31372 56046 19403 14061 14973 11648 33800 29369 56548 63668 48875 38818 35076 51354 8961 5713 35168 9706 33833 380 62071 59589 18208 6655 59250 44859 17990 31021 34881 28480 57535 24422 36227 16957 38473 6990 35245 28796 6103 8516 19221 35705 39728 40002 10207 15786 11068 25730 5919 411 43770 61686 48916 37764 5570 27204 11134 49073 11575 1551 43892 47935 22207 3396 678 8815 15677 25874 42732 17184 7096 44736 35219 12250 10198 7700 38234 60824 49284 58532 18816 45031 10037 41947 7487 16158 57702 38318 10272 48006 57065 1677 35077 63448 47451 11717 23935 59922 29508 15631 17924 3160 20710 34880 7648 35322 4488 8328 48988 37137 24905 36132 14214 6360 52402 13249 20740 55587 5545 42335 54857 36066 24064 16223 60218 24983 7545 25878 31520 24422 2777 20447 19836 37726 50163 18932 38024 62106 33448 45717 15863 46422 3306 4114 43399 43058 43451 19642 9740 52278 62619 34738 13836 54205 35931 45806 36500 34825 41157 48122 25815 3456 9067 55929 10161 57671 18663 1871 63313 38716 25846 50128 2978 47696 18222 50723 56529 58473 45064 2731 51408 6060 36909 17291 60606 15067 15783 2036 4442 54936 10099 7008 47805 64431 20376 58239 62231 37807 5059 38364 14355 55147 14812 30226 31575 19259 36698 42525 16668 59308 38090 21642 15836 61553 27761 12847 6440 51887 41197 50663 26498 1956 55813 4457 63085 20062 4443 26441 63729 62093 9278 49450 21940 27778 6471 10189 47939 35709 26817 10992 54976 62985 12279 9099 41922 52072 64182 60335 33094 55073 13260 61042 63126 46072 1832 16673 22947 36924 13267 57324 4166 62706 9330 53652 5099 14035 15329 8182 28341 7682 8288 3363 53472 40689 13662 63950 35530 4571 837 19471 24531 50433 11781 39974 3138 25529 43322 56158 52863 52842 39295 52573 21273 27126 23237 12682 5985 62231 2530 9100 36370 30237 1793 11702 53842 15066 61813 2830 14481 18713 4664 52537 49614 39274 36955 34818 50906 24606 24521 39490 29719 51207 39548 14118 22062 57792 57928 59212 6921 61057 56967 2852 63607 11 22466 5711 22669 24289 36672 57905 20274 30585 35172 7496 19921 24336 4696 34089 24809 2715 15760 17479 47089 6599 58672 57418 63578 54663 12382 41946 5469 47292 4763 16028 38751 31603 3735 14540 52357 61854 41600 49568 47963 46611 36271 7137 20063 45580 19206 26359 60990 38376 48972 45559 45333 21706 13284 56129 28884 22943 56404 7969 49126 25952 31365 37092 60607 3858 21111 24482 40674 8581 8328 33652 30606 52649 61792 56039 19237 33754 62781 61302 35149 39809 57947 9807 28135 46512 54808 16779 15019 50805 60749 29471 2560 60478 29123 30828 50443 41122 1191 24780 49767 56964 56956 23746 13681 55095 56273 6652 30038 38272 15380 6165 54888 56956 63868 46397 19253 56164 15002 34818 54050 44650 4391 43483 36818 53997 1612 30379 20321 51116 34534 46232 9292 61655 46601 2194 56092 18058 52283 39857 28089 28562 47522 44243 51006 12386 20056 34953 3000 52329 544 29407 228 42880 19026 29364 30424 56887 63668 58657 955 43797 35873 51008 42720 21711 19761 57674 45780 12168 33535 6984 51794 344 60153 46656 40044 49933 44808 29016 10728 37375 59032 45908 24031 57409 16633 35363 43392 30624 11137 61679 22735 9676 44428 15596 57493 53828 18183 5803 44116 31351 12901 29665 62783 29524 18354 17501 39732 27636 60601 10605 57117 28827 47678 55558 64022 18320 23498 3769 30913 61354 29988 34296 10440 61978 52721 45245 35617 51119 11312 36473 43969 11892 56498 16001 19613 45820 37057 46484 2009 17725 10812 52666 11488 57337 22706 17364 51094 55924 16218 18386 15563 38923 55433 15923 14166 58020 52761 45589 14787 42979 21218 58750 17190 9830 54704 34124 11918 49777 53286 4363 25596 2020 55536 20536 48416 5319 2765 58581 63856 63306 64154 13196 42832 21473 56571 34855 8336 1214 37109 9076 49746 45630 58789 39187 49413 55190 17030 47070 11325 4778 15191 14519 19672 20641 21619 58863 13159 62526 1327 45647 55215 62883 18740 45535 57683 52963 63091 25794 31598 37086 1028 20772 24290 45152 37303 14397 63978 6960 59249 15388 45436 6561 57506 40266 27858 46854 25638 58500 19197 52830 35806 23183 29748 39768 64066 35732 16129 28820 59910 18332 15754 16303 18237 293 19411 27446 64175 12360 33808 26339 54805 58726 26685 7505 9889 5555 54227 3653 2925 4566 52149 8674 21548 16167 12772 4030 53002 20716 13589 3139 17032 2515 31191 39226 23377 44331 35737 11827 37810 39409 14696 48879 12839 57435 60270 43511 2126 4546 55906 18005 46415 15254 11352 29129 52375 33141 55492 33456 51931 20635 23421 55413 61756 8420 56439 63610 41883 48729 15955 1394 14305 34128 47221 53263 61107 27047 33618 35147 26436 41130 55411 22585 7475 4091 38615 34871 50405 20285 12478 3479 62291 61449 15852 16659 15359 530 42617 54126 17477 6280 35935 7896 42072 19737 47018 48468 28453 21794 46813 41280 3128 3159 14139 34239 17291 49990 19037 175 22804 37864 16272 63204 17841 34341 47464 61070 41352 23027 44630 20633 42977 49689 13066 17775 25911 34280 55058 60712 28052 19531 18256 3398 39179 23671 53249 60611 1826 9880 30370 62795 14189 57956 14377 3255 25248 57227 30022 3092 61127 21481 9799 57373 44237 39044 20343 18289 59378 59333 50356 61026 33298 58665 35578 20149 38599 7295 19630 54677 63659 1535 60101 386 52462 57477 43854 26427 1713 36473 18994 25130 45409 25925 21159 53731 50561 8330 16559 26357 2279 17940 6227 8490 15830 15045 213 60557 63611 19994 30497 53867 24454 26265 30711 10157 48627 64260 59035 22534 35762 50438 32987 15549 28998 46702 50723 55997 9506 28131 18735 3808 36027 47219 57771 45040 33317 11321 18922 7499 63663 60079 28327 23224 29205 46883 7606 15894 42287 62367 53573 52552 47793 5562 29429 40389 34499 4387 24527 12142 33693 20643 35014 48638 2478 48765 49562 32 64485 46469 39921 1991 52911 25549 45187 36914 24152 30206 38197 4967 42009 59710 53645 5556 33304 58676 11299 5362 59481 55752 54172 15841 20340 54328 14003 1665 35974 23241 25391 63673 21242 908 792 59953 41738 18030 29614 48973 60260 17104 24104 35284 16143 2302 26478 46113 54667 22911 60587 13112 21534 60861 31694 29423 7713 54277 20580 29319 52679 21655 38078 63580 27505 1608 33238 26350 10667 17308 60676 9466 42781 10257 30558 62272 53905 37066 28661 44176 5629 11460 28735 7186 53411 4598 40579 16949 19370 44300 14341 35927 62179 45473 22180 5667 38674 20898 14686 56486 37321 29645 61750 8951 7378 7570 63151 28404 35781 15081 9475 52339 25908 20090 59355 9162 23362 9661 26764 30478 6775 34762 25722 15173 30200 56129 17926 12302 62169 19947 14253 60149 10193 54916 29157 43740 27344 60978 63552 35478 21687 30591 21332 62888 40774 697 40731 7529 44170 48978 60416 7143 52123 21805 13143 10491 53626 43247 43608 42757 15619 38829 54695 25347 980 62902 54031 49594 5416 16434 43768 64371 59661 4495 10769 1517 55486 8267 49903 34172 54923 15938 8498 43215 31629 18348 33706 62002 51752 64172 11009 18012 36194 18778 55994 31675 54594 46365 48063 6820 50626 1777 48259 3070 61838 35425 18349 26722 58317 53978 36868 60591 6482 59507 55135 16556 9049 5918 40438 21670 11798 33092 13111 60294 28904 15699 48107 22640 29515 63991 8611 3158 26101 26319 58133 3797 62131 36558 18424 21534 14878 59617 42972 33449 12176 50052 30353 20081 61094 59255 11707 26964 30903 28521 53210 36900 8280 2136 49544 41548 5518 48752 24806 41584 38947 63007 53470 54465 29381 57893 41825 55427 221 736 59379 7173 15728 57621 35318 47007 63566 40853 53575 1477 64106 1542 33109 64390 55177 37675 1913 59723 51088 47607 43230 58548 34668 3797 45016 25689 13405 56629 39984 53815 61786 60659 58877 20217 50119 17704 13490 34266 7896 21782 55856 49724 39923 28086 47168 14012 60621 18402 61453 6487 15732 24040 767 7301 34449 42715 26808 52328 25991 27912 16613 34608 8898 27876 1450 42214 54332 62898 17684 6886 4060 50010 16262 27008 42091 47763 28764 55604 36930 3137 7590 11688 39650 16222 49468 22234 62149 3843 49605 167 20273 3102 8125 40197 46734 59483 12037 7357 22355 63049 19062 62992 3385 37368 60413 42750 6897 44926 60176 51469 22457 15578 9718 52662 9594 26212 6555 36429 34665 46848 25036 33863 17191 44421 55409 27063 31107 64434 64037 18200 15704 60143 17139 285 56223 34473 60134 11684 41055 64095 40518 37494 12473 61082 22009 62725 8315 42455 52554 4876 45013 27764 63438 33866 11672 19286 52898 50116 51316 22123 37744 36420 2605 18424 34155 56793 56768 8586 25932 27266 60255 64202 40154 31540 49691 9657 33132 20130 21620 27756 42788 40005 3181 36616 22676 167 984 13663 6718 25811 3144 314 53780 3075 33867 48755 23471 15425 34450 56094 50619 2945 10580 7839 27737 0 1333009347 +1024 61985 7806 40972 63336 34883 48768 26329 42522 50738 47569 58182 42272 39813 36957 45995 55734 22338 23286 51684 58913 7935 4450 8912 39580 33577 54015 11466 45694 42472 18500 39148 38748 33555 4024 49269 4411 38257 18818 29641 4465 38804 6302 8981 13953 56303 15002 19379 10067 62681 13230 7410 9729 57428 60117 62700 16225 56681 58661 38417 21007 19025 18368 17524 50050 27057 45076 62293 58801 63275 16096 63890 21378 55413 47192 60760 30523 28259 27633 46992 38880 5190 54258 46716 33303 6778 23656 60325 54600 10944 16441 24366 33921 36370 43373 44024 27825 20937 34211 1738 44500 4572 6868 16458 29414 20434 2665 33707 41319 62212 5483 7893 46057 38439 16822 62970 56337 8092 23824 9935 44811 24956 42913 40130 18645 9406 7814 3231 12912 38448 21831 22971 30598 47415 26258 27833 42364 57825 56788 28024 11640 24582 14142 28274 34713 16697 37135 12017 43182 27272 5230 11309 28130 52195 63723 12125 8662 17609 42459 18026 58557 11261 47111 59849 18695 31675 24241 22151 36175 28256 44168 26821 46336 18825 49292 40516 61291 46912 58903 54957 1475 3552 60255 23464 11420 44741 49227 52348 45956 16615 50939 9434 26735 2789 56629 31108 20692 28425 52295 9241 22307 27767 7761 45573 6068 34910 21496 28178 45578 53605 36273 57062 41938 21424 63440 28562 44299 60540 8929 12450 50034 11395 58889 29365 36779 64346 9258 45632 48678 2959 54985 39312 29741 29378 18902 54325 3140 53108 14556 735 49798 49788 60732 51052 22414 16693 64090 37133 299 28965 5320 59054 34598 37479 3826 47332 51531 54496 50496 12003 30040 34163 25454 9937 2239 12181 15521 64079 33507 21167 15759 26753 17878 57648 16435 19711 52910 62856 5749 15634 57214 30554 63801 51121 60432 38399 25764 22965 61186 13034 41908 4068 63900 11194 1714 47155 20892 44060 20777 56267 1582 26126 15709 49171 43569 24290 25964 14349 52110 6871 32887 23372 31664 7067 31227 10851 49259 58538 25666 61270 18774 48265 9055 38163 1224 33107 51124 12370 35586 37866 12629 27168 6884 474 4167 19267 49663 37200 58367 48361 8568 11144 3594 41993 50286 30032 13253 53416 17652 38410 53748 48926 41260 7697 10445 21886 46556 48331 5302 34288 1452 60608 33360 11054 21901 53742 33110 18716 46222 1949 29787 40687 4478 5770 16270 63640 44987 36424 11200 38558 37332 23145 55297 29715 44768 25855 8550 11919 13861 57071 30488 13726 52226 4240 23162 8629 48747 31082 10580 57694 31240 17256 50563 10711 28982 59338 54227 37206 10314 58977 29816 63976 4739 8416 51520 55335 4451 13828 41341 16065 484 61005 10190 45379 18323 18288 23058 18399 30681 35073 16521 14656 58803 43860 50519 4306 22947 42976 30677 29414 16998 36101 12115 56089 8740 8596 34739 63516 9618 64142 53941 1352 52684 20027 50576 11910 13650 4400 4535 13825 27699 49646 62244 48090 13202 34991 5222 30804 58501 15832 15286 34806 7907 25545 24392 5443 13387 56082 30210 30044 28153 56414 14793 28054 24208 30183 10225 37687 4768 30390 56211 63544 10322 60609 14044 14368 19224 19414 25738 38427 15553 46407 45984 10901 18145 28705 39836 21980 59059 4102 49733 40513 63203 41620 2175 47764 53692 5302 20958 55420 51433 4123 13540 50097 53878 9380 29558 7771 10050 51201 35650 39306 61155 41122 30274 2695 33380 10690 40500 16566 26198 11402 35949 24710 50379 34277 12182 12499 26239 44420 6556 45761 59475 34189 45734 49486 17884 25384 57237 18240 15784 6926 16061 6095 61540 52590 15124 46730 32979 17168 15950 39132 26234 58041 899 52098 48892 36353 17806 50097 38300 33070 44834 41672 35066 41539 49479 63673 30986 19312 5832 28574 46957 59485 17326 57949 63155 18379 58364 59899 60372 55305 37033 3406 56561 31463 35502 19183 9710 24908 15960 42342 4286 377 49181 53145 14746 22201 30725 29181 6610 52969 56829 53358 11602 40220 47671 14301 44001 170 52587 10874 35580 1329 47059 1389 41522 44674 34858 21056 43428 62650 2225 48119 60531 26440 59476 29959 30784 41281 35641 4598 46910 61871 57800 38241 34308 46865 9567 20805 40620 10868 63084 27716 50251 36507 48038 63778 14919 46044 61242 36232 8490 62492 27455 3300 24708 38210 20495 22668 6419 11512 62272 34861 14379 27723 37670 56154 57432 4092 14398 57330 21868 31064 34614 21065 37588 11334 7214 3442 56221 62650 63365 61253 7698 27502 10402 16247 15010 38885 54992 48296 39420 49629 62727 24837 35318 41618 1917 49078 28716 45521 25848 60075 23368 29160 29482 42279 31441 17515 18952 54416 8922 16559 46357 14176 24132 31590 1877 11333 36206 51107 34079 29941 61981 41259 57967 49362 63368 14719 12305 16630 11250 10068 35280 57883 20749 3974 42979 59949 29593 47762 37333 12904 37573 62975 15797 55844 47692 5167 34959 44374 7181 33567 6055 12929 62352 63983 41735 42538 11343 18041 10267 24164 29100 30749 14111 48759 24195 52038 24927 34991 46855 54231 35595 24914 3101 62002 44707 27619 30154 4713 14232 18271 11564 55731 7382 4681 50612 62477 4562 46475 38496 56015 11299 44393 17261 22999 34375 15029 51989 53676 25232 22712 39236 46109 27202 46058 51793 27770 8457 48838 572 55543 22796 41950 28781 51078 22617 61748 16046 8465 23814 57762 30071 12088 48262 60810 19491 594 41489 29657 29417 4552 20610 25493 15805 1525 56173 60898 15653 49392 11283 43587 53314 51451 5620 31025 10807 15773 34521 33258 4016 15261 49086 7725 48475 7736 55532 57845 60219 19102 29220 30644 46523 41813 26291 14107 60024 18387 29376 47401 53812 26921 21704 37824 24381 13634 41408 23162 29317 21584 52828 46786 23683 30805 60312 55357 26196 17098 7008 40234 47604 36411 48947 20904 55175 18701 12439 3681 11009 45304 55737 4515 54538 52073 17421 28562 58670 8415 51689 2890 48983 7060 15648 44375 51017 40304 27652 52679 39024 20046 52566 27964 45203 41316 28776 10016 18381 26217 12228 6565 39414 4942 48726 23624 53201 4111 3509 63424 57028 41829 48186 33353 56743 7889 48031 58226 27259 10915 17953 41236 38540 24154 25416 24257 52598 25649 53059 55158 34369 15765 51099 45498 62354 2548 5088 20407 6754 29254 311 24917 19575 45535 23256 34946 9360 21660 38939 43093 15720 15035 9485 41594 25480 37966 63809 42695 2275 7654 45984 20555 3812 60887 3842 43123 28508 35874 36405 6372 20595 21650 62752 43874 40660 58371 22628 62241 45408 60076 17618 13371 1747 24091 50582 6338 18431 45957 58872 5336 45597 2944 27361 26971 664 23032 42470 36920 57677 9195 9656 8371 4120 1460 43379 44192 59226 9229 942 36899 33120 22161 35411 48 54164 33711 18209 34848 27317 32769 18825 8859 11616 56533 33627 6567 37025 33405 25794 8661 15882 16111 33488 61612 31264 58060 8970 52213 51090 45249 35854 47460 29367 11276 3823 47748 36603 63974 46010 11704 6773 45063 5670 37868 16482 394 25912 17455 40297 24616 25518 29416 56022 21602 17796 10803 20106 7212 6245 59608 33080 30252 24057 24285 11700 49390 40880 29037 26782 51362 3598 28388 41268 1670 41915 10366 443 11814 25472 49301 39881 55452 5198 5130 9663 26574 57336 16807 18707 59514 9846 7669 59423 27890 57908 52189 37502 3259 12897 52435 2990 29817 34410 25163 8110 6362 11689 51891 49567 63840 63223 24636 8954 53065 23979 6203 11076 11030 886 21746 40174 39949 40746 12787 13683 25904 20088 44441 36903 47209 42933 60500 21683 565 59271 42750 45232 16980 1244 52573 52394 42771 58632 43153 40082 60067 59007 41622 13247 49790 40022 21828 44524 26104 36442 38079 20669 1716 24540 55886 47531 26621 13122 17561 58166 61089 49055 35779 53889 16138 41751 5367 33494 19964 25372 28392 58411 46831 26999 10150 20155 41908 31410 25071 43387 63017 17794 62489 10694 10016 41215 62279 27874 27195 60740 47388 23983 55523 61429 26836 26615 41909 17052 12813 6438 50235 41036 63386 31015 13816 57127 20667 51707 3810 11272 60359 57867 55228 64285 55103 60592 34469 26036 25194 15912 52341 5775 35641 55753 15852 7364 16149 30320 11792 33969 50874 9540 14957 49435 36161 19302 24855 37345 37276 51590 14399 17732 54207 723 43305 42378 58796 12359 45015 24510 22847 4288 51512 41960 19152 48411 22869 9259 28521 28610 54887 63627 38367 56596 40229 39301 10907 5287 43727 1440 42172 56654 51338 28077 13311 30052 16596 11541 41116 61322 58145 11973 38493 7457 12280 37830 18881 28057 53784 56131 59589 17342 31114 61759 43955 22230 48486 50480 28943 11400 34648 61278 4726 49909 45322 15235 48437 2289 42930 33305 49544 41631 49172 47315 24570 13045 25395 41246 24442 28055 45393 24494 26175 6722 36797 29872 34803 14690 4671 40674 49574 36341 14415 48851 63159 58115 13588 50279 17 21288 17788 25903 56126 42919 34013 3831 12980 33636 16774 7194 11873 50460 23297 52837 58385 53652 3899 60196 22319 5522 5464 43242 19186 44413 44153 29776 48290 45565 40962 35390 21819 58503 23117 3743 57715 39850 59318 51039 60486 52868 36013 26656 14293 10541 57367 47698 44919 21476 45462 49444 40372 57602 50628 20930 5228 59488 22819 14175 24760 28749 888 44311 2776 54222 54660 64083 30912 52072 55984 40343 694 22199 3527 46142 31098 22541 52519 1848 34722 17793 13996 19227 16689 20744 54931 14399 27894 16962 37180 5926 26200 3178 194 33857 5944 63010 13183 12720 41565 33089 43703 56820 19577 6236 5195 45825 7485 28441 5575 61430 49158 37466 64078 47822 58790 20095 22272 9913 63380 31730 29604 11841 54718 7936 23626 2534 15188 9624 49821 63862 4339 62520 3055 51786 51724 30982 12540 63074 33574 40624 43056 8814 46616 35476 6576 26886 20953 21992 12922 33959 46802 35605 28363 41036 36563 14632 62430 49601 30235 25484 60578 60096 35638 2979 46396 48842 47181 53 40547 37690 35222 5082 47952 1809 5193 48272 52766 54150 59875 43104 34632 23651 16978 25444 54698 44570 3815 847 44772 9854 2742 52853 63566 22611 40909 55483 17932 32832 59416 16966 10011 16574 49030 46043 62511 20396 3057 20070 53407 20721 10083 16190 58271 23111 26429 42722 31413 43133 43034 57782 45701 53869 44052 21016 5870 55067 39567 27237 35021 25091 35917 23832 21980 11578 42941 57680 35803 17862 39793 13215 46721 1552 54706 682 53016 15592 5097 7720 52213 41642 29840 25882 22391 34499 15636 22203 59418 25206 8746 48187 42633 58712 10595 62333 22193 13668 18354 25343 45029 570 5941 49599 50980 11844 4174 40747 55553 46923 21689 23051 53781 43186 36889 37510 33609 54292 1257 27532 47715 34865 25389 53689 46938 19955 12169 7858 3989 12016 26601 26421 50204 33668 60696 12019 29962 34358 4537 34393 7991 64168 53166 26735 13465 36625 62327 15741 34142 39440 46384 30377 6587 58164 48251 2582 6168 35997 46212 12596 26102 28364 39355 53040 58263 22141 51225 37233 33777 63050 50275 41744 13746 61407 6030 58219 34224 27634 34737 25060 60249 63884 63035 28742 58650 62738 61848 14825 34919 13713 36941 54066 39955 58659 49217 5179 12439 62693 44167 40163 8013 61187 5592 48785 40712 13129 26592 16682 55003 49666 63056 17764 57304 33492 19872 11426 43166 38973 45473 12835 29229 12699 21376 39612 1225 26198 11824 57383 59762 55001 21139 7543 48863 25656 26400 57374 12815 6314 8007 27259 11787 37022 50799 30687 39069 12030 58294 55790 2115 20332 17245 5521 24899 58679 6294 55597 15303 40910 62173 12915 16164 61335 2884 42721 42104 21717 16609 63021 57017 52768 12812 27414 13454 35997 34822 18955 39573 51720 55189 12101 30592 5862 34278 57226 18535 33197 31545 44472 34461 5878 6965 19557 1618 41920 27019 48045 4009 51790 16875 45104 50249 18826 28581 59757 39069 22060 51654 40681 9936 46612 3433 20958 52734 52374 10692 43242 33031 16472 52772 16733 34901 54808 44056 42970 34283 6221 28755 16347 35536 1026 49790 12463 9947 20212 38231 15572 1054 46166 27682 43664 59731 33820 55544 1626 26028 28039 52927 52953 34154 54647 33069 24131 9084 28820 61274 34858 20364 20010 17057 22183 21537 61854 54678 1466 61652 54046 24037 5102 49160 50909 39868 37025 23124 6409 40361 25263 49093 3958 15447 43745 19706 53905 1769 52056 5412 13234 44471 8896 13746 59708 52974 4703 22105 55652 21557 28474 58566 20318 52269 63634 46559 3489 15077 51572 7939 1414 47724 10912 46273 22534 25629 54383 28233 55242 63654 290 13854 17776 54415 1835 19768 4373 49220 50970 57065 39121 63114 41585 7816 12648 56053 24283 23928 26370 44644 2201 38215 11471 12458 22936 10174 52437 28965 25870 50508 14996 44309 15692 19623 8585 3044 49393 27975 3279 38526 32789 18243 55405 30039 53720 57082 3068 20175 32779 2938 47725 21991 26960 11049 40446 61785 45756 40921 9232 33192 50219 3298300504 1319503015 +1024 56650 41967 48937 41269 12834 2868 33787 12414 57929 25375 29486 39919 18145 24118 35771 9585 9080 60551 2127 50769 54331 45770 52902 34166 43609 36288 14021 42615 15365 11730 4232 45882 44564 15001 26233 3942 7612 37055 8746 22811 554 55751 58838 44925 10058 4826 10871 7433 25927 18902 24175 3995 53476 30642 24189 5410 10106 21354 4906 46793 48198 30296 11925 61438 3363 54647 20788 12765 29744 7316 51716 21992 11658 43969 56437 44654 62407 53732 15449 1343 49970 56260 21517 14926 6806 9127 54907 33108 6617 28968 17110 1001 48974 42106 38081 48581 10333 38321 25205 44360 7788 1922 61972 2259 59411 39819 36812 21153 12957 53824 30440 52248 29282 55559 42965 61368 55965 27460 10187 44704 30410 17436 7290 27093 26708 25501 29957 8523 50860 24681 45922 11907 111 52537 9917 33077 33152 57109 41225 10606 49217 18853 34374 26288 33718 19643 39445 3751 33517 37811 48724 52210 42711 61971 43452 31186 20765 58987 21421 2662 59755 40288 6070 16112 30644 2261 33270 22971 64311 21739 19583 39349 56128 36236 20425 1626 33840 7775 63618 47199 49158 20206 18071 6855 50739 53870 47253 10626 56852 48314 49720 16269 28655 6857 39476 58506 10544 10605 44801 6866 2177 45916 36891 52327 847 11623 23478 26069 51838 21935 34967 43571 54357 30492 55527 9022 5317 50118 44012 58634 47919 39126 32779 3108 25964 63030 49112 23343 9708 60982 43073 44539 36607 39271 43155 31441 46748 20301 37065 8935 49946 33890 43101 22707 48347 23818 101 48888 17554 1569 45847 23791 63989 36498 25136 40525 4460 29522 47072 47391 38990 55501 26647 55626 26381 50572 32783 38880 62952 19427 42307 41259 57172 25135 53492 13348 48106 41223 51662 5530 58016 8411 63640 25465 18313 18514 12884 6231 42646 9168 23896 56846 54094 41729 34386 17782 15110 34944 42272 61955 2684 48618 17113 51866 3629 13637 25850 42968 39957 53098 58790 51049 11018 41385 18155 23388 64332 37142 12060 53640 15216 2362 63120 46397 56399 52019 6976 17147 35437 19947 48072 13076 24809 27169 61276 22951 57096 7632 2124 53502 44266 13408 30471 54883 37657 10736 33706 59321 46751 8023 23936 64019 22019 46722 41318 37307 55952 43215 18675 63440 30021 45797 57638 25295 28078 15325 58679 21007 63106 1920 37975 48919 40228 27710 60464 36430 43129 42084 46840 33967 4834 1974 3555 41205 40294 27544 49134 1051 25985 5430 14738 53123 28485 39035 14004 43931 26 60148 50017 14025 11860 23141 20065 11605 41409 58063 44276 2369 20238 54941 40613 18824 26721 37079 39743 47550 45435 2617 27035 23807 57502 3750 56571 18014 22552 45801 50043 18979 11650 55354 28224 39078 46066 15278 56606 31157 40539 48910 33908 42427 15596 5291 43920 22396 44227 5697 55004 53683 48484 59126 22946 18654 14687 30903 11012 34428 26709 27348 28477 5377 26957 8062 26046 57929 51042 11033 52949 20984 51458 16863 46166 62989 42142 45188 43364 34711 42481 44309 3040 51814 3498 52989 37762 15682 55558 41630 13988 29849 47963 10140 43201 15894 55535 52455 23739 49630 19750 15742 4363 26867 29976 487 34146 31662 20520 42580 59462 61368 52400 9783 6190 9300 50243 63874 18790 17660 19869 2682 20557 58790 11682 1258 46606 20499 2756 44994 10456 1077 17772 48699 35973 12408 52923 61391 38422 10042 10364 7566 4627 10399 22259 11334 20334 21492 25286 22825 29995 3445 18159 60099 52225 16960 37971 26768 58473 47042 12660 47658 56731 149 10872 46265 11722 58986 64222 34921 37089 37072 53324 17547 4746 33333 34361 17318 53404 6851 41171 35492 33654 60244 36626 54493 36185 19698 63231 60127 8238 12197 16952 2619 48258 39674 15256 19792 60791 38441 42573 41865 21467 47447 58277 6993 48400 56622 29963 18894 1647 24518 51021 49081 52433 54924 35720 47501 20625 8739 28111 18195 53457 17110 48910 2322 26749 44106 29173 18498 17092 12003 24089 63359 42108 20813 40904 24687 42794 18608 40729 49150 51096 52091 11358 32906 33812 40082 17994 10772 11192 25844 17866 59899 61696 691 12560 36381 24679 61666 4825 40965 43681 46350 5084 6697 34338 18352 63482 45053 9625 16067 16956 36645 45476 57677 47917 2242 55152 26262 18947 13439 59045 46803 35904 7827 34651 26966 3576 38764 41753 54405 9516 30992 47857 10307 37936 57016 60134 24253 30005 51941 60058 36931 29838 3443 41243 55893 27958 29879 3458 28989 37143 57054 39605 28424 16548 62171 18506 36954 26547 5501 54777 38601 19640 38647 1230 23996 27814 11727 58440 55764 60374 44837 38806 3222 61575 13894 48713 7695 39659 39772 27754 3879 17785 60466 7416 54529 44760 45439 36477 23911 1907 60797 45226 28804 35185 13180 1143 54435 51293 40595 34866 31456 58584 60681 18357 2563 58049 24052 62688 19602 3415 28276 41623 7335 50713 58096 25301 51732 26826 42511 37230 16851 64344 16917 11855 51789 11892 51071 64471 42627 38651 8692 17656 57013 2270 21298 39666 57835 7994 28854 22591 22730 18785 47304 24828 58637 42097 24598 53192 9631 18819 44520 48629 11983 25300 8542 4357 2022 54386 49159 44835 9353 2740 11394 22192 33555 49278 31184 47620 21782 58409 63564 29490 58034 17357 49758 48619 28401 59906 53932 11474 44058 57665 46652 18625 25524 55489 43008 21640 30101 23423 2700 30619 37425 21543 13981 15418 8018 33704 4866 3414 53917 44978 61799 52701 13529 41958 43305 54285 26975 29572 38983 25642 59928 37556 28819 3094 32832 27900 20201 37367 144 27589 56328 60524 17523 16369 12144 26266 48178 62666 23842 4040 44853 18166 15721 43270 1672 8513 21825 45042 16798 60360 60481 27715 14022 11622 51133 22680 28096 42258 3469 37626 6337 27413 50357 45823 15732 31458 19917 51847 36290 8083 22421 30233 10716 29862 24613 56980 32981 54384 22555 34639 47500 50633 14840 6621 4483 43016 31153 63871 22137 53136 7842 14117 57732 37113 6249 59124 39727 13576 6641 36631 60163 61765 57066 61299 7535 37769 61726 5845 27583 63367 64486 6231 63132 10595 48199 23428 25529 57219 16369 23837 5574 35296 29450 49450 19981 51410 51144 20108 33045 23927 62766 11900 1825 52817 45554 33286 25079 61126 3948 48494 52776 2574 46698 4467 40129 40251 28639 20027 30375 7753 58818 56376 46541 24795 12182 43123 14122 10097 24541 41702 6761 32974 18471 18428 11408 14739 43693 118 36592 16779 57729 1617 15663 53240 63453 12431 31420 51035 51788 51645 35559 61655 5638 47420 62003 16828 27290 3642 10465 64279 30339 5423 40419 43453 7359 25076 29315 55710 4042 2689 53872 51918 33030 4731 23596 19828 53507 19025 39329 57546 5411 10972 13255 58097 12655 45929 33561 20811 58291 11166 41418 5178 13210 16992 59539 32882 34067 9300 46169 23854 63793 14672 40449 27999 49358 40609 57786 55804 38828 59911 22402 34481 6372 54625 15560 28988 35805 8055 48801 38154 12460 42270 16429 8476 23201 61260 31520 26348 2545 21948 322 22818 30324 5297 40695 26102 45518 4192 50853 1567 29231 55501 61449 60564 5599 37446 48826 38033 7349 5105 53693 4416 60917 15650 47199 49035 54173 43489 56618 63414 39139 48357 29478 47408 1045 58445 44717 38802 61994 50806 34340 58166 21961 50237 19180 54960 47166 23060 33877 39992 13985 28090 12537 26968 62081 37695 50829 29483 15859 29606 56158 23277 33005 45372 56320 309 29581 33494 54590 25213 58088 30592 2794 41816 55633 30258 27045 23193 63891 34045 12452 40519 47879 9647 18987 56735 39759 44537 331 51935 54652 40042 29080 48297 20085 24196 10503 47619 53229 31471 25894 60584 15335 62635 25750 35002 40889 27776 38979 10568 21528 10986 53158 2806 3608 58339 22229 22211 7494 14985 62391 13439 19139 35623 62533 54807 12323 43547 19588 36718 37624 3726 54397 27189 54127 26091 59866 25687 20937 12653 53966 23222 49551 22463 56176 13535 28592 38248 37181 34243 20702 48784 14267 7834 5861 28723 6344 3916 18518 41397 7300 61438 11884 13624 1318 49100 42776 45396 50249 60335 34359 46815 21610 7848 15567 18789 37016 22629 53975 12767 9668 27994 15357 15816 17814 2428 10027 58173 14859 3476 43686 17832 29048 21938 6474 31423 42823 9620 26247 22825 58893 25593 20338 31532 50405 55700 1792 48492 16592 25218 38109 64028 34568 51250 21103 50633 56501 7312 16416 13594 60996 20430 42899 28848 22499 43537 51746 62176 11380 57034 64421 12066 60599 60339 53826 26943 52567 19885 46586 64265 15140 16303 3233 30577 43381 56157 14385 20506 25835 7203 27787 58815 16180 57396 55404 28265 18098 29252 48216 38514 25659 52554 15430 44509 40765 55382 24016 33504 45052 10519 3154 35243 3082 25117 18583 62253 48438 54483 28905 55396 64120 58152 9848 37752 1068 15119 60955 57477 28309 30519 16848 51621 64268 18331 11716 33466 21339 30765 23482 7220 12161 39720 46639 9584 51434 5411 41761 29576 56545 41404 10856 242 58885 6522 13952 55964 13826 55145 11992 44127 53776 34166 13376 11276 41948 38630 59522 12895 28037 48635 11977 2563 5086 11695 15305 3048 36474 5621 12379 17641 47148 48069 57689 23510 36511 57268 20868 36486 24533 12586 42954 42373 8616 5282 47310 35924 12719 12667 8923 26867 34104 27853 4696 24680 59696 2060 52525 47136 47964 4467 45268 44491 53493 33464 22251 40712 19565 56825 50119 59034 49375 63629 53854 11223 22133 54613 63355 28723 45394 43436 25038 29894 52450 404 54786 2144 12886 49907 5137 45318 12842 10513 11621 20226 49919 37978 40971 62276 5307 48423 23295 54584 3581 9707 21423 7845 41017 40203 38504 2713 15294 5447 54079 23945 37959 6659 12741 29982 37443 34972 63600 1122 36458 40294 47059 54673 50850 31060 36074 18956 52679 50814 23709 18007 44534 21122 20206 48300 9985 41696 57396 6051 9219 50495 42950 44905 50448 35181 60745 52518 38609 23893 20921 12378 24992 47782 28576 15205 52732 19801 25457 37985 7714 6288 29391 36316 38314 58660 54698 2984 62744 22704 16739 11875 48840 52814 30477 11781 18633 38898 41254 26098 23137 30352 41701 15755 23153 55559 18348 35690 4317 11169 45667 53046 34513 1803 55968 28176 21312 58622 16813 14119 6731 36432 40658 9955 49529 9391 16093 47797 25379 17195 60245 3474 26509 4270 45096 2302 46835 54419 489 57088 27671 50646 234 12635 17795 12152 8491 33743 48208 6667 1651 14726 17428 9953 34889 40473 55718 45918 58505 45088 48500 52448 61284 26913 43429 51972 23402 41583 40174 23251 1793 16078 47036 35841 25025 43831 22202 19141 25403 45353 56863 7916 62246 37267 48005 21905 53572 57994 48548 24279 44169 48549 12204 36548 7708 5187 12065 37058 25804 43127 30878 26639 50573 23152 47200 12998 2782 39019 46554 7192 14512 14324 35481 25352 29132 4906 28930 17359 27891 10447 38972 38302 7580 30959 33841 5153 51972 46149 24177 33365 1154 56719 44489 8316 25995 27959 58717 52344 27035 63545 57254 45652 29335 54701 63762 41536 62451 630 5597 45920 25704 47474 49366 39578 29345 16266 5595 3951 49602 59169 60311 30477 58815 63620 41555 62530 23294 50583 40456 23394 39575 62219 55618 25044 51846 21138 55255 11075 28267 15207 9912 46243 46821 21309 16092 38984 60480 16873 22130 1118 64255 43384 8814 24308 9393 47024 15729 54764 29767 6567 52596 58661 30288 6363 41897 54707 9668 54552 57307 18392 15460 18319 14561 30528 27426 29837 43378 42570 45810 16636 27321 59202 54005 2189 5299 24002 56198 37482 44710 34058 11469 25672 37092 56113 51153 59288 41596 13211 23251 1054 16367 3967 30166 19793 6330 4495 62017 36099 948 53311 21713 33397 61909 42385 43598 42524 1251 6807 12275 4538 19988 943 48774 52212 30631 35470 52971 34979 13910 17564 46093 13366 23650 14245 53713 63139 19532 29609 58626 51628 48249 62223 27220 62320 55558 49549 5494 21716 938 61896 392 6876 44163 19867 27104 47608 20898 1557 9997 485 55012 17107 42524 58600 53292 520 26009 64098 34837 50693 10618 30553 18171 32792 26177 19376 29909 61554 8497 34987 11700 5027 24617 52082 8053 44101 18071 6929 5127 63954 9630 16889 16811 59061 448 47152 515 48883 23660 41636 19097 37135 2636 22249 9671 36789 53648 47811 30911 53239 16430 26499 62176 53885 46231 20680 11813 49669 22565 58597 8162 36286 40125 27199 49067 58223 61596 53645 27783 22150 4892 54871 62305 43708 46975 29374 49842 22016 3207 3936 33575 47164 52797 5087 7974 60343 48028 20022 646 16992 27079 51560 29065 58872 30939 40691 3867 52036 1740 55120 4471 15065 5090 16239 60094 17008 17534 64455 33595 56221 43065 34561 9765 10232 12091 58615 64274 22230 35103 23364 47164 6562 50582 36486 2319 13473 26538 52780 52743 63397 20205 45971 40376 21336 2373 19809 30156 52297 7759 37547 11099 4963 25666 54144 18803 3193839321 3474650491 +1024 26798 2677 19854 25619 12906 20769 36443 17168 39784 40459 20849 6319 4474 13977 53170 39074 22305 50686 20657 58756 2395 63899 61601 36620 43791 37503 64319 63366 34303 6219 33981 46909 19236 56544 3228 19588 39546 51892 39300 50514 9059 17958 49972 45221 43952 59911 2083 58879 63240 51617 30151 40200 24108 38983 62854 17318 47152 12671 33613 23319 6189 52007 28094 9078 19351 64086 57875 40185 60364 29765 42726 23284 16137 31072 38780 42932 5114 27239 54855 29796 5596 63187 33459 40551 20905 59823 52089 25252 25154 14722 46789 15327 64306 5926 51144 54093 49162 12021 21996 13315 54487 48095 21937 46408 26881 44902 56461 53459 59408 59401 12542 13741 22748 30316 38005 57533 43168 41566 40502 16530 1760 23382 27520 57023 14589 38559 52741 38963 1479 18869 60759 1763 33294 31053 59198 5235 64509 7819 38666 61166 45211 9296 34404 50400 14212 37954 45168 46842 43968 20866 55782 57604 27727 36998 39232 21075 4605 54182 56268 12014 27937 24896 27208 1022 41685 26072 18393 40905 57146 33258 18478 38077 60955 42437 62927 20436 62048 52941 20 64244 43572 43623 12687 35658 9904 6046 20659 41358 38650 26501 48876 9992 48716 37420 324 51889 51752 14278 5840 351 42380 35547 35568 42446 37556 49809 47397 9730 26503 24551 6658 52277 323 28543 55539 28324 30173 43140 36374 61228 48217 26136 6417 41850 29582 29441 42434 41054 48551 33762 13778 17595 8676 33621 27691 20248 45081 60536 14079 37748 23755 4500 30148 27409 30166 24237 19668 42787 54720 55258 20805 63052 43385 4269 35229 51210 11158 51249 59160 24034 4328 4830 4862 60228 34285 4748 63602 25019 58142 33190 9291 50468 4245 18621 33341 43077 22180 39628 7951 9823 15221 30578 58085 8777 10669 63315 19324 46466 61353 47599 51920 30738 6604 25913 42849 17369 52670 49146 3617 3199 3192 34726 26905 28428 35466 10088 59532 13873 47964 14824 43134 10892 13389 1679 15664 2748 48049 25168 47704 23331 13106 16322 39825 17523 63348 15569 7550 57063 15736 37642 56958 29505 5276 5079 36581 9245 24521 49394 108 54087 14965 56112 48946 13392 49651 39853 9589 59273 55988 4712 30455 56311 30165 63310 7789 23748 28523 6931 15495 16182 33922 54437 55587 25637 10891 30693 57226 57134 16968 6802 30980 1903 46978 9374 12987 23598 63059 59490 18021 19898 38217 17054 49472 29843 37024 63127 63874 36806 20828 53959 56445 45633 22188 1091 35655 36302 45547 42516 15176 35296 59286 34058 47056 34378 58775 16850 9611 54981 26386 60580 4888 24009 5224 21822 18024 50796 47628 61215 35324 36578 21820 8286 30433 48941 11003 41585 45007 58930 48636 34027 59584 20090 60462 47978 56143 11422 51596 36097 45381 40585 57090 35268 54775 17761 21843 1369 25575 9167 17950 54585 38400 38142 18244 38840 29064 24403 38515 43234 46436 27205 50068 27094 7171 5380 53524 41385 3425 56275 6879 63400 58789 9108 22244 50989 44326 1418 12513 34976 32777 34513 40572 25680 3316 11921 37080 57887 24371 54470 51398 13719 51243 26599 25344 2252 49047 30136 18403 44190 49920 13882 45237 2965 20080 56881 31281 26624 7764 55245 23497 48883 388 21179 41839 7361 49609 14335 7615 33669 54060 22933 52581 47625 29308 42692 10039 51190 9626 40173 33635 34458 9155 9370 25219 14231 59592 3675 59071 7298 1673 38021 48581 23473 38869 50379 16289 28206 6379 15695 46643 8111 26045 21877 402 5298 48480 40994 1749 50856 46790 28308 35443 25812 47181 39991 26995 27055 6258 20791 37576 39028 56468 12488 57979 9916 45698 40761 7408 32832 22806 33583 6196 31573 47794 36242 19716 20022 16943 30225 23354 58210 44566 11526 1924 10517 36778 2506 18174 15906 58576 22300 51893 18288 23282 16561 21461 29469 43485 11081 51142 50638 23636 19536 27696 29865 14216 2242 41751 55575 14744 53434 26628 4021 13750 49316 44708 12223 25878 53795 22006 30638 36823 46136 55677 28896 31732 57448 47074 41646 30145 13530 34533 41458 44719 22010 39685 35402 61322 55313 5109 22310 3952 33399 41930 20476 24294 22886 5188 57227 28346 25389 46750 28779 13803 44186 38448 60516 26352 18 10204 63805 51357 58274 51037 38036 7259 37807 18887 46283 21304 31706 6065 37620 819 45855 36632 30453 24220 39526 37653 34001 3888 23423 60365 21196 57111 5038 30928 39351 11617 16082 48289 13625 58219 41364 45402 25607 15613 13503 9932 51497 30128 34655 24246 39389 16381 41946 41002 14593 34759 48137 52623 10789 44888 30698 21421 53069 3377 35244 3048 38002 11799 55159 15111 17020 50652 6371 13071 29734 33493 16081 34331 53738 33948 56109 21763 19427 60739 6095 45571 5335 63430 19195 58841 42929 63118 19664 29394 63770 61791 12877 21658 14036 19250 25945 16955 21963 17715 49548 38096 511 59774 51059 35993 13276 20415 466 16385 35236 42785 25310 20854 25247 51044 21328 34405 47131 40205 19359 48654 58012 46740 45283 36661 2847 32949 7123 1877 5336 41229 19025 36242 46058 9344 41858 1801 20103 30704 7706 52877 353 25424 28433 875 38331 18616 46752 35725 19131 12288 38491 40938 31237 63591 17329 47913 4134 49842 27947 29021 49140 44302 16162 12357 55909 41680 15365 6624 23708 46879 19454 23174 30160 701 28340 52433 61662 11604 20390 56646 12617 8900 46204 7925 42042 21444 15594 38506 9078 44203 5114 53974 26838 50579 41967 13841 18433 52718 27022 35607 1265 34658 46531 59103 49441 29928 15531 19892 15033 41793 54285 54718 38791 48030 44730 56417 54740 57160 33002 36582 11305 14741 43548 12683 53360 45385 45360 12641 13454 36300 59280 10126 33222 26717 58773 49125 52004 11923 34171 55968 51509 37979 29786 20577 29476 2486 43116 36141 23932 36719 58097 48562 12736 60931 37122 58482 8932 41344 32994 14529 34993 39542 29678 47571 23802 28074 37932 57666 3407 3557 2754 23382 34447 61926 20238 41929 62886 50375 57399 30019 20851 59054 31190 13128 20555 59370 52354 31034 36690 39783 31034 62944 28631 9761 53855 4421 420 22117 23819 24280 24128 21083 41079 20764 24760 5853 38232 731 34072 44781 48899 24508 6470 346 60446 51942 62796 9116 38114 60282 39755 57222 42648 1451 28619 52703 52133 44729 16253 59185 54174 16448 8617 41920 24459 60980 59543 18499 59823 3248 47912 49900 20903 47173 11382 36916 42887 9784 47322 44485 23488 26329 29698 14268 23625 24140 19518 58789 30558 52033 4661 63715 47875 21901 44339 21869 29323 58517 28636 16947 12742 21582 9754 4605 40788 57146 430 33414 9774 45682 8019 43350 58835 52101 33858 104 11875 29117 61169 15179 29366 17722 57865 9322 17216 43854 52697 10811 23672 2103 24055 38198 13778 41287 61773 41574 51781 54311 50000 13661 6775 44733 62893 24870 14593 61018 3453 30170 43296 26469 52 19776 31304 2892 6263 50405 13955 20888 39412 945 57130 27764 49384 56369 10395 4469 6758 12313 14361 1197 57042 51358 15024 9145 4228 60453 61373 9294 28148 49049 51478 53824 42584 33749 37390 56581 57818 1290 41552 37903 12142 29629 27099 48370 7154 4501 36100 30134 12482 29236 3009 5622 63237 41768 29154 23570 29920 50458 13195 14283 46430 31627 39618 2008 6924 62058 63796 38967 19750 54409 48449 12161 49070 25211 865 38509 34721 47519 33318 37009 47820 12125 28624 63153 56918 36303 58428 38610 38339 57100 50603 18980 7840 22595 2644 24341 38347 43399 18183 45316 43764 18697 20133 23931 30922 5799 58992 55832 24545 37297 11242 43925 18821 56860 54756 24351 24136 10591 60296 28425 58598 28968 31000 36395 62223 61657 36085 42558 28064 50577 61702 28974 54327 10813 46674 44255 18654 40694 20051 45495 59191 33997 28068 15669 63219 31064 38477 38536 55322 44250 21983 20037 34813 49034 2689 39745 21358 19410 53594 16502 28788 23305 18223 40369 5620 30871 55524 64040 51890 54453 23003 6313 25030 51328 56163 27670 51789 16165 42790 5947 58206 6834 60115 59575 30622 6572 41393 1824 29586 62615 11748 63401 7488 27069 35255 18297 1098 50971 12479 28877 46877 22951 43660 33009 48445 49108 8311 28209 48495 46998 26717 340 1101 32936 63966 48980 52914 23771 24 17405 46692 58165 7052 17923 7866 37667 10941 18886 23528 10209 24471 54426 26313 15711 13286 6309 57742 1508 56356 44503 37721 37606 53755 64055 46276 3908 40543 64263 9515 26146 4180 37089 7791 59106 18897 49641 26077 34073 26878 63286 11420 26316 64331 15037 62908 50011 23621 52732 29254 35074 31409 56375 46932 20587 45752 58572 6338 3610 1415 56677 19563 38457 48756 27286 61554 27525 37179 32856 50299 5983 64040 42071 31305 28677 61410 48923 27156 43855 1908 26085 2268 63588 13136 58784 57448 51104 22550 36936 31292 62007 62216 12121 35183 37679 33370 49174 25950 63913 13257 42985 24823 64228 17233 11151 42271 63814 13287 1033 10477 60374 17974 10248 25459 43804 60701 22168 32981 7048 63456 21090 39872 24131 59174 25674 41931 7422 39687 21288 42078 14394 25540 43470 22105 2925 48348 22198 52643 9190 46102 27250 31067 15124 12799 43649 25580 13808 8253 19602 9225 32919 20720 37633 31223 56626 45567 41203 33196 1474 47719 22640 63885 52717 14807 26598 29808 23065 54801 6092 51276 41553 12308 5561 13805 37413 56748 37358 23052 45575 15059 1853 31596 7134 20354 57065 2140 9838 33439 63597 14545 43961 29362 51261 25210 30563 4429 17423 24357 1599 18482 29521 47908 1599 19050 44876 27382 49028 10733 4831 28506 34716 17102 20300 41086 9006 63460 39641 8417 26497 37501 47325 56842 51393 12768 15329 57934 37811 16220 58679 36225 55991 20988 16988 1223 39219 50181 28209 21007 20066 38569 35193 61329 40768 831 34159 41961 27481 31510 47393 1200 1207 40000 31390 680 2744 25002 3152 15575 19216 38932 22152 27373 43158 36259 98 50008 29554 51745 27321 57440 27035 39350 14974 46044 5227 4636 29676 53939 7262 4908 51198 44719 21813 10289 33599 2499 8055 10594 24673 56551 9250 61341 22986 44152 38927 13390 31428 8973 28309 5903 15936 43901 15657 6041 12620 18581 20341 11549 15213 61984 27155 4092 42417 50661 25608 36161 36088 52429 43926 33993 23321 11478 45922 50349 12042 2500 26793 28685 46371 60032 43660 29728 37509 13413 57554 63777 29088 4837 41566 62957 50818 45387 37259 1706 2673 46675 25543 10536 61395 30433 217 50591 60624 34651 33979 47382 10669 57017 10291 36344 29011 31153 19508 19705 40451 52217 40981 58033 15828 21209 18443 22287 17721 39759 63974 36714 57959 51882 4273 35800 15460 3427 60704 6495 35064 46594 23481 60836 46387 17211 53985 54025 27044 37279 16209 58229 37348 42855 50180 49364 55850 25958 12744 39485 37041 2886 29482 62421 19825 10863 58082 22441 10110 26767 57652 39031 18122 61829 46156 59109 22670 22496 189 4604 38411 23529 48129 49925 43599 55607 34543 14372 24638 22928 54721 23544 44366 18951 58754 30416 57804 23171 9603 13414 37332 6837 30781 2655 50671 16594 8586 40204 25718 8659 7725 14475 56161 12987 26492 62088 55862 38893 3538 6117 46479 22135 63006 60119 21714 3185 10737 26524 41767 8480 20813 22459 24016 55922 13940 22491 35850 52816 33975 11797 60197 48299 26574 30321 6410 62365 35970 62844 48421 29700 2910 34161 18858 9329 38424 56634 63086 36936 50188 37246 36039 23646 14084 38902 11095 4663 2076 50995 34594 5378 46359 2176 7181 5425 46639 41798 35197 13277 19881 17221 50217 7418 28487 58931 31663 62421 10226 53927 43630 39940 21230 2167 47313 59102 33106 16569 53797 42082 15075 54107 28142 29358 51990 62550 45645 33410 43201 14164 46059 13457 27444 7898 48390 23640 46592 9709 26145 45707 31438 35837 18190 54314 7524 5635 7730 9744 61708 53382 61989 9847 45828 40122 52607 30741 46577 55489 43873 34646 55625 53755 34587 62973 29104 37566 19032 28038 56270 50217 11026 29460 16752 40812 21737 57367 7518 63851 54767 63942 30171 38494 44255 17698 3427 53812 47639 16320 30758 45846 41829 15353 12925 27615 1685 55049 5091 10945 7922 7175 24688 39670 44079 58801 36082 27932 3755 16931 38471 43214 28803 7303 58860 39218 22588 44758 53431 51372 29737 60799 62622 50951 9845 23968 49950 22949 29877 21939 41788 5223 10633 24979 45707 5837 15848 6774 33505 37806 8052 64231 7594 48619 56332 55213 38384 57747 33681 45018 50666 31062 57773 63598 163 49241 5179 13474 27211 35001 52581 41431 40850 17685 5066 61781 13608 40537 61025 9063 63408 10598 12662 19630 14913 26295 15691 45942 61140 15717 14428 4369 26646 21527 42643 17414 32887 54047 21486 8595 38080 59345 25474 60692 34515 4518 26043 24712 26846 62218 34011 54621 57614 17700 8270 58824 52881 11060 28767 55030 52899 42151 35028 27072 62112 35826 2777 1698 13806 3750 0 1338739209 +1024 11549 6836 19454 43062 27799 33722 44876 43693 62653 30872 35150 14538 60959 47508 23463 47016 28756 36875 19441 19933 59043 63298 42446 12184 29051 19639 57122 7619 52032 62662 63322 11735 31401 54440 14544 18114 44802 18208 58424 4708 3895 31480 4937 63345 7601 42070 13444 19167 5665 1149 25024 38492 18946 57439 1252 14633 48541 52363 21809 2822 27571 30767 6476 22070 35642 18999 49003 58369 37175 25251 54378 17655 47353 59793 15457 20842 61418 45852 38366 16583 14050 55621 4548 35183 50698 3327 53925 46295 15113 17298 22665 63245 59236 53359 35686 45268 17768 8930 4596 38844 9718 10300 38451 4127 42689 38906 59231 32906 27210 737 61617 25874 63518 21484 30443 9322 55508 33424 25210 48476 15030 306 15671 2612 40126 60519 11737 47806 50767 2142 27601 11920 11750 51829 28501 28290 33347 3510 58783 17398 22028 12389 35929 20831 58665 63460 41219 49607 6080 12735 27561 47458 54056 12347 8258 19250 28517 8118 26385 32784 23974 54045 25517 25894 32915 14718 36023 60834 28475 8815 31344 25350 8527 59815 4306 26741 6257 19038 57467 26402 21209 20431 3081 21796 24301 54905 14799 38474 49974 44216 33859 12195 23431 42758 7398 23556 38097 20526 57198 37732 53727 8815 7727 44250 47800 11332 29859 20753 56746 9741 50845 58004 30186 35990 62154 6195 6556 23617 34435 38328 39930 55434 14493 7257 2517 54160 53157 49795 63219 50193 18735 16431 38354 40971 39523 30638 54465 41864 94 53418 2371 60700 61899 57199 32937 33617 26860 58933 4352 49582 54252 42128 27744 16974 60895 3073 62464 7479 42557 6954 24757 2554 43945 60520 61094 42428 63584 40420 7934 24306 37460 36093 33618 28274 59964 45766 341 29747 37414 13626 47463 16235 61994 13437 39804 61720 47969 42265 26574 27354 51587 58698 61241 56256 416 53946 29924 64088 36698 12490 59906 33212 17045 19208 18678 1506 35333 33490 14373 28326 4416 25268 35073 45672 59187 59277 21653 62775 7051 9909 11201 49425 3004 8618 58286 54981 19470 33674 50921 20347 45590 28440 50894 27455 58672 5786 4950 46250 30521 15898 10034 39176 23325 56782 10611 7678 47969 39060 40679 22813 61546 63960 15801 9104 60405 41102 38076 43271 44451 15932 4304 25127 3741 476 59456 8076 64170 62303 2695 60338 56217 28253 34403 7247 45840 59624 40972 25708 25473 54855 49668 21717 38256 43031 36027 34363 58375 27402 8916 52270 58195 24152 57558 24134 47674 3306 17592 8549 59453 28614 57033 12168 4724 19449 14909 11035 13887 55828 33362 38291 18320 44757 51772 63427 14651 48806 19837 18652 56627 18652 19938 2796 13051 16592 38460 49442 31663 53384 1380 21710 7256 2168 60974 6040 3781 61441 44957 24571 3150 51312 43869 3683 27742 29254 61665 6453 62430 64265 12274 49285 62362 62466 7146 52879 13974 11881 56808 34672 43034 21358 33896 14793 1711 28486 23686 22423 15824 45818 6760 36546 14734 24005 25632 4512 51421 17296 24530 59660 25815 9802 17576 9766 4315 5639 43850 29813 24373 16821 1059 1152 14741 43455 12779 63153 25881 8 32880 35056 7409 8150 10744 11937 11134 40483 20868 32957 61771 44657 15574 42853 50181 44052 53154 58583 38701 18592 4247 36352 61808 30519 55635 1774 58330 5351 16593 27486 39780 7855 5768 54679 11141 283 42137 12247 41922 56311 31068 54822 56278 7423 11876 15984 59305 49590 50715 57588 19888 4628 147 34122 13480 39024 60296 40245 47731 39258 4034 55440 28926 12680 52158 20337 7446 33729 36941 33520 2181 37834 38467 16336 58217 45228 47625 33371 8663 4593 64489 6872 61841 50206 50137 22240 11053 22797 62181 40022 52557 63331 18753 15148 12753 61538 29232 30750 41438 2191 41945 43377 35080 49870 57875 25431 13362 50954 51507 2787 29702 13092 38680 7975 63605 59524 13271 26057 17673 12824 34678 56624 25089 14611 53049 61789 28958 53073 58961 27247 56340 39734 15770 37545 44048 17574 13244 37917 25793 16820 18708 53695 47949 36119 17955 42313 2720 52358 37091 23934 60231 10586 51028 53317 55613 43184 21845 39435 57233 15279 14624 63309 51559 17331 9113 32972 4852 39663 26297 54466 29161 7593 2258 59560 43458 41812 11982 52079 18714 24653 43367 53871 22054 3284 34745 8756 52526 64505 2926 4831 31133 30742 17359 40720 15589 11435 36286 44850 56457 40389 25054 4186 58073 2228 58651 21400 6450 52300 2130 13785 24842 10097 48225 1280 34854 44794 53831 37543 26342 54166 64225 23716 62908 616 61734 38243 26647 44566 4103 30334 47491 44380 9134 2780 40795 41685 46905 11639 52339 4464 3474 38227 49324 55939 43397 46205 47041 15781 20845 30172 2824 29990 58503 62081 2928 36248 799 18059 4138 4018 3174 18072 3476 34365 2699 4068 12325 6519 37523 56834 11198 2969 52901 36763 46331 58063 34628 47879 46755 64297 6999 41088 14962 51131 25446 21840 10821 46102 30146 5651 47560 20623 23859 11491 43156 730 5177 64038 41787 26772 55258 5820 55670 15507 48515 10236 57931 38683 15363 7758 58391 53398 14932 35049 57125 8597 36961 9675 18008 11071 58594 54306 40466 33564 18886 63549 36346 45159 36817 13575 43377 55009 35486 18369 50477 49415 57177 678 17052 28248 34492 52475 5273 51394 7325 50572 60348 56615 53748 39793 48555 18317 19229 16291 8079 8136 16864 25374 59004 39503 37910 14868 63129 4374 48056 50434 50757 30799 34453 12035 21181 45050 43321 54378 8650 40654 42547 59841 21488 54795 2434 15804 64473 147 43138 37801 49338 14628 20474 9188 62495 5454 60599 53823 23241 60374 6200 663 35473 22773 12562 34858 41654 5510 24465 51105 20095 15209 14945 8268 4976 35502 18173 63378 24039 49253 42623 41153 19531 19261 14041 30269 56162 13827 43877 37879 37858 16460 7799 59217 3669 28932 13937 23304 3987 39587 41858 28075 25837 6884 40098 58900 61671 21927 60181 39111 15253 60026 33584 4019 8557 27679 12159 41604 16116 4119 61988 50172 20992 40184 25753 16773 55945 53638 44708 6468 61090 47116 51124 31571 38847 16896 3163 24333 40870 27487 26729 41950 31284 37271 22212 14780 11342 60068 7772 61379 30504 12920 9689 40831 32816 39066 18268 47545 25965 13718 19117 44917 57429 50534 55352 64218 22860 9661 39593 1259 22971 52361 8260 21376 7156 48674 19625 31007 36566 2016 14438 16094 2011 11430 3909 34816 56206 49006 27254 18461 15632 35525 35051 9650 2442 27306 30798 26748 41152 29728 15095 13249 37861 8687 42642 46646 42671 28865 3783 2413 38726 13639 18743 40171 56772 55160 58594 20470 58715 4762 40965 30901 2698 23666 39356 49495 31133 8047 31728 22911 32976 14214 46928 20102 15261 37488 32988 8372 24274 58881 13717 53717 41636 2590 41199 51168 24147 25282 31203 52900 39733 59356 60960 61306 46962 12463 59340 26661 47619 51236 16723 14541 52043 21549 51159 27354 41729 34602 9923 60535 705 1933 1794 15619 8072 43499 28001 50032 14981 52509 23541 7111 2281 8360 57551 27386 30117 11008 58198 27052 40661 26407 55036 19023 37721 63736 13167 1822 4703 64214 14544 8 60876 29001 61404 53257 9457 3936 53134 3845 30152 23377 12846 57190 28768 48027 51736 33325 2439 14015 55148 22460 42847 43862 38588 49722 27049 55071 42118 43720 47463 60837 39974 63039 58184 39212 30350 13676 16882 53593 36834 12936 2177 60135 62944 18686 19858 51820 6047 33114 9334 50097 46218 24313 41973 8950 30954 15928 49145 53093 694 54696 33979 14640 7672 33833 58164 19530 14505 9343 39137 11699 46278 16923 24630 17492 9137 24732 55501 3551 9545 30192 36542 38817 41424 34024 23835 39033 4583 33420 22297 19902 7382 10776 34023 44047 57791 56087 33462 7927 2489 29132 3519 48615 46262 10937 35100 18260 62227 43471 5198 15964 14258 52863 50134 28256 36251 57494 32904 25947 17523 27381 1918 4368 44293 48341 19332 44143 5964 21495 15822 18316 43180 62652 56983 6565 14583 38331 22905 42266 14088 54765 16742 57688 62311 50696 16422 48804 4789 4924 24593 5385 39731 31042 53074 12919 8744 39004 23536 53617 15221 14948 63488 37491 9393 62905 63223 30415 17723 63878 26667 33357 20030 19190 54940 49635 50406 36145 22296 6118 44823 63536 22300 33014 42793 2680 34375 17035 35574 56467 61431 18181 40683 48104 47857 21562 15671 26226 7035 45458 26093 56833 37088 43532 9463 38416 54970 14466 64437 57785 55880 23050 64452 43828 58945 25585 45604 62789 5519 36365 50683 36990 63199 13680 12018 30077 33734 10270 16960 64369 46192 50879 15666 23339 23112 11590 45781 1622 39579 47197 35684 58603 54838 37242 6494 48532 28286 50074 41814 54703 57891 20369 50065 16142 22287 2656 19561 63773 37676 6030 27331 23153 20569 13562 55905 599 17212 47980 53269 3885 7863 44314 19343 40761 45047 20643 1246 49266 42538 26704 54266 11519 33247 6538 3068 11662 15245 44354 51017 9191 8301 5141 40339 14033 441 57748 15132 51156 1961 35371 2745 11129 19097 35593 37070 39244 19885 34616 29513 57507 60215 42711 40985 33499 2259 30954 36927 34832 40276 1616 43080 18706 45097 25613 8126 28349 5174 8032 56401 41386 52306 30886 54796 8671 4494 23980 48947 50816 23367 53127 33413 3140 19735 24784 10491 36100 44494 57681 10988 61056 1569 19713 12918 1540 48492 15251 28920 5358 8447 14015 51297 55011 13027 8732 40076 7081 15351 45784 47555 50391 36158 27028 19739 59207 44130 58104 21646 5937 19549 607 19720 39095 10971 13215 17147 43796 47089 57650 272 27875 8487 25456 48574 61019 17227 63796 916 4358 3305 30296 58140 53708 2244 24294 20503 43291 5890 28827 23504 58960 2735 28289 63670 62891 10365 41632 51399 21173 11181 15218 1107 42582 43556 15348 17164 23614 38075 64374 4903 51878 56145 59463 18902 34484 63964 9747 44016 37197 25014 45486 28205 35856 38485 59642 48663 31643 53654 41890 13658 58822 9429 11269 55145 85 49404 9580 28349 2227 11465 22770 21013 51208 44226 34946 3363 42582 516 31662 26971 19433 9209 57531 34185 5799 993 58578 15365 39247 35059 62006 55041 41175 40798 39135 58997 11314 33611 11043 58628 15578 24329 13156 50069 26438 15408 1778 749 55336 30925 58557 44239 3344 4539 8731 38557 6249 29746 38080 48606 50062 19344 24630 39928 19700 55135 38084 19372 53112 2248 28977 11562 4683 34578 45148 8248 54327 10103 16610 60719 39724 2109 14493 30515 33152 40707 30738 59183 48747 59528 22012 9609 50433 15348 41815 28470 1757 35237 49376 59750 4819 62448 21365 28209 14320 46851 386 38187 59567 44256 54623 52463 3841 40435 21310 30886 64150 10741 45790 60790 30659 34166 40440 31406 11105 28263 14810 29904 62721 16179 40970 44790 47962 14386 688 169 52949 43951 6869 6040 56342 24307 43617 5136 18200 8887 50419 60972 37832 43731 8700 5441 57419 45911 40169 17888 43538 28776 38263 16435 6424 58081 32873 22378 59528 1429 39529 34967 48701 37992 33833 17012 56993 11000 6770 46497 30484 31320 60381 26594 17891 29135 25069 955 36511 53021 33413 51698 63420 14072 44792 543 11321 53111 40341 47551 35897 21810 10623 55200 19827 36628 8446 13721 18012 43354 42144 44261 9305 42272 1425 61020 46289 35029 1845 49983 55279 50117 3719 37838 10462 28476 60457 51104 49450 42331 17587 28714 1938 33488 51785 10364 7799 37111 15827 3523 9839 18554 25772 62325 46877 5517 7335 12549 5145 887 57241 62293 60042 1971 15140 3026 11728 15333 25116 25467 5539 38377 58665 35644 32864 47830 47587 58811 43065 47150 12224 13335 22995 47328 40179 56833 19138 48250 25962 6468 14183 52870 50404 20993 44678 11100 58382 19723 35509 35781 55180 18005 43120 16853 46971 13806 28527 54708 2709 6485 51057 21076 46695 11215 51366 52091 2135 44279 31686 39022 10895 44534 1067 2314 25191 2319 5091 10667 16813 22006 63486 58224 10404 43126 48237 4460 1749 32960 33776 21923 21485 35214 18344 4166 53537 62061 29385 45320 33224 62567 49746 4250 41643 27781 28998 29958 54713 10366 27959 21958 44309 56936 23910 32943 44812 62344 17813 55246 37392 9676 20265 60801 15727 8466 27969 11092 54991 42324 58654 25363 18027 61491 61137 36960 28092 16098 5404 57057 34106 2096 29695 63808 4828 9102 55615 54687 16716 33991 63577 31183 40423 18968 63664 64253 22595 37203 44016 17304 45850 58652 26951 2899 29105 34243 63026 64119 40305 4546 38065 16764 28845 132 40276 12620 58238 10352 31731 53456 43870 19383 57340 33446 31616 42156 26299 47308 9848 54950 23050 54152 43170 23458 58724 59453 16463 40933 59981 24110 10202 55930 54710 25916 57040 59689 19223 42688 47661 57477 52592 2140 14577 34940 40976 15493 19811 3955 63353 58079 57580 605 6397 17645 2343 59554 39290 25509 13260 6832 55684 13596 47078 0 3468410416 +1024 42420 56393 54089 49638 55132 25769 37781 17783 12264 24854 10194 47828 37134 63521 20722 934 49451 48757 49291 40101 58656 44275 3377 43576 62681 25028 60636 41701 52188 56979 4136 38241 35645 46477 61329 48199 20477 59615 55285 4868 24899 56131 37482 31095 49419 49595 24577 12820 7850 29121 44383 9318 52053 29684 22279 38157 31550 54770 59525 9055 13848 26255 44411 46573 6296 35604 61890 45915 3276 38298 35768 63813 15578 61254 2394 54026 37362 6680 8552 34655 4828 37785 33403 56344 46294 37658 5123 9512 50217 48084 59706 60292 51760 20994 62807 33937 60348 59616 56266 11167 145 61947 36948 30498 16655 8165 22309 48027 16934 48744 36091 5033 672 22651 21935 34618 26203 1132 42587 47890 48120 30706 61146 41690 18527 20921 10762 13979 2041 19838 30805 11349 31652 19140 64185 34708 58625 7437 24784 53022 24388 419 57923 47674 47673 42123 22719 46179 62855 47042 19388 4452 53836 56669 1220 17911 57084 29506 36448 8750 44343 45862 29701 2328 31559 10893 39107 55727 50644 1188 16657 8370 7701 17967 12219 10324 21843 46770 29890 2940 31437 5646 8071 44272 1891 570 8027 22493 53171 38539 45192 1390 1109 27186 60678 58695 40995 20169 17473 60919 59640 24673 40388 29854 27636 59430 33242 29943 53321 28609 29803 64445 12802 38149 47396 22447 27473 10271 51003 40057 46630 9944 38820 62573 3263 38709 7017 11746 48888 23540 22443 61386 28685 52703 6683 23794 55335 42015 34652 24478 56403 16185 15838 24271 16319 31689 10731 22320 59394 49149 7627 2010 45888 62524 59237 60556 55907 58083 63830 32872 55434 40302 56798 12694 27501 54546 59404 10390 17703 61996 3023 58608 14486 57245 44445 48488 30320 26212 9767 60699 36294 21850 62823 48461 63186 36985 30316 25431 15926 47778 11906 19313 19151 21677 40026 61069 2122 888 7552 64059 55784 24573 20528 38710 37607 53004 33675 43547 36489 14364 14023 22398 5943 23000 21185 947 51917 41393 35565 23571 46518 25042 39015 25102 3690 37521 61693 61633 42703 8456 44960 880 5112 60196 33320 47793 5834 10778 24233 61408 57174 4182 49476 12342 22510 34942 3538 30467 15052 33154 37866 7983 24792 61137 33396 63853 26157 8770 11743 40739 7674 47447 19589 30913 60202 44796 2523 59255 29387 15244 40758 51913 13064 18453 57240 58399 58437 59268 12396 26622 22912 44311 45855 40143 54506 4069 2177 38445 33054 14571 64384 60531 60398 64460 63013 58708 15457 9023 62147 36339 22204 60434 9133 56241 63986 15232 53674 22771 6905 7370 61012 40344 1539 27550 39784 55816 56456 13942 29604 2624 64218 41848 36574 11224 34380 20947 166 28652 22966 57812 43805 27928 34083 34821 8902 18703 38858 63162 62526 47796 11545 29085 5381 59373 56363 30695 50883 4990 50570 52260 54727 21294 61118 50449 26088 29135 38268 63307 38887 11991 21112 54541 26559 43585 58324 40544 28408 52035 43267 27782 29667 1902 23706 27822 62678 40783 5415 19754 26014 7455 18809 5712 59391 11551 19428 46143 24237 20292 58586 50329 40963 36515 39382 287 33585 50350 24637 54121 30681 19240 52339 13231 41386 24097 59336 30751 3868 53982 27409 14354 48397 26766 9028 33565 39269 31424 26306 54336 12413 43001 43056 33793 55573 44743 6148 60414 33524 25177 27964 13758 13450 44104 34725 42633 47886 46647 50351 41537 30105 20765 47190 59197 3266 36310 28080 37597 29674 20004 63378 12518 30457 57168 17823 30868 51627 57129 38563 21585 6239 28062 43838 5778 13736 33850 12122 33571 61253 18688 63686 5396 52599 60938 20634 48627 17969 39399 8125 38382 1469 5612 24392 58646 32768 47302 61507 33062 37205 35937 83 27904 47577 12929 42931 55241 56607 12982 48443 3286 19956 10115 63217 39229 59220 20879 53963 16791 59059 44570 16233 51357 21144 5987 23382 809 53897 21944 12657 18463 57838 2821 64459 13504 29392 39881 15762 5046 12540 845 28081 58234 23515 14986 25484 5544 17300 48831 64123 2410 49985 39207 56180 34944 60353 57690 54854 21941 22827 35444 11248 35218 61019 43492 29171 13817 53726 42725 6923 26793 19970 20169 4409 25917 43581 24100 42099 43196 38736 30559 4350 45357 55537 55121 52979 40403 30470 36038 29087 5348 6400 41057 30273 21843 44575 64358 40973 52690 48702 33207 25689 456 39918 8721 57867 8648 25646 19176 26194 46187 37435 14501 48192 17579 30741 43765 40506 51881 55944 31440 31171 3483 53302 10831 57694 13285 42736 63066 10090 12377 42681 54060 1249 14239 2517 63183 63693 50350 59341 30656 46509 17239 22842 13379 7170 25941 8420 2657 21760 63639 24993 60534 39195 41960 16284 16317 34960 20190 18210 43869 7193 20716 37391 16700 9652 16200 51139 56991 52219 25699 5420 58083 12807 50760 31512 57119 41195 1748 37338 61851 45402 23868 40534 15306 17203 63325 55190 58576 42929 8298 9984 24247 27541 763 22397 11905 26190 29917 51383 45876 33832 11959 58223 33541 54701 61323 12385 9901 16308 38675 38003 52269 26393 49874 14317 33165 17937 29781 59115 1595 53576 25138 47799 54665 28231 50468 28304 47264 43542 14316 9160 52733 12081 55072 34130 15852 61977 22794 17983 3239 17823 15407 21270 35180 9222 33643 3094 44067 64365 9788 18123 27666 16808 53900 60720 9364 8119 6420 12341 45359 60900 13098 62022 39987 7520 63317 12409 64135 15855 7096 38365 13363 15182 2441 25897 50636 50924 28403 19694 17835 23246 53008 6823 886 19972 23652 43955 63952 8111 52871 25181 61252 38230 39574 42319 52669 20946 19138 49503 23328 25505 1885 18514 21803 54485 43691 1989 16943 48207 5267 21508 36803 48063 41326 39847 28635 14634 22900 22546 6247 22809 43267 58279 25175 37585 11491 53301 53260 20576 15210 61212 43427 50076 18328 9586 36163 27037 62481 25529 13939 47050 30481 54814 56975 4550 50562 56869 36858 13023 41986 62970 33310 62625 24093 41464 8258 57097 48430 53677 14270 27657 42513 15879 13444 53631 2606 45042 7826 22528 60505 9727 40797 21911 12353 10825 42826 14422 10140 43650 46753 54635 30953 22673 61886 37100 21783 11174 25111 38736 12828 60011 62997 19982 15035 27189 10608 35261 62246 33573 21512 11729 24330 12712 18034 54171 15854 48978 49289 45362 41332 60721 14062 3118 34478 19157 27788 46220 53864 53589 52433 2464 46501 884 27775 16802 48629 17270 10739 57294 30994 48222 20791 28286 49009 1327 59198 2521 12105 50131 31688 23486 58582 21507 46919 19082 52278 63700 37701 18962 2114 13638 55947 57930 28790 28441 12741 53430 11540 18952 6355 43389 21317 57991 45840 64451 48036 40336 52336 21057 49844 40236 25019 46574 43160 8283 1245 24279 1284 54352 9786 3352 46514 7933 3784 27433 53610 57096 36454 59672 49337 38693 46481 22916 21313 12167 47077 13830 62572 20239 19409 61925 27154 24545 11709 58536 37114 15108 36466 32769 54237 41685 36731 4082 48782 48237 53194 49514 55556 14619 10626 35656 7215 46607 6547 12430 62174 38314 16914 24141 23230 3006 44546 39725 23678 62704 36121 12978 46677 58847 63718 38958 9766 40526 37379 55405 54571 43996 50537 56079 17560 56109 39797 31629 23949 64368 64486 7763 35747 21419 42205 16260 26232 41609 7134 26348 25854 60170 36438 19390 1916 27094 19334 8685 3306 25894 24747 18693 60360 4430 25966 63714 61635 41338 8224 21998 13438 46389 29625 19349 59438 58775 34355 29789 15429 59935 24980 50020 47653 50343 49665 18790 18333 25115 20852 29368 20714 56831 27549 57258 60563 35135 6426 6805 30281 24342 7402 48391 37146 42063 19766 43532 4838 4011 5366 10379 37811 1348 57350 49494 1970 51795 23178 26814 7759 20451 35487 4575 58675 34524 46297 63635 30998 33560 60549 44768 62604 51791 47251 52005 35942 60760 44681 39774 12668 35529 717 57738 52059 64024 40985 30148 55059 12269 6807 38394 8847 24375 14567 4664 12244 57472 44926 25769 60799 1648 35254 27259 31708 52962 21690 34379 53920 29926 50739 61812 57258 21950 25047 55612 2836 8399 52418 39932 33394 37122 28421 24618 15038 26789 53836 38208 23501 47961 30249 24899 41257 57436 12279 9975 34176 12852 20661 15826 51929 38791 59453 6251 43827 28286 6783 52881 50958 23892 62456 53975 62717 48189 39653 52 47657 36454 28416 17616 41356 54704 6783 18619 51116 15729 46709 2005 14923 16997 59571 32979 59755 56351 19960 54006 15355 39583 30490 61453 40523 12852 1583 54603 34941 56049 10410 54727 61014 12855 20048 52861 23739 61172 23652 44950 15342 41157 43108 15944 11144 40522 56892 44400 2470 14423 46538 15989 26159 216 3141 45109 7856 25049 52197 46290 20787 41924 9167 51068 37556 5112 31422 24889 43990 45575 47260 39853 9118 44839 60244 237 40023 6885 3560 46522 36360 36994 17111 35755 37661 50359 16026 36197 54316 27285 31403 19872 51684 12142 37544 10962 63034 48238 15332 52394 54230 11709 62014 47774 28288 63627 53680 13172 14879 4351 5891 38464 55592 28549 46402 10063 59243 53226 11523 2304 10793 13215 19545 61928 26276 49782 9990 15329 5720 31414 25668 49742 59819 45038 61007 36497 54700 45943 40268 37447 58414 56941 20654 40338 228 1054 60031 16028 45931 33758 55887 38621 55763 1151 63452 894 55310 236 51663 55340 59156 55663 41124 27435 38386 42266 28723 9468 38654 27978 57892 57659 55307 15422 1450 35208 56920 49603 12300 12676 39744 38759 42067 39174 14363 43944 5376 12656 48621 5574 4313 38837 33723 7171 34289 17313 39435 23100 48434 44913 451 41465 7592 3075 26480 18287 22555 8376 63687 41662 16745 27004 48181 5429 30327 17879 35669 50428 19038 28838 22441 60786 54133 8648 40585 31043 56283 28917 11320 62629 7889 38435 1684 59184 45757 36546 45717 41856 28922 771 63241 29039 51709 36901 29759 10552 32986 596 41245 19789 6891 10863 7606 14490 40385 57728 59688 30347 34721 1816 30720 22473 15310 59375 27606 40406 26861 20071 13023 16848 62575 5902 58306 58744 5862 51138 44969 41246 10772 56527 37556 12540 27208 6937 54119 55632 45964 24886 19556 46087 59005 29073 9812 14258 27996 18646 59522 48453 24418 59222 56978 25080 3715 196 28121 45303 57662 28762 33022 63220 1236 7466 28803 49926 1270 33102 35052 60610 22509 59914 47203 20837 50945 33875 30145 1338 24594 55197 20708 4138 34255 25677 34437 60540 12399 30854 30028 51303 3712 60465 47116 63528 56091 3909 13299 50371 18774 28767 56980 61858 58541 4176 7453 25441 59167 64490 42712 47941 47193 60800 43809 15628 22468 38674 22790 1937 24196 11648 49388 11040 19385 39695 36762 2427 19743 26591 5756 2852 23787 33134 14905 57768 50109 19323 34497 58400 37061 40221 7666 23193 35713 23344 10322 19730 31698 49948 64092 54171 53436 42227 39241 34004 29480 22939 11621 44453 9815 2295 51392 4385 61709 10713 23079 15946 1251 56967 14317 33475 2842 23744 3157 18932 57008 26203 25022 36184 28019 2776 62690 23483 45895 19280 9852 39044 388 29910 18400 26295 37008 56801 13758 56580 63087 44273 53804 19923 28200 25782 4996 24118 50361 55720 55946 56150 63106 9321 57193 35511 59672 4719 56123 19904 6382 61496 46491 52916 55992 47181 7851 13791 27502 46478 55577 37105 50462 62423 7477 49530 20799 21034 7308 56352 28084 18855 34256 61052 21212 20319 45858 52790 42892 44110 60462 19569 46890 38031 4679 58555 21934 62251 43265 7989 63442 24772 39665 52164 17810 47474 1205 39717 13237 14555 7303 23068 8538 51735 38965 15196 52332 28352 399 21136 63894 63353 10033 55800 57004 38930 365 31729 18587 49469 44752 19874 2530 30787 48635 41684 11670 40844 50056 6005 28679 31517 13310 14692 34421 31670 41893 46501 30427 51089 60856 38828 59456 63243 12445 29036 60867 10708 64259 61357 21074 55030 43783 58895 53277 10716 52021 5338 10816 13053 8447 41017 38824 47536 9406 44300 61838 52425 57625 4252 44032 4592 63451 12152 45708 59450 95 26192 2274 12116 10494 48612 58627 13109 16356 63071 61566 32915 63434 51451 48020 6535 19883 29905 56550 37951 64285 45859 22688 24242 51056 16341 20060 46943 8161 41703 22330 17004 28617 25347 27779 9907 47149 34652 21186 16779 49940 8453 4138 16240 15201 5305 57960 29894 1763 48120 47709 5963 8736 45391 13023 35342 57425 59313 7444 20103 25670 8950 24091 18624 36026 43047 36124 51278 54880 56482 14759 8988 5433 6553 11636 39584 40432 28840 43969 9164 35932 33059 55080 14936 46069 49895 45863 40211 14807 30078 40172 20140 13631 23472 12933 13123 48304 15057 20928 48618 37365 26312 11773 17992 13441 30899 16651 17088 52705 9950 50049 37868 61522 41784 1804 18131 62221 28411 50356 22705 53731 48702 28774 27667 54175 47670 3536 41700 39060 317 57203 57168 40152 50946 14109 36296 21688 28250 37790 64044 4522 35251 16911 1131753182 3470198184 +1024 7505 20501 55750 17057 11593 54979 46554 9246 40983 14790 29039 63760 34911 42392 30222 2966 26915 43381 30225 45376 16489 17500 49470 35241 1031 21477 16813 19327 61836 9244 33969 25981 46273 50340 50585 49875 15682 12689 14672 22003 53847 55128 54132 45991 26695 14306 59345 28490 5852 1202 13721 27910 23274 25759 57038 21652 41009 16209 23273 35034 64159 60381 33500 56375 39776 13836 37583 19708 2924 11955 18845 54406 26605 34447 30609 24967 38402 12545 44246 39392 34204 10095 53990 53668 51478 30793 18521 59487 7596 12542 2613 49792 61257 26265 22588 17036 60266 30348 21253 23651 15710 47767 49952 4763 55947 19222 18741 3283 41567 56471 23635 55061 39874 52574 60143 54531 53807 3794 22611 27160 29426 35458 41939 35972 15642 18533 899 57330 62045 21536 38330 8506 40602 55352 24690 22719 34054 25371 56477 21224 33210 10947 62080 16853 15097 30870 27612 51825 47570 15844 28453 33902 63998 41748 25138 53265 58946 4824 5064 56293 7871 2533 12557 62062 57271 22044 20014 6568 3816 17371 60735 25246 48167 48660 47812 13753 24072 12252 13479 62354 51971 39884 57462 43777 13692 51445 30429 24812 3195 9035 45029 21528 54801 42202 54802 30723 26972 17746 55382 50168 64426 2467 28974 54504 45909 28238 9918 34819 4405 47977 36075 38270 54826 17370 12695 7059 22654 14485 30011 53174 19413 61370 58272 62715 16959 50541 17699 12348 11762 14065 6909 37811 11194 29787 61423 3029 44602 54805 57173 50512 4360 22745 60355 13440 48338 23274 36794 8240 53834 29125 48522 42886 12152 6292 58678 19264 16389 62972 63307 58541 59115 52174 44568 27103 45536 45792 38571 18415 33877 1722 31462 64025 50377 9050 10076 48230 42378 5931 61270 53773 16485 11692 60574 16301 46252 28623 1249 19478 51402 40463 17347 57454 13448 12444 63824 57925 4887 12205 38892 40619 16531 1043 2920 60183 24889 23382 27004 9607 2320 42519 36653 14550 33837 37395 30522 49130 56316 1331 5849 27771 52410 5517 45367 19223 17408 3640 23915 18128 33679 7461 29304 63630 3535 16813 38144 24571 60206 29009 19236 2561 8923 20062 52733 23179 24731 23106 46583 12874 53286 14895 10048 57929 8373 16111 14996 39583 48295 51263 47104 30805 12727 61091 35316 59562 13939 45495 17889 41207 30309 38474 5654 48336 19204 4116 10048 38961 56440 8079 8979 35429 48782 37996 51944 62895 14878 56648 59168 37386 42927 8521 48364 54425 12751 30803 51798 4179 13600 43949 50797 58388 26227 40467 18806 31252 1608 46371 17221 33564 55037 54435 43476 49487 39395 21077 14059 10676 48201 14656 25486 27176 13072 55768 23660 20716 55580 28191 2931 50920 20662 54965 11798 8718 51255 41414 737 41779 15499 57161 36809 2061 22744 63811 22157 2107 7930 28053 19922 43924 50418 60245 40444 18104 53268 19192 57240 9586 17117 24982 9630 36653 50346 61736 21836 30025 44844 9700 42854 7329 42815 39155 44147 6585 49776 36439 20140 25283 1650 42424 54177 4379 6503 53839 14894 55519 12668 8022 63582 21536 33463 49520 48742 46127 21873 48192 1458 51513 44709 38437 20167 30570 55334 47562 38885 47659 48326 60216 24517 50158 17920 28375 17062 9877 30523 56058 24720 15098 13614 51369 19631 18155 14731 58073 187 3353 22967 27159 1229 57352 22770 20805 2522 55531 5140 19401 63499 38556 3171 12013 54354 34607 63547 30552 46807 18924 19617 48126 5138 31411 26792 53049 45141 58292 10682 63094 44776 52129 11969 29983 54334 22219 37048 33786 52948 20798 182 9950 8788 14658 60467 41413 3049 36908 12977 42815 30063 37595 41080 18135 3348 23658 52601 1233 21920 38072 736 24435 7223 50264 6970 58847 36017 26674 47203 35248 48968 1259 60252 12504 61716 34791 42947 57239 62940 3345 61610 19334 22231 53527 30373 64184 12497 749 13503 41539 48129 9454 22150 40038 27272 34523 2459 58419 25116 560 53642 21859 10827 28597 29093 14319 23185 38277 25523 36932 21032 30376 45989 33641 22630 35090 38124 31251 29406 55997 61496 23646 12753 51612 11913 29263 32968 60563 64361 22268 8820 47837 56592 55669 64339 18709 6858 8069 49475 41988 36585 4615 6725 39592 19801 51681 57850 6818 3905 3784 48125 55309 49039 55712 26683 63291 58355 51858 34808 52785 227 24751 38201 22983 51543 52423 25218 11741 43661 37542 13537 5023 30096 56097 49979 5265 45823 47632 56108 62051 29754 46473 56100 41858 46054 41008 45334 30388 7340 40371 17693 15974 40903 38444 7446 17064 60595 38836 2995 47153 9663 35256 10728 36417 50451 18138 19978 36772 3975 27501 24829 37020 6833 45281 42927 5482 57560 46546 50831 28687 14257 39833 27821 24753 46450 42453 46789 15420 2639 8962 13634 19129 60171 20479 20667 28551 24557 58852 52978 34667 61669 41879 44011 42987 63094 61494 53069 51897 29161 3776 34334 22154 9128 48813 46249 60796 39991 33293 7501 9995 47075 61820 24685 13796 2050 36917 31528 43308 52536 23924 31743 8189 14604 2627 64039 58933 28985 48320 1354 56672 8647 56177 62397 15773 13321 23197 41132 57137 32828 63710 44441 12238 36324 3717 33264 50664 52848 23935 52258 61432 54423 55070 10372 46355 22210 61815 23921 61428 39157 31257 29742 14957 36729 58590 31408 54741 47959 59241 28721 14838 4266 8330 7425 8278 21502 30576 7137 34108 30247 24974 23030 18082 38014 2074 23784 23199 64104 1334 58440 22795 56280 27616 40098 34788 50508 50883 18927 33077 7650 40358 23008 7269 9264 15635 39879 50619 63837 62732 53205 62748 25987 58821 46064 54006 19113 20566 53978 48353 10591 53387 49721 40007 27434 21666 18643 35340 1628 2903 13742 8158 18294 31601 52913 59415 51220 32994 37978 45260 34435 34364 25099 60628 37929 11940 799 57575 5965 5538 2051 2509 40546 17909 8687 29946 58345 11436 30272 22344 56336 19361 4486 50226 12397 56545 5074 5796 51690 26898 50663 4540 7148 19844 56035 51258 52987 46397 11395 24991 46168 51834 3601 46030 64413 21513 44114 62867 14237 45404 35140 40098 24981 40045 28530 10656 57155 21172 52709 30506 39375 37069 51680 52763 6444 14485 20232 5982 54792 59119 4693 62125 59135 5076 14603 3017 47330 5246 20641 2247 59682 11818 39311 24301 40436 3062 18501 55488 8209 50273 18587 14288 61779 8119 53839 2998 52652 20366 51703 40654 2387 39669 9650 11129 8125 13783 49052 13957 30978 12294 43970 7937 15084 45584 25238 34488 36895 43285 4336 37105 31699 23335 58252 47156 4881 10628 22537 49094 12361 50021 62956 19984 5691 4909 53897 18514 13973 17016 15344 47483 63443 11737 42057 37216 39089 3115 36953 42906 48525 57832 17687 46598 51086 269 36574 22997 58847 27189 49496 9577 12745 50510 15626 15077 44011 61621 6516 8997 20503 5404 31526 38138 360 35655 34750 44261 16936 12970 9417 23874 39237 16960 7995 61824 52377 42594 10202 10562 19084 19346 59233 4116 41036 33971 59555 39731 8031 51256 12626 62626 59750 20547 60965 15196 36617 51773 49378 44106 10260 35514 21940 6158 9913 415 2627 51631 12910 29971 19848 47387 57003 53001 14518 38323 1565 38569 63820 44387 23269 30361 15428 36956 58091 31537 55141 19452 6894 43647 23977 29530 24165 43020 18270 27011 58289 5785 45642 39541 37823 58098 38010 19176 49045 50526 8424 3332 41974 5058 28758 24699 12985 12345 30096 13848 14006 63490 50090 3879 12148 56300 9199 10973 55607 49496 8655 3652 38454 59443 28611 557 63791 5131 57799 11934 7370 52929 33616 155 32784 27559 55486 38420 30576 53870 21927 47821 1433 15099 78 37335 595 85 30150 54722 39778 64025 35650 22171 64082 57686 52181 43960 62527 46 29554 4912 62965 45128 5597 39547 25594 26669 4284 42185 54854 772 19153 8599 28247 23149 62210 7185 21164 8376 8976 36553 133 60383 47550 23476 29648 39750 43150 34613 18790 19047 59572 60961 50884 63530 21703 6377 53626 16553 3454 36373 11964 21199 25671 56844 34748 14412 58179 23136 64382 366 35594 51693 47186 29188 5627 34981 31619 51233 3782 24784 16460 16897 8983 35128 35924 58468 10532 59482 53285 7034 7285 26700 38469 54097 26582 17238 153 58737 43270 9153 15496 45237 51471 17430 53725 43796 6275 12306 51199 17059 49384 38395 15067 6745 2672 21822 47680 51543 31175 52797 8433 24478 2092 1758 56703 58968 46226 28998 19012 34090 13349 15979 33893 33191 35255 31598 50218 47682 60501 46482 252 57060 7132 61170 41292 17312 21329 37602 36658 47045 7349 11467 49291 61422 21132 837 14253 3424 55930 55915 57376 40162 14491 38367 29224 24325 57871 35570 23300 40608 60064 2919 23420 4860 53420 13451 10004 56762 14961 12832 58202 21606 62042 24938 46299 55944 13228 16183 14806 40391 20587 38445 19963 29155 38875 26638 5036 13432 10124 20468 14512 34770 26173 18864 23277 48371 43231 1121 19740 51955 41944 11399 46935 64188 58048 44271 39091 34016 41498 4102 53408 2053 50077 45461 11436 18510 20143 54840 7919 33411 49979 51868 14765 58762 42922 4673 3888 45993 28701 13237 53947 18870 40850 28655 20849 4380 25763 13099 19683 49638 23391 23774 35506 48488 63835 48222 20435 12003 8097 15248 15786 22248 37020 12272 50685 38885 56403 18810 28389 61822 35979 63913 41125 46833 9811 23048 25741 25217 52284 12370 63414 51485 686 5443 47306 7673 32793 36959 12533 24415 15509 12400 18186 301 55566 11562 63055 17430 33918 51823 3489 39996 25320 57403 40965 34490 60591 368 38105 58418 11771 58304 9740 37444 254 55418 17998 4594 24133 49577 45423 59333 50339 44686 14944 25396 17591 27093 19854 50960 49669 23653 27856 62367 47059 36349 11686 34693 25519 23555 49038 35175 53471 21524 25887 10480 9976 25056 42664 45396 23170 60146 38671 50545 36822 20662 43827 5968 13300 2808 2290 64208 29891 19811 50413 36331 47642 52739 9271 510 25067 27069 56292 28203 30940 20407 56062 4344 54710 57541 38226 11164 39144 46925 9783 28191 53164 47853 16486 18757 470 11553 63344 63633 34400 52824 52473 51489 59740 21898 9367 64419 58060 62428 53404 55146 59029 30184 21941 54453 29671 60633 38967 18917 18526 21858 11892 49692 1658 15681 29085 39731 39696 46166 20903 51372 26757 19667 64019 26358 46068 486 2582 13954 14475 18047 37405 13139 20976 43641 25045 10333 8407 54247 6509 60943 59235 23801 34888 25682 63604 18198 51723 50732 20275 5022 39595 40615 52877 30483 57125 58422 57544 62258 13939 11846 56488 1918 43447 52029 59659 61713 45683 29345 20159 31224 12518 30920 10896 9696 25064 29824 33726 51399 62636 63876 12784 22309 47280 37427 27785 10324 44279 24574 6126 45699 60621 12191 29415 62840 25852 28030 14533 59030 47303 19885 30570 43065 7146 56360 52557 28969 60779 57526 18164 33339 56509 50008 12426 30701 39834 48070 4276 21044 63085 8850 16697 16294 37331 4957 6611 51164 2231 28417 58389 64473 11753 37720 6674 19109 50524 31525 27951 3979 37274 62945 19986 2216 18228 49989 3995 24321 30783 15798 17991 53116 769 13899 24603 46769 6140 5158 24119 35420 48445 48971 54289 23181 51916 21775 37582 42866 6586 16000 63640 21938 5070 38729 21732 13041 8130 39660 22964 54216 8393 1189 47422 21002 8739 15025 41299 36286 58422 58003 56954 21531 13851 11944 8763 42401 35526 46647 50583 53847 36288 47219 38090 21845 45282 21912 3196 21039 30666 34246 47499 5617 63411 24786 58927 15346 38252 13200 42611 61484 59157 44022 23263 39949 27471 27318 28149 26476 31531 43367 49564 544 31388 508 49641 21682 15907 39968 56454 47276 54848 13061 21172 24171 706 9425 62609 1143 37826 1178 3430 38188 2242 31732 36027 41330 48833 45906 25332 56433 30428 63072 57461 19956 53003 25582 58944 8305 34079 40828 53271 58372 20822 62481 44791 20473 8420 55162 4203 55043 40462 4331 25842 9173 59144 28240 60228 19627 22573 49712 11075 35384 54505 55463 23281 31182 57008 19760 24667 13296 59892 43001 4352 38829 49887 59639 17145 14977 60621 2547 10931 37734 19332 52625 7430 34525 13280 12344 1518 50536 11134 13487 6269 50995 15009 39557 60054 22056 35547 59587 58843 2355 52743 23136 8402 12550 46959 42921 62695 45631 38262 28587 31020 11279 28963 4813 40788 13126 62862 17702 42514 18072 49644 4896 35280 59823 30479 25659 62861 11178 58761 15453 31681 25277 30098 27666 42645 24941 50664 3159 12442 34285 52793 3334 25740 21524 58155 11394 56401 40406 60716 4594 40834 55876 36608 17624 25922 53207 5429 58705 44924 42865 27057 59334 34346 9184 28633 17818 20250 43434 25094 59879 10271 24455 10102 4610 44645 45787 48550 63871 18215 2046 57899 54500 15443 34462 64088 59658 62099 6526 13959 12368 10058 49712 18529 3789 30644 4235 25585 15769 22659 3844 34257 5880 31107 44368 0 3459771333 +1024 64067 10397 61140 61676 33406 7113 52598 5483 43383 63434 5272 30859 12479 8026 25339 10932 19742 28012 36565 12627 43934 10668 43989 41201 59593 16347 34698 25282 20592 12306 22764 46694 44871 11624 17256 44090 18514 25953 47432 3480 55719 55224 57517 36593 37381 44927 52470 21425 56298 845 49805 29197 13152 63457 54685 2928 27902 338 20073 51278 61187 168 24244 14162 52941 3597 45148 30000 4645 24808 59080 56464 63804 51924 17605 29304 64070 29271 10679 39992 456 48997 37153 59170 60856 8673 5038 31019 24906 29867 58601 24613 34415 54703 36828 57811 3525 60183 43913 35327 14195 10675 8508 35577 61242 59274 52792 4520 53624 60646 42526 25306 21754 57754 25959 16223 30194 34948 26142 51650 38699 5105 63729 35903 29524 64141 1165 49635 38693 40422 59248 33112 25312 53490 33129 55702 40029 13732 26716 50616 6290 29210 54722 47659 2520 25661 28193 50293 41137 38129 29420 64084 2528 59031 57776 30705 48909 59008 6887 29652 24286 55139 28696 24473 53406 61528 24520 21647 6647 35099 54316 28461 13543 58385 15511 47809 52450 23875 29376 18319 54181 61438 49747 29482 61927 49949 59336 21573 8804 51786 31083 6877 29145 35480 39877 47347 58171 15061 24633 36311 38012 24899 7654 22927 51554 24483 49596 53404 56292 60759 55570 47583 39702 60396 790 29352 5655 40080 44304 38221 39334 22840 56672 19815 38296 15886 46583 1748 13864 737 60649 63319 39048 4055 49449 12846 13012 63149 47675 16716 46773 28451 7962 56576 43309 29623 24895 49963 24486 40231 42293 327 58425 62155 34635 9302 53438 27415 47323 56592 42148 6205 6575 4032 38360 5767 57166 16494 58469 12525 1710 23654 64151 53363 5338 18471 16503 28796 25562 10270 47208 28531 35940 49963 790 3702 8545 322 55430 36707 20493 8081 36919 42227 26801 24451 11931 14836 15924 1654 13720 61858 15781 59962 1163 56218 63183 52328 19658 12908 15360 41358 28670 6811 6598 37105 35979 19603 47996 34287 46884 9908 53470 53744 33013 59019 62478 59116 24707 51499 26309 62551 807 2971 62604 56398 34811 10382 17505 2796 28218 1189 54039 28808 24177 12790 904 61337 62811 30352 20115 38204 20915 23023 5993 25721 37949 38788 48667 10712 12190 22726 8987 22757 40690 33449 28433 28375 3222 64498 48721 62802 11898 13849 17402 36916 43510 29803 39126 22583 49054 4155 44400 39774 16979 57994 2151 44995 18116 18508 16809 11880 31100 63736 16566 20405 46244 14282 2118 13944 55430 41663 2712 57138 31238 33651 60569 47426 64466 9677 31258 10945 29147 4085 43115 43723 10050 29516 4120 57214 19857 10587 34508 10780 644 10624 18792 40145 43920 15576 13216 19335 35149 51363 31665 17361 17834 13577 51022 19876 47899 42996 9287 16914 54107 61307 23208 21215 20641 61974 54877 13619 3139 52213 41829 31409 44956 46869 3897 45757 45222 18714 52075 51618 29102 4889 38887 4542 25565 40994 14476 6523 23768 11195 24169 17397 45836 4214 53999 36479 42634 55437 12360 7584 15864 5980 21171 21173 1201 29198 1228 36173 10849 58457 27464 15793 21897 41852 12741 50591 56035 59356 20543 62656 59523 54901 16511 17957 37693 17184 2945 61496 43305 51527 19881 25749 52505 31151 16501 40568 13006 22807 1807 36428 17534 64208 35086 50854 11673 57793 36446 43998 58381 29130 18207 15749 39929 24128 36399 20182 21832 27874 55587 54725 439 57163 15428 47793 54902 27777 12559 20919 28313 41899 28656 19697 55334 53022 9583 21473 58608 42839 14267 34253 49242 59343 18587 20584 23189 22240 8038 21961 64386 1352 55628 34881 57309 8278 26962 57937 26268 10205 5439 1301 5631 50214 43125 53411 40041 56589 36527 10265 9670 60212 27578 36787 26428 19814 49758 10608 26007 33115 6245 52354 54567 47952 45156 60285 10866 62796 42561 49212 20355 31254 59476 50616 46259 52079 33245 24439 20852 39418 60107 4361 42650 27807 46276 54451 38113 30539 7614 43707 53763 30853 38098 24681 14940 53937 40985 60796 34730 27988 39136 17163 34549 59052 1885 43761 52228 13527 61633 53847 43391 25397 45341 55855 12041 33825 1118 30662 1468 1555 28381 28025 49016 62453 18038 14507 50962 55243 29809 24863 45966 58834 44850 46622 21947 47771 52441 50066 25811 36048 62210 32995 49668 51198 59149 7918 50861 22173 16496 41410 36111 45338 7869 60524 41728 52741 3185 35948 42062 46456 64179 49261 8283 28105 11897 485 9820 30371 26506 35922 60943 64174 41954 35149 42096 4839 62839 60719 26615 54564 12184 62714 829 18161 15380 46243 50822 62461 28617 5224 20076 51011 8653 1341 50988 2482 19081 43782 1711 56526 52031 44739 10938 23195 36932 53175 42402 50359 36201 13321 44747 27288 64348 36313 18985 56427 52984 20472 45267 4700 13251 41061 28563 44811 43599 51411 30830 42763 34001 34506 6084 13503 2535 794 54526 45094 18694 13549 25442 50375 23876 61572 25105 14948 47949 16069 27750 31341 48995 43537 14893 4784 14848 4723 51969 52079 57192 45879 40739 38644 41916 10604 49816 5920 25128 10727 22609 37852 57145 39019 48468 21409 9646 14781 38319 51143 8899 4616 56640 9056 51333 52808 27533 38339 19124 62851 12360 53414 57167 46093 46833 6542 27944 45242 11025 4244 11984 64033 15156 34893 59536 30989 41099 11284 5584 15622 62331 42259 51205 62197 16846 45426 44621 44977 17783 27168 13326 20981 28994 62691 9608 19595 8416 178 8359 18226 45850 29176 1258 3771 19532 40601 62819 6327 354 43703 50033 45104 4812 54532 63420 53168 1534 144 17350 39285 34886 18371 38974 47232 42712 8887 35356 56517 20692 541 53066 27940 27556 29393 57477 6899 11527 17430 29320 17442 22073 24099 49033 21274 15608 50871 46848 31017 39988 36111 48886 8476 63584 5166 10658 24845 19097 40022 975 14562 13485 53895 45403 7259 22095 14888 15426 57696 6417 62417 15318 25687 61678 51990 40926 20206 11812 21405 52568 38337 63082 49616 47175 58838 37320 910 40474 13519 53463 24915 12547 40781 45772 3508 50919 23684 40049 42976 48439 27616 12773 35559 17260 36068 10447 30021 28748 17468 43893 12716 38246 21175 24493 26026 13645 25700 37817 4397 12129 26239 56109 16314 38137 9384 19744 3349 50581 16241 29686 23407 1198 40369 3375 36485 11275 38851 7027 63391 45418 6135 22648 60151 50295 12230 10736 12473 52783 31118 11097 12191 40672 37475 20386 2198 12005 54398 8134 58614 17500 24589 51751 29150 54617 56602 54590 9253 44257 33770 27970 57395 11790 14003 22941 56614 63994 15558 7717 2945 39923 20397 5177 28277 51461 39049 2914 23951 11308 26378 30132 53428 15994 50880 44021 56096 5404 46092 55258 53562 34198 43423 8609 11116 2061 57274 20119 25548 21653 20325 58245 3060 3307 7248 38751 29839 9928 15631 56208 29766 55640 24607 26174 40619 57782 23721 30911 61138 10944 48875 2604 4899 7243 44890 55027 20218 55628 35114 20185 10982 52339 34936 40915 10761 14437 7082 51197 64272 41792 16045 14053 57337 46890 9378 34365 1433 25525 30338 26650 35552 49857 55542 9158 49710 11190 4355 55322 58989 52576 36932 54327 35681 5571 58547 57348 640 14225 59760 51917 63684 47693 61514 14212 4176 2480 7565 26927 30660 3863 14224 41211 22960 49687 24634 35795 28237 11299 21782 30432 14282 62580 21268 54854 24105 43302 14554 7339 19388 21095 25757 30001 7539 39428 53913 11506 6961 25308 3927 43882 39475 34975 24112 50469 59272 43864 3917 33742 20143 35459 55243 30855 8239 27495 13820 61855 1451 8864 56322 51658 24531 38661 54613 51548 16850 23642 38894 18941 27207 47977 40050 12284 10106 21540 10489 10580 46901 4917 10875 44952 52824 2571 22644 47501 29939 12091 30696 18889 59953 19689 24534 51506 10453 63039 43330 49128 24464 51785 22238 40893 16151 20574 23802 42281 52702 62449 60090 54156 36294 52665 22292 48768 25022 37010 58360 64170 38643 57270 36974 42329 60259 25067 50897 58168 53918 29910 33649 33828 48111 49160 29410 11414 6189 62043 22660 19510 4091 50599 30159 21047 19557 10325 28019 61826 38765 62887 9775 18031 10011 156 55652 20903 58818 28861 12550 49768 25826 41705 43812 48208 48862 59072 48591 20328 53723 26046 12553 15457 33709 63800 14869 38262 947 41258 61454 53491 2085 39825 40979 39192 61468 63001 47156 6 13707 58403 30858 17961 16501 62210 26176 20807 37424 43435 29419 38168 48016 33396 8112 10307 63261 37345 29669 7798 14858 32867 12234 150 6868 33301 42366 17617 50972 45150 57975 41999 51747 54476 11511 44531 38984 54343 45973 45714 42614 15011 40123 56457 21908 44114 29601 13231 5150 62239 36745 61196 38235 45941 56671 22579 22799 47259 54710 9255 22593 55114 11031 53510 51070 47894 63557 33530 39194 58867 58650 59381 56501 61622 12241 44612 58516 37150 25473 14157 37608 12060 46400 30872 47928 34476 623 29032 20649 43466 38277 47990 47919 47578 5906 160 46728 7121 4924 15588 59323 25329 2198 16826 12304 21684 14399 2829 1601 14845 20217 15016 25774 27251 29286 13969 21595 5202 2174 17882 40806 6224 37114 2616 31480 732 15632 53085 43113 8667 35395 33608 37301 47993 51965 5488 37627 18642 61907 29890 9752 39892 34332 56183 15368 18817 40200 7509 7856 55147 61253 18362 40528 20541 37233 35117 48161 39393 58941 61210 6752 50007 9754 30985 45780 25723 19870 4315 6143 61620 33666 53514 40500 42053 24194 8088 36834 41174 63370 10851 4771 21666 1570 3288 26139 9200 37527 15612 3183 2631 41315 18765 5845 48217 39891 21423 59164 62019 38100 39571 14134 41822 15764 54492 10116 34474 1087 46486 40163 63455 1600 60264 17532 4768 25073 57213 42127 5773 34938 35757 49478 63166 61587 9120 7865 2363 50287 31595 20078 40634 48125 26506 20514 27274 4588 5895 34063 40229 19840 16794 36604 64282 21057 60456 40113 58089 58262 61107 35436 11340 10008 31700 6834 17166 59948 5858 36492 17300 26762 47073 53694 11018 25558 62022 64088 51726 41999 32768 23552 27360 48450 20618 49039 52342 20322 28020 52005 53937 47855 12465 26585 22096 28958 47873 14584 34685 59261 17878 62337 52034 44010 33466 23865 46755 27626 23580 34680 28828 3645 38484 27130 25646 5320 2495 49108 47780 13309 5013 46420 21843 20844 50053 15246 63726 42374 44275 31076 3111 27526 29093 61716 30525 51918 9377 47266 3449 40604 15842 3372 52283 57169 9805 10456 18062 52915 59460 3743 55960 20591 56154 61466 41316 22535 30491 920 25674 30057 28600 8474 18220 948 8668 20960 44283 37087 34482 52674 61503 52125 49908 23686 360 8594 18809 44759 5642 15375 54321 10983 32967 43895 13091 50553 40395 54856 3063 24588 42020 782 21963 49714 6505 26020 38134 27962 23004 11004 36296 3470 515 30058 37340 30565 55619 10983 13093 17285 63409 64197 62551 21414 46103 8611 44677 21477 57752 55831 63814 52888 43329 21956 31545 4950 59558 18722 50697 17122 21638 22472 37866 44377 42606 55480 63905 2745 63926 6644 20302 31482 9567 34804 25082 54491 63977 48803 34298 63477 59976 21099 44603 18173 29059 21877 18447 13289 1121 56512 38507 52493 28520 9130 27492 14750 20058 29907 50325 62842 9750 30459 62498 23574 5674 5120 57827 39539 16453 5419 38037 50441 59641 5368 28764 62563 7723 62951 2694 34853 50439 9636 12787 26612 59744 35370 11646 36498 3692 12247 57389 57932 5546 34577 30954 28819 58567 8986 5023 9125 27608 52654 14655 37891 39038 52311 34511 8617 14249 8665 3251 22991 19815 34127 60109 1514 59990 49298 50723 23735 23424 22258 36976 49032 9242 56949 18073 48806 28099 38494 48297 52104 58 45701 3358 59298 29026 62272 60465 38519 30585 14683 64001 15203 1607 49674 1204 18501 48108 22108 50161 61463 17224 57306 56640 38363 21516 20105 7101 60101 31392 58492 55 63158 33761 40268 37778 41427 8067 61206 9178 44544 45965 62889 57175 29727 29950 5475 45824 47961 16625 15952 1568 30197 53816 32995 30325 53680 29831 39019 8747 45226 17936 44297 29019 44893 30019 17868 61560 12266 40379 33145 62972 20635 1645 20641 26419 57357 9746 50541 33770 47775 52032 20996 12558 43436 760 51245 41859 34389 59998 51568 27329 61279 55427 30905 18743 4279 41281 46413 25997 44328 64035 61026 43972 62364 64223 38960 51587 21014 12412 5186 38666 19544 50501 49573 47639 10549 61886 19273 21120 14750 24354 4589 46120 4957 6850 31734 14737 34054 19726 61535 61569 57873 6326 14018 34469 59911 50497 15406 31551 48284 4409 62601 35959 59137 7515 46481 1821 28794 30215 62623 12799 33146 38079 13899 45793 11220 26011 42100 18185 57922 3035 20142 58844 32967 15779 38206 60753 20078 50852 46274 60793 20470 59170 36983 28154 29367 35424 62704 43809 61098 28558 54387 46943 1623 18531 7260 12463 17076 15578 11014 3347666468 1320327177 +1024 11622 36596 48646 27333 24672 64075 1156 45677 9192 17919 590 2367 62242 14563 9364 61894 14412 28887 22884 786 42052 41390 39150 39099 29395 3926 13426 39936 5877 26414 10070 15821 54595 54336 63792 3491 60348 27458 12935 47245 58087 1463 26253 51072 38708 39927 9048 45752 3583 6907 29951 53464 59038 31643 40036 59696 21225 13231 19119 21634 58674 59693 18826 36440 5762 18580 57981 23795 55865 24861 7311 198 21316 34191 43499 36518 20905 51105 2076 31198 39806 58264 56182 15668 62141 16762 51929 40896 2532 51621 14814 33817 18230 63673 58833 22170 44200 16984 25638 43300 21946 35805 56944 50773 57104 11674 14246 19856 15754 51272 12402 46515 28269 23691 50621 61401 27635 53601 9575 56099 27809 43573 37796 28223 35379 2794 39443 18455 6290 63249 18957 62939 51651 46228 25861 38357 4347 63374 9474 9372 49837 30319 10678 51289 38407 27484 10839 35443 6573 27052 29351 37381 4183 52902 2384 20312 62409 5106 60537 16019 58386 1413 7160 51112 12730 52655 38470 61053 13299 51723 17225 23104 24725 54270 11206 35131 12739 33223 29882 59759 21362 44610 16624 29335 55893 28131 29949 34255 19890 28720 39326 52457 32857 37431 26849 35598 7832 26553 38740 56185 36430 39416 9548 54228 31626 19126 33870 18467 19522 13117 57535 21566 11498 58129 15772 43841 48358 58176 43056 45257 17595 20485 5477 35351 61012 42882 23601 14789 10560 54905 3737 33185 63283 58415 54956 11516 34622 61600 60357 6699 10623 40559 27682 14812 4236 1231 25025 58749 11134 63659 23514 50895 61664 46441 3794 36946 43285 62513 43959 31174 62400 47861 15179 8196 43727 16915 9438 54738 11754 35902 15753 45717 16464 47281 11530 2860 11887 43511 47325 10688 40545 34862 12913 58091 64043 8362 52879 61326 5083 52964 27942 6030 49165 59430 35526 19627 40743 3202 40973 35427 7606 23729 31397 26712 48247 29067 31715 46950 44126 62631 29558 15832 63746 5021 59861 19368 25792 44262 64128 23389 3038 5269 25834 11670 20020 38948 7586 38249 20399 14630 2878 55082 29035 16367 5055 16117 33511 16520 53534 26557 60425 10996 47710 30272 1482 63035 25503 51371 37782 36128 63690 20479 40554 882 55524 59906 1042 28633 42614 40473 19437 49927 20552 5510 51418 29700 38908 37955 50337 8018 53051 34715 25229 10527 41207 39628 33319 43116 37813 8199 8440 47942 35907 25632 29717 7455 11294 39297 56480 19121 33777 46727 22796 29095 12115 30000 2223 44916 20791 49811 25042 26449 45451 57753 47003 20189 30453 27679 54818 23255 17781 28405 56814 51218 46599 57854 47473 31419 41928 58018 53873 61438 40566 4269 22312 24289 9308 15851 26764 18137 39404 14080 45543 16637 39858 42709 45646 6303 50867 22023 5848 34561 46200 37413 40810 61442 14334 30680 1785 2776 51318 57188 4794 27682 18119 17970 58625 48596 58897 46628 28257 48244 56800 37956 58041 49880 21329 35406 50436 42410 48470 39156 26063 16911 543 45969 24377 48421 48144 41087 57093 23009 24735 38791 55734 12992 22026 40388 35272 34941 60504 19912 34408 20912 33899 4063 59589 28768 35226 8079 40083 40662 162 13924 52086 52061 40570 23164 57816 483 11832 50646 4151 28957 35225 41054 22717 25223 49312 8430 43152 50297 27497 30720 48369 45322 11602 758 18720 7173 336 28670 29945 55526 31225 58302 27945 59589 40937 16426 7130 632 564 53609 59894 13268 19351 33708 56021 24316 57911 54330 8403 39782 30150 25410 6298 24560 14771 1925 42551 46470 42090 40459 52492 46308 21796 30729 12513 39830 5628 64082 63710 46353 64021 23421 59373 30903 34424 62185 53904 55008 50991 21739 61457 46723 39233 26272 30976 5450 15031 61877 38708 35800 56621 37837 18562 35393 25765 59587 52988 29454 58723 31467 36903 18703 20124 48500 23267 57658 20310 9135 10601 10550 6734 62472 10454 2725 54047 61234 19351 52922 63674 7063 8662 55955 9357 20660 45546 53722 9885 52015 35097 36710 5682 35234 47676 32791 19969 21206 18320 63701 40337 31455 35385 16209 33453 25527 48026 4154 15549 2181 54673 58179 63490 63490 41505 53625 15897 46666 17292 20862 34793 5577 2170 63454 55771 9738 63382 43180 15479 13273 42568 64080 63008 35780 12824 58947 11756 61021 7019 26560 1711 4666 25468 12303 54329 22712 3503 47150 51835 54943 53157 60775 42838 63031 47141 21970 5100 43084 27544 6378 57783 3953 16548 3269 56629 52437 5845 29329 39140 13484 28026 14295 22608 41761 49111 60365 7454 51526 58371 55272 30056 955 36150 673 48248 21393 26818 37321 55190 40121 13638 13425 30085 55431 57438 33363 63919 38455 34438 49289 8982 1727 40069 28206 37047 6792 45674 5885 20714 51474 28467 8900 5793 21130 5041 36386 54345 37848 16528 13774 19447 54010 43623 477 34876 57020 6144 38667 53697 25653 11664 59743 10217 59462 22030 16151 9100 9779 15078 3841 49719 19979 34556 58288 47910 30017 3545 37290 10792 40918 58126 28394 53288 30982 7284 4337 55405 10223 48436 19165 60492 56938 62848 63771 25837 18516 13577 19665 56246 63339 56359 62160 14490 17550 63202 43681 16186 41595 10811 55927 37922 34757 12223 23210 7855 8664 57793 57616 42626 11343 46657 48510 43029 35876 51136 23578 8785 20490 60692 46027 58620 7936 57604 39161 17854 21328 16182 41063 9325 122 56466 8738 23750 30757 41566 53610 5332 33672 10356 60828 35578 6605 58764 45149 43013 21819 63483 23386 10619 46750 52136 25940 40138 5536 7580 16691 16125 58566 57666 45861 63258 46509 40991 4799 53935 52335 52683 16543 41401 20245 4476 14586 23314 581 4568 39097 60409 49389 49792 16643 44112 27985 31396 55926 63126 44547 44698 42494 56616 7075 3807 42681 12736 46797 38811 29671 11683 9237 58624 33598 26251 6367 23440 41956 56269 35427 39333 33171 30161 10858 54827 10233 27666 2501 2822 51861 62196 16592 64001 62658 26718 13436 19090 53945 45820 4070 23926 51598 23628 20933 25883 15237 6652 55083 58079 48813 1280 23506 10176 355 29591 30795 38204 18613 59926 1863 44871 35216 20678 38005 15308 11575 15953 63717 53913 52036 4504 40683 38117 2977 1372 9025 2154 41918 12364 10616 28869 34705 19526 28609 32820 10740 51290 59352 18034 37534 62324 8343 39558 16339 23195 45689 6925 59286 26985 23416 28013 36325 38631 5795 49277 17460 11890 7418 48147 31655 40141 17648 1440 18230 39998 50398 30802 35915 10986 52321 25077 3920 34490 36667 18621 15317 39135 50573 59725 24783 1381 44346 32891 33469 6257 35730 14981 7140 974 18270 47775 1043 51808 8375 16926 6812 207 27187 10112 42279 3126 29846 43328 13610 30205 49353 19928 54465 46934 35510 10017 34550 7902 6337 13662 64091 25619 61306 53774 30035 22397 52595 11098 49109 57139 56561 58423 15520 54978 36677 51995 38799 57832 42530 3206 61479 19564 1803 25015 50824 57371 27372 63120 61389 28984 43817 48585 8638 51737 30476 52491 38244 8020 54413 5597 19673 60169 4490 16105 60760 60620 49166 60103 57343 2294 53984 9025 25664 22876 12258 63189 4023 62366 17463 52276 627 63869 29056 21731 2656 5080 53565 43949 2445 46436 27469 62722 29593 39975 31138 11246 51508 21804 3870 57086 53534 63809 61757 25179 14355 50265 48390 20438 15553 54618 9879 19333 45946 43457 1833 9747 56135 54991 62586 36079 60327 5802 1863 30290 63621 23541 22556 16796 41936 44170 50951 24116 30203 62530 7565 21535 20917 46259 42322 1798 63296 24063 22855 4293 24593 51306 4070 5744 48053 13281 56080 5420 59934 50256 42579 28640 30772 3618 13198 63884 54600 7992 24189 34764 58078 34399 56462 48602 48774 16173 27562 55602 39436 9563 23492 8976 61051 58755 43577 7238 10800 27988 11061 47412 3775 63862 22425 56929 28169 29438 140 20274 8616 12512 57171 57984 16896 932 15156 39637 60359 45222 8028 46531 42739 54176 20398 61745 47006 27279 24158 32962 17730 33830 29194 30755 12829 18244 46517 25965 14569 25129 39245 4493 16843 62293 38663 58318 56174 25224 2204 57602 64402 42756 33542 12130 60256 38807 29977 39260 36610 581 50841 5680 42014 28033 62727 49203 45985 25577 28439 30867 16993 53008 33716 45906 33047 49731 25359 49815 7444 53746 50220 50465 6319 36074 47671 9504 2170 54149 41559 8467 9089 2366 51674 29001 62275 15786 34924 6970 2997 59872 7182 60538 55576 31229 16979 23886 54523 37027 63615 36696 16162 22539 8399 7903 51967 37123 26732 12115 24729 40710 1855 23416 19930 13496 3316 56119 13174 61238 35809 24211 34057 38654 51176 60796 5413 3522 48814 23463 34307 14360 34219 41380 36146 58621 11073 59751 30341 11164 49433 50142 18980 48990 27249 57996 6551 22639 18980 37886 19945 3181 18043 34177 56672 29249 6938 51969 12303 28426 30261 36765 52374 57359 8015 50918 42386 6811 17993 43997 2135 12447 53829 55940 12375 4538 281 13945 13749 611 51411 58190 18665 42517 12780 43316 34657 33574 1141 41591 747 56560 36399 30826 31658 3540 25357 16441 58887 18657 38896 47674 2587 58324 30531 36392 36307 33227 58405 10921 59086 2905 41822 59896 43592 11936 24216 29321 45537 55909 54967 17960 43772 15257 54808 13997 15308 18888 5992 55235 54192 7385 25884 53119 37405 27362 37031 294 46649 8903 3810 54870 42307 53403 7066 3387 35846 17974 62719 37395 45575 44191 272 7678 64065 40770 27865 45381 19360 15655 25142 37971 1580 59787 38286 24686 35557 17151 34552 41575 61078 22298 1939 37163 24374 24984 61122 3895 27468 14690 10641 2140 54241 15343 44129 44829 30036 13775 42520 63460 52023 60385 64076 40150 55436 46060 52999 23865 3416 29305 25560 50765 37681 45946 3568 47515 29864 35154 22060 61231 50518 40088 60341 59259 42031 49104 49119 33435 57064 52238 47344 44843 53128 15075 31609 23040 60119 62660 13542 7904 10933 57249 2947 50960 0 36996 49639 5776 28480 62085 828 60976 15878 46369 25983 11236 16594 8534 44575 33099 40284 3694 54187 47308 15454 26328 31539 28478 35807 12374 6828 59392 11909 13017 28350 15038 29874 59114 24943 36362 26838 34599 63408 61694 1064 21268 29827 23883 55411 48364 31041 3781 20318 44203 18346 46360 6105 53183 33575 53201 56069 6068 44560 23014 63661 24645 47006 30540 35142 26301 30053 21498 11164 44211 22729 433 28612 57347 2097 8991 37861 30551 46335 39089 18991 12829 19292 54440 23959 50417 42159 63969 594 56833 46629 41164 29573 51765 46744 37194 1838 27396 1474 55460 7586 38749 58855 22873 27631 52339 5769 54975 16203 54390 51922 58522 62283 16065 45962 26125 47249 48232 31134 44180 56756 7347 25882 27330 16441 38517 49592 3705 54729 50669 39827 7708 63438 21830 9375 7890 27421 14203 59964 7266 61702 35866 11182 5253 47141 60858 36831 54815 45215 31630 3194 18046 9900 16142 41105 51669 5554 36482 13984 13977 59514 37955 5074 35739 44964 39892 17430 3051 41279 56738 37119 44390 46126 59737 62813 50035 60907 20945 30946 40971 38769 18076 38534 21638 47256 31562 35760 58632 46195 33001 10510 60983 7120 16533 7266 8613 31285 25645 56564 9760 54848 57751 30037 34738 25490 30724 62789 25225 47803 8237 33708 13384 57601 24028 27113 1511 3262 45192 19158 28653 46467 41645 61752 40490 52337 50413 60208 11560 53106 49077 27367 48290 34548 62678 58722 37337 46333 10545 7727 37388 26730 16253 13691 42257 2410 63536 50492 48927 9556 61912 41216 34236 38421 39192 62863 684 27125 63396 51090 63068 16903 9046 5489 42290 46303 25619 45822 53304 53582 4713 59879 47358 38310 12201 25662 52532 22277 55270 63114 37308 51404 6453 33101 19147 12262 58195 3625 46007 15224 40529 18744 35277 36959 11374 20317 36662 60906 309 41918 19451 7121 47635 6999 39994 14408 18715 7877 15574 10822 2753 53673 19019 61342 30234 52144 33076 16956 24311 41529 61656 13020 12566 45852 40983 25030 63404 905 50843 60547 11118 40413 17656 13220 36220 50115 42915 26223 40437 5360 47306 17718 26593 61000 33706 36835 64242 46534 45139 25679 5376 15202 6149 25572 3931 6011 61245 8051 53895 60582 13812 9951 50875 24880 58428 46486 18180 58692 29089 64282 55253 58487 18891 46964 13206 53017 63091 19859 31174 56341 59630 24986 6078 39640 3926 14906 46465 9356 31375 34353 32944 21908 43471 61765 29904 49929 25772 17448 47795 51741 14250 28741 52547 41512 8250 44817 11076 43860 40475 47549 40999 47861 36100 1587 61111 15327 17931 11685 40740 62318 22487 20683 14553 9361 26327 2227 16945 24180 61915 56648 31156 41246 43095 18401 35341 31044 45579 56155 6840 56450 22979 20948 26538 55921 48115 51115 37546 24907 60973 42816 17017 45828 26021 50832 45635 50560 41279 11756 36396 59179 15983 56350 13070 25646 46199 172 56257 2911 62167 17622 33245 45491 0 3465929717 +1024 43112 54319 17260 55970 53168 56153 19346 43029 57461 63171 61844 36780 19583 3643 9532 63317 61282 53618 17336 62882 28275 48883 54318 58733 1929 36767 8156 48145 46270 12634 931 9494 41215 7587 14104 56923 43681 23867 47487 29225 59110 13446 47265 713 50357 4854 13927 41029 7514 55309 6412 1444 24060 61434 56836 28074 6227 11826 46037 34895 35491 14070 41061 47817 44874 33564 33716 27708 64017 25331 43625 56547 6223 51570 16777 56128 59592 42664 59028 40131 25995 45712 2539 7821 482 16107 60517 36911 13366 53831 38325 30350 8281 8586 29975 19989 18935 25506 55954 37361 47028 56654 10103 49003 36795 30890 28379 29502 16981 38201 59515 63322 26974 23952 60340 38731 1094 8580 62827 49482 27751 60482 27994 24134 24203 19906 23572 45754 27582 13291 50418 49365 36229 35748 61178 25542 17956 45995 30068 61141 51322 11861 56569 45308 20637 21448 5814 61194 62276 43031 8005 25983 42839 40280 25799 8750 2259 39245 8055 21586 33720 62109 6590 4498 41858 16081 24290 11992 60140 62622 29567 22345 36994 58734 11061 35577 17972 43561 29742 36819 10505 56138 47969 17964 27293 38606 25235 1607 33432 4921 8659 7754 58712 39127 16017 51814 13519 27420 24880 59996 49517 24252 49033 47516 58846 50891 33631 60184 58472 58595 46713 46316 50304 54470 54823 35449 3319 61309 62703 14442 20697 58434 55783 54349 17444 25043 6237 50078 19894 24500 17002 38511 57306 20557 47612 15789 23756 30333 40797 44843 51617 40754 55722 38510 9865 27112 1611 7144 18297 34863 50687 38636 35588 23339 10544 33570 35437 30664 26096 22684 13607 80 60937 42063 13322 16206 33850 21192 38560 6714 1752 8860 34709 56739 35413 14549 59972 11412 8352 45281 29542 1473 9308 8767 16794 12684 18330 11202 56805 20428 58601 60188 59704 4246 41334 2203 33871 24194 16195 3583 36658 27343 3517 29763 53193 457 44506 58667 10167 39019 20335 55754 52250 22946 9663 53801 5423 30455 21403 33310 45296 51076 46910 4466 41062 11162 42918 8182 10594 33773 59395 52491 56876 46572 17722 40399 18682 37431 10545 52520 13117 15569 60054 40053 42822 2968 50370 29280 56996 58588 34956 48633 56177 64307 18354 17275 44619 19351 49211 22506 55791 18180 64285 17094 32907 36676 55595 53731 36880 51373 16832 3616 228 40303 19262 57211 48593 19247 36564 886 46485 56681 58149 63785 18873 47088 23463 17144 19930 60883 40794 36192 52951 4992 36760 47125 20265 10170 34746 52707 12236 15081 43624 35979 59772 50366 62966 61453 45167 9176 39340 55816 61470 3494 23742 41227 35495 40468 23368 39320 35907 55564 61650 22748 60016 52835 4688 7918 57798 10078 26521 29014 56713 61048 23133 47036 4877 7624 30751 18037 29729 20438 35001 21644 33217 53074 13621 54411 148 28618 50644 33167 45951 62420 51711 9232 5976 29652 52824 21917 37961 10974 50450 36857 30829 22743 12133 46760 41416 54799 48614 47483 30599 4727 16097 39087 46550 12017 58609 6539 14537 34864 39954 7354 10950 57817 10983 50352 47254 730 29517 55453 54549 29144 33210 6642 25300 12592 55338 45915 55916 49368 48853 53386 8371 30384 20867 34612 44479 12112 21373 40148 42157 35162 4188 49360 52760 26398 21538 58477 20842 12122 18813 32779 25583 47833 39695 53000 13874 54563 38762 44264 63311 49482 18225 54031 41203 50506 19669 5585 13130 39825 6528 39803 34926 19925 35369 30674 31389 27326 64204 33422 39563 59083 52964 13965 23984 38712 34838 23833 63313 56895 51715 58029 4141 31644 21263 38821 58214 4580 12970 24172 51457 63081 15000 25428 12509 40940 5691 11125 54385 26313 27924 43335 3229 19319 21314 31062 26920 7609 61487 9004 14058 20599 37337 63290 7134 27702 40819 49692 37705 52191 43583 657 10188 62808 15268 2884 1742 57353 40536 14014 63805 30296 11617 50675 10560 63837 26546 58144 38345 61284 46283 36671 58112 9334 55637 64408 37272 56141 17684 48837 63159 12513 27593 42663 53985 53896 3532 38407 28706 5011 54709 7497 5799 8246 61580 54286 1152 40372 39699 24069 17877 40433 19727 24073 61611 13774 57327 47896 41052 23912 13624 1974 48434 54938 40741 14019 41271 8951 54684 22515 40254 21289 9818 8178 34050 25985 48394 44100 63841 50739 33577 25055 46910 51939 419 4444 11093 10671 26240 41484 53110 49005 2956 35518 54978 43643 22593 50653 4699 27703 23931 62278 7930 25925 45473 59030 24778 18475 3392 57286 64112 52460 62384 2347 45736 63780 33133 27518 36434 61459 2665 41254 59338 52258 59134 18562 24788 21805 35295 61345 50282 2252 26676 22115 21188 6951 34495 60831 46797 26842 61729 40369 38647 51939 31362 10774 22502 26820 24190 29473 63096 20541 9711 15392 28024 57920 33095 46005 5282 38228 42603 17172 39773 55857 8900 54703 46250 47631 19559 43364 17153 50275 54693 54861 191 62554 49387 10087 16910 5280 50169 32861 28460 26839 64367 4626 6921 11098 46318 30981 7431 59023 14226 39666 54535 39555 26228 35137 58051 63748 56169 52251 55214 41802 5528 15669 54075 29844 5200 29549 48480 29856 60385 12762 38804 37379 6363 27496 3888 17452 21325 58555 25695 21477 58180 14891 20497 26808 697 54962 4759 5369 16841 41169 1534 52975 64295 37836 61267 44031 47507 20324 44378 46863 29639 17089 29044 5090 39727 45173 26324 60055 61902 25756 23540 6334 1742 57916 47348 11954 38150 26036 21537 1557 1975 32880 43143 7625 53725 28370 8620 23331 34749 21015 2128 1083 43779 18793 34409 62045 13866 48345 17346 35943 32927 50451 10265 44373 3601 58148 27195 12397 50718 56222 23708 53373 48874 22581 46429 49451 11866 23353 23204 44233 2159 54858 47792 44198 6423 49063 51101 25164 21478 17596 34476 6106 49705 17836 64328 30247 55387 63022 37504 4629 8323 40481 47375 47610 29482 17854 56016 12927 13987 52866 54090 62201 39116 13008 30500 30544 60083 55969 40535 27086 41611 11772 50397 54202 55972 33667 29592 14648 39815 12431 19151 39684 22812 41956 20111 33634 56483 22864 33027 25127 4047 5642 35764 20046 4053 4857 12882 34851 1643 37428 7264 64355 55144 1817 24421 10786 25217 11666 23356 56990 48136 44871 39184 51060 3800 29510 24759 52122 28752 33516 55537 17640 21603 43972 52103 62939 26863 33789 25503 59406 52165 30839 7911 12456 53225 49886 43227 22762 526 12708 53121 246 4282 21039 6199 9752 10135 46751 28245 29795 18448 56036 49266 38797 39359 61645 57570 39963 35956 18207 8761 45282 30169 27043 25408 14943 7868 38564 26514 780 35073 29472 24912 39928 4303 29972 47901 42618 43366 34826 64391 5245 1010 7761 42152 5721 60285 24429 41681 13319 13310 37681 61469 2556 19759 53052 21738 29021 28492 56784 41624 41859 50431 40062 57942 37961 44584 121 46277 6707 44525 46831 10897 62714 59029 29488 63447 8468 40201 43888 24616 42735 52747 37204 14979 33394 53518 63530 35582 4479 33167 28815 58820 3028 52096 51672 10025 39671 15983 64297 53627 35867 10373 44067 15569 64208 19756 10523 10318 1902 29828 33954 24114 51787 20929 17410 4529 29251 63893 3389 56194 51735 27852 15870 30544 3026 61009 59018 18275 22282 64179 27642 25913 63093 16636 22022 2587 50060 14588 14476 45941 50854 20221 26939 20983 48024 19659 23419 20726 30140 50055 61148 25440 55342 60637 41958 61291 18542 35328 39862 5697 26060 52224 41873 42759 18635 62145 15101 6412 63843 46802 33225 37998 36852 4484 20634 51417 2236 42486 13152 52063 28216 63433 38071 19502 57246 12443 44216 39009 45222 11226 62123 27293 54847 14607 44185 31101 40969 12991 22638 30720 26605 22467 37208 21780 11087 36169 5546 21944 50298 54638 17767 6142 13051 29933 45441 54798 48508 1875 63160 40911 11054 14914 44351 58307 20311 46916 44826 23310 1477 63979 25695 47995 50067 18976 3706 31564 42711 6675 46793 54620 24179 1098 9657 7653 6189 37605 29074 7889 49834 7535 11260 53394 53541 19703 27144 55251 29927 9449 17369 19469 38487 7688 28622 14062 50196 12106 51390 39688 54582 49033 57065 32789 39022 35996 55473 34830 14703 44859 11602 33344 13118 37614 7193 11161 53441 61116 4023 24869 33995 14745 14065 31380 4782 31442 12530 34412 1737 2970 7584 37784 22749 22079 55687 36361 14191 11572 49642 6760 58558 53339 30638 36372 59563 4822 52619 28880 16971 12326 31025 8682 61982 20745 23954 46014 11202 59637 23816 35471 7837 820 59554 49404 62490 46980 52705 20813 15841 5497 58415 4903 35373 7555 63748 24875 51723 30415 1142 24346 11294 1750 63808 22623 59419 15752 6712 51915 17441 28927 13220 7805 62155 30534 62942 6929 35794 18375 3747 53344 45770 59068 62872 7587 57862 6482 45747 11861 3257 18369 37508 36429 37369 44678 48054 60784 59922 53271 44527 57869 12913 25148 16613 13170 11382 43394 20539 44421 53830 52470 59166 4061 51451 6496 44325 18278 37356 13944 51779 57175 184 47170 37628 61823 40779 64030 53228 41120 19317 27017 56028 61391 48565 46601 61375 2328 15749 49094 50838 46326 689 6075 50457 47648 36829 48366 44175 47434 50136 27251 41081 14625 58023 17600 53226 49191 7772 54085 47136 38525 47747 45748 11853 6086 13240 23268 15379 43360 35246 761 61321 6711 42010 62567 1779 40983 39422 38095 16755 48540 45730 3879 37282 28126 36987 20796 11978 1468 36987 24470 56631 57773 488 1122 1369 56357 22388 1283 20567 6926 24467 8445 10341 18955 52830 48538 35439 44364 41036 4463 25542 3367 38119 1911 55883 21118 3538 23351 15745 41218 25153 34483 10992 27460 54696 22575 50497 3642 38310 39574 35210 13745 9269 11609 34427 50939 53723 16385 50711 54228 41762 62090 19148 11683 16839 30806 38845 30399 38888 17960 41099 26231 43334 13443 50062 37804 38885 16953 28466 4231 46823 9308 52216 14253 30240 59748 23915 8768 16924 4879 41198 7492 43555 62295 63097 61573 4570 17901 6733 29871 48299 33421 17350 44652 33726 41943 7559 55041 50513 40340 27613 41011 28579 64389 24719 18183 18800 26509 43278 44030 46600 1275 29706 22477 40446 33611 16265 17187 2391 11148 44854 2130 47845 64063 15829 10163 52416 64216 52192 60044 36664 59176 34786 54453 15528 4908 1080 34545 33634 7454 23769 55262 39095 10829 13964 17193 45273 1348 17680 12114 23727 45223 26027 63209 42547 61727 62704 13386 54842 35155 49891 21305 116 58408 28082 4205 55577 12903 43665 8682 26537 13647 49757 58908 420 45991 18771 54685 49526 56597 62166 52751 55305 21756 57759 52151 37358 58333 25369 47634 57656 48555 30221 55853 30252 63037 46577 19471 13565 19277 33781 18633 19309 28673 3477 45225 53553 14045 12674 36545 16548 39023 11958 39376 56305 50207 14521 2273 42581 64423 1539 55172 33981 912 15851 29241 30739 41668 29855 19109 14072 38750 50379 33625 42918 22670 50217 5224 12763 32843 36822 1207 55341 16592 44334 5298 30239 44605 45460 12824 52439 64388 47180 42819 14348 48046 16017 16993 48507 46207 42709 2239 3740 59707 64370 59297 17246 4464 4402 14824 61705 63421 13518 61314 57439 24194 202 40250 20591 48452 18948 17799 12674 39339 785 24864 46722 38041 33343 31242 27016 28041 9922 62837 8079 23979 3288 29111 16911 4118 29488 18312 88 34916 58149 12679 35700 46878 8647 15908 25200 17358 2772 52409 30907 43484 607 16894 1210 60134 7152 56349 26490 8143 16963 61639 9799 30325 10315 30917 15719 41794 21177 56021 14441 6121 9741 27223 17551 20309 10949 24611 18360 28207 51524 55827 61974 64428 49039 47491 54947 11 30175 38641 55363 50076 63684 40020 11962 877 34528 47378 56502 62895 58816 38626 10209 58607 5274 29202 16608 21739 41234 31285 51909 3622 38062 30376 64242 10615 60336 33324 30064 41174 56796 1946 11116 5402 46655 38449 21893 35372 41670 439 6716 11649 27538 52159 8936 25022 35957 54893 60809 7759 44446 4779 10714 53898 6183 563 56867 61655 49333 52384 3732 3661 49252 17925 55481 60598 11670 28900 7977 55594 35075 7313 59299 63758 48069 17831 44385 36121 8466 12142 62645 33563 13982 49528 38213 8299 46920 22414 18422 59255 20926 7713 7467 26087 31690 54977 37937 833 35525 49420 53320 3566 21025 19753 46566 53054 15924 47585 64471 44605 33884 29306 26160 62959 15647 14705 7947 59193 2069 8309 53522 60229 20407 16966 2523 46714 18490 9329 26562 9117 30711 1591 58771 40944 22950 48377 38001 39615 26601 7077 22293 25282 57793 9438 55123 48926 13580 58347 37672 8832 42450 28280 40020 46966 25752 44607 4615 24916 9005 20933 57642 60446 46723 58720 28015 7573 64117 10152 57576 17425 58600 1956 1959 48269 54411 6012 28972 36248 24291 15475 21737 37551 39150 56711 29819 15798 1226 56104 16273 137 19020 5809 61958 52367 62078 1042 25580 57275 34078 3189456006 1326349042 +1024 11243 35696 22079 62194 25720 46556 34458 46040 2618 34586 9646 28787 20210 21407 10548 45076 61141 7709 60162 18109 60634 17966 28360 46161 10921 6550 53339 73 9079 21685 59261 46155 15701 59803 61702 39205 33811 47374 19957 41040 1600 25138 41442 3886 23054 14290 31246 20684 35030 18914 49180 34972 9503 3339 1472 53098 48102 51320 60691 10825 56510 3225 20732 56052 28119 44712 33301 61721 21501 23173 18473 63039 48669 29723 52988 42427 50655 23060 22164 43276 45179 57375 53471 59676 43103 23634 48497 24369 49234 53396 25373 46085 5419 49821 7215 20527 37679 17234 410 26056 57727 48588 40218 25285 21038 10619 64466 48709 8523 63070 38068 9231 10947 30588 41449 52120 47318 46051 29841 42763 15728 61555 17221 12127 53856 7471 27378 6102 30536 47073 59317 54524 18704 41274 9404 16104 17068 19661 27531 25913 5566 35339 63339 9833 45803 18953 9321 37738 13909 34938 19525 35187 53708 30545 27317 748 43201 43332 29767 12651 4997 48988 19596 35386 8535 60285 55057 25593 40414 46480 26117 54060 10468 51029 16545 51045 63376 35661 59905 61992 59968 55344 36533 13759 12149 44156 23478 63743 25149 52509 58212 27274 28252 12920 39856 47209 46554 22906 54798 22547 40401 13108 16760 38107 12840 29008 52525 21228 31123 49342 55657 21574 3639 35203 8447 35092 30903 12609 14001 53571 24688 44818 34242 8847 13137 15228 51380 25154 34956 52723 61224 13388 62695 38219 37873 18665 30111 33463 23979 57238 6705 34136 35569 15556 3247 24557 58335 10115 19516 19804 33880 46939 61731 30895 23991 11390 4847 37143 57343 55022 48918 18163 55729 6621 61143 5835 49027 523 1918 849 23976 18751 40347 22813 45027 16161 25727 56170 37613 42287 13322 19601 63840 42835 3391 10913 41306 42681 20599 19709 9635 41382 10131 6666 60352 33621 49913 17914 27393 17533 18145 22562 4328 13957 10712 43832 21647 43400 63634 19274 49410 35032 31741 18232 4472 11268 58444 52346 24425 48665 23068 19904 16835 57428 21854 41588 61909 58796 39981 34109 36179 3813 8775 7049 48527 19912 51869 48945 49115 62250 52438 56417 55778 63234 21068 34627 35261 46029 2440 59698 36412 51708 17943 18358 21071 61938 51781 62311 18591 28509 53371 58341 28099 43587 4328 54053 21288 41453 3335 49145 42197 15200 51503 56935 41192 44367 62109 2112 28317 7822 6010 62231 37466 34424 16976 18150 62566 36514 25513 40367 17089 1799 36496 36791 25912 52314 56851 8101 45139 61645 41258 35207 35074 48968 39325 20315 36359 6784 16149 49163 43828 21779 38698 44690 34185 27617 63073 59359 56952 23281 1056 48559 59321 23965 40749 42914 3590 62112 29988 51683 14031 19902 25698 38943 42394 48304 6491 18754 4556 42497 51657 22303 30909 15021 36340 14244 61140 40981 63697 21489 17884 29046 40478 19921 53587 49329 51576 22782 3983 19221 53859 22804 36379 11763 21257 48717 37711 46416 25527 1579 3413 36669 5150 43693 45641 33148 2163 25750 57695 7513 30990 41253 37705 30586 63793 5677 13375 44461 32775 35139 21880 51844 29101 44455 24855 34100 12788 1574 46522 24900 38589 10163 3850 40526 45192 57333 36849 25792 29953 37255 17223 46854 24667 19267 30051 9147 54299 26970 11924 46921 51112 11929 35132 55841 52124 6540 50391 41898 8178 39764 18956 8950 16720 40459 48452 60419 26004 47559 61591 63804 39786 62372 18138 13571 56478 24638 37199 1623 59090 43603 45174 56876 46730 59351 64159 52325 22605 9817 9449 51938 5358 27216 23724 2620 20504 2168 35451 60179 12890 55080 45122 57537 28156 33742 33475 60220 10666 18360 60347 19396 43155 59829 27960 12856 52622 19634 34900 34212 8553 39194 60895 25619 23159 12422 35013 63667 23140 29374 17893 46139 41487 19829 60827 18562 27458 59337 39009 45679 11910 39831 45607 51529 21403 2869 16580 11442 48947 42195 54636 20727 50087 5155 1805 41151 17100 44725 1592 38035 44899 7947 28232 50911 39375 40717 45670 11184 53815 1063 54209 28051 4601 56732 49217 41527 44204 48352 47804 35319 50406 9538 4760 49604 33203 27192 21063 46792 47757 37958 17370 4249 12926 61687 49897 58704 35147 44130 45253 59793 16004 61721 53508 19388 46747 35241 8616 48644 9956 35849 50914 36982 39549 4067 10676 22794 27212 63546 21439 56457 26327 38372 1194 13112 22338 50938 8581 4402 56717 30885 35929 64006 41703 24426 40304 16795 24300 13172 28159 36848 2903 8801 45426 59515 60778 19583 51508 45498 27138 55965 7197 29880 23345 7798 27008 5311 185 55333 58834 48016 45115 49111 43359 17251 1983 10787 8484 51442 47788 52751 62415 42630 33580 63210 5279 15351 5776 40447 2553 57365 37596 37483 60606 23690 53299 43646 22169 64287 60913 35190 39596 39787 46695 45442 41241 48425 30726 48828 9880 28750 60059 23848 45109 50893 130 33445 61503 22398 3974 59603 22787 43390 17912 56356 37903 30541 36885 18649 27241 24015 53435 54187 1575 61957 27409 31649 44156 8862 50991 48649 42967 33343 34661 540 27873 28837 60999 50922 37170 9854 29157 1401 33639 6510 45313 40742 57852 56876 54416 41613 59668 25102 17479 56216 49106 51886 43414 58362 16804 10093 12956 15694 39700 30248 58197 48037 56304 53802 4010 57554 24256 2211 4687 60581 974 22151 25232 12531 28919 20643 40519 55148 15917 34893 56952 38456 56407 1275 50766 24705 698 16327 64456 4171 26395 62970 45909 15030 16528 50509 62370 105 59854 8908 364 51918 29675 48638 47107 57105 34789 48125 46442 33446 31243 40615 15879 57288 5897 46823 38284 62043 36406 30512 48404 22339 4901 58679 39355 45778 29192 8605 4637 23468 27891 27984 20744 4527 62901 36838 23681 26709 55228 58719 21612 31195 53580 18658 53002 27011 43451 21755 56788 55371 36579 15221 59126 7929 31408 49397 43241 60959 33605 33238 64245 12425 35842 53928 54122 58720 35558 19726 12627 59879 35977 51269 54163 62231 54301 8358 48201 16205 39648 61799 32888 53890 29067 18028 50590 6154 58007 34210 11207 5049 59184 51125 25271 28420 58533 47418 18802 24238 30469 30098 40260 4129 54939 43994 36564 18842 30222 50849 32868 51487 51395 40731 41572 4322 41353 10452 24127 27373 15219 61169 58004 13317 51943 38674 20387 24098 48345 16958 56515 19925 54469 42345 62904 8100 37437 45682 20142 60078 812 33932 28635 12038 32795 12401 56286 45647 55276 24558 58461 58378 8641 45233 60086 20371 11952 18824 50435 4175 31332 64037 8589 30883 56274 54854 15747 25453 19668 39170 21469 5773 57624 15562 61708 29996 7805 23525 21374 57840 13963 10234 46862 51899 60008 35432 21456 52822 37789 51356 39533 36274 16452 19818 53183 49117 53583 26582 58880 46960 14913 38919 22437 7685 5115 60348 4916 15574 9741 9954 46470 20253 702 38948 44249 30600 24275 36733 5578 24903 4239 43423 7809 8679 29531 43008 33391 9144 18526 30706 28376 53437 58923 663 55285 41275 60417 16713 11910 2262 19858 38527 40654 45786 30048 53730 561 16652 27619 26430 49683 30081 9867 22768 33598 2112 16309 24643 48625 39842 8948 47511 10221 46653 46877 46494 29867 28846 62503 50406 13945 13811 57931 41307 53267 20408 20249 12414 46851 38674 45359 13347 57116 8935 5506 19913 50303 47022 20905 25152 5588 55507 41851 50260 45792 50630 14031 28021 23945 21633 58542 45895 40683 62531 55148 38123 22347 14732 58188 2119 1612 26565 46224 29579 2660 21228 29295 45755 7212 7861 22133 9970 19488 4675 40819 53365 20054 18616 41224 46763 5473 43360 48568 9191 17152 30374 9535 8158 40335 53171 55312 40322 47231 60502 49755 25806 17859 62879 19179 6698 16756 14853 9638 61606 53087 36487 30581 36380 45287 38406 37463 22711 11538 25222 36533 9956 27829 35482 48658 5905 36374 47293 61436 60340 354 39247 20091 1464 31248 56165 52115 63580 15906 9443 60567 59330 60586 21554 23997 27866 25043 38214 38079 17942 29706 63940 25238 10642 64062 26343 9298 1260 29758 17109 21395 46024 21078 22108 1467 5228 28100 14061 40191 29860 2301 35454 47163 34433 18454 49417 10662 28574 11956 11629 13849 14200 33376 33651 51332 18257 28235 42402 48059 57185 28610 14209 14866 16453 54975 61579 40456 57507 13066 6922 14027 24856 43551 3491 21258 60862 34571 12997 50483 12779 37282 60328 27130 43946 37719 18221 50436 61781 54223 23599 53528 61113 18532 11657 36689 57197 5081 30229 61460 27812 7513 28277 63773 43627 28392 6905 60569 6421 19684 11742 10368 19228 12943 512 61356 27912 10387 39205 14217 37403 25109 15565 2266 27952 44377 19722 2179 8507 34714 27436 40698 59024 14013 55820 13257 43874 41513 16627 24234 26860 62201 53677 46165 55383 11587 25590 29489 45698 3479 39200 29500 33074 59811 28443 20936 40183 799 49517 41178 43388 6030 60271 30368 52445 12324 11731 47123 54840 33348 13287 46349 59500 58881 21342 26313 42345 39341 24187 27696 26430 4544 17280 16087 24398 63288 40990 29677 52583 64135 52728 41798 195 7149 25482 39426 27276 53029 33450 3806 29354 62558 7879 1397 16666 11476 23048 53591 19186 48628 4329 39146 61503 5476 60094 34263 41985 40695 47264 792 46674 54527 8034 8152 29274 15182 49782 14793 20901 53847 4683 31596 64169 37622 51337 3543 28157 2459 10659 56686 43905 25388 16656 27837 40159 47486 24273 42374 58555 56627 33023 10891 14361 35224 2369 35301 29949 64211 40538 19143 42945 54315 23257 19819 34981 22299 37517 4519 8113 30066 55543 47430 6708 20708 20046 19424 54529 1929 13315 8310 44561 58402 3315 29677 36883 13850 1427 5245 54429 26086 44503 3879 39811 47468 54087 53873 13243 3481 32822 13277 52316 23579 55075 36748 46022 28224 60129 1867 52446 19677 64296 41602 6890 63967 52894 26558 4406 3323 62910 56586 6411 1764 23159 60146 46016 35697 34289 28519 59005 38604 10525 55752 3768 30205 34360 41372 18919 23531 63939 41551 30290 5755 37909 43626 48287 38647 24492 32935 40459 34682 3438 24917 28189 52104 47006 2494 61861 58913 43444 55319 20150 59682 29382 8046 46243 23133 5242 3092 16131 51524 57561 50504 51183 9538 52431 14411 54699 24539 54169 25874 22626 11771 57786 15875 5293 18591 11733 53837 12348 45283 63466 60938 25166 47348 41376 62 23908 26092 24369 55256 8032 51457 18885 42938 26782 61335 2755 48377 49632 23256 27377 11160 4581 49999 20424 1935 5134 2427 10323 34917 7022 23521 6865 3676 45925 45200 39130 21524 11723 7371 56525 1506 29402 8425 3032 48591 16445 35941 61842 14276 58303 28591 10 42100 60246 8461 23267 64347 30228 37881 27542 13341 5761 3644 29883 57777 37351 59532 23246 2587 34019 36865 28138 52573 7002 25756 17962 770 6378 16677 22241 53117 47443 35159 12903 2565 29517 61350 34689 19298 53534 39205 8896 26059 51189 43150 58300 37710 7160 24817 14221 12981 58068 57040 23304 29133 57059 57586 22198 29766 30153 26651 57505 29488 61178 21579 28711 1161 61628 4821 9713 21813 23673 14646 30639 47939 61758 54559 59867 18937 4483 19681 47123 52174 11458 15472 35329 60921 55386 16235 28082 50163 31269 20693 62840 53776 29885 14185 33151 42285 47189 54566 7775 47583 12476 3793 6961 19692 3366 38917 50489 16301 50846 34569 35329 33703 39178 49703 33466 11800 45814 36888 62362 59212 3153 50141 6692 48254 42627 41866 1467 35125 28638 45461 64109 61077 25386 42596 44993 63281 22439 46843 20987 48464 55493 38950 5562 42679 60780 33354 53088 19032 39737 55885 42709 46924 20687 18267 33345 53391 49089 19867 14340 15549 55977 8222 63650 64395 30724 52857 7600 35504 5941 4743 35355 6283 41668 62881 38907 52364 53112 25829 6534 45495 24441 19997 35743 10155 63189 23885 10122 38961 28787 30227 45034 39835 51384 59191 16914 24538 7957 4300 29306 27161 31087 49361 58241 44868 25464 16357 27620 49441 47969 49799 57406 10949 52679 54179 37552 32799 12443 25290 29715 55948 1838 4299 47416 23439 34033 45611 15177 11409 3766 25684 53718 20446 41517 35022 2726 53477 25011 21619 36090 2115 3930 13126 9137 58414 30138 41420 62863 52792 50935 15873 14326 29240 60829 52871 12577 18191 7439 49466 52324 54422 41340 11685 28325 15482 21981 47900 63470 53244 35285 31734 11802 47664 25443 5339 47305 62584 48634 9796 58248 38605 28687 54620 24602 46177 53948 52729 26122 33553 48833 10510 60297 34947 64070 61094 51197 30158 10372 23132 41103 44394 35541 4319 37194 15528 13432 8157 22885 49141 11940 29658 55763 35965 54560 17061 57343 5598 3033 32879 45912 57712 41217 41232 12551 31007 49396 44756 10059 51250 37893 16999 46190 43745 23196 53005 12771 23903 38713 26222 622 25310 46676 22516 46849 50669 31732 9029 32832 2768 22774 51291 30411 52145 49882 17972 64182 20006 1240 44620 21789 49474 41736 0 3489949237 +1024 27773 31149 23163 64077 23609 9830 4405 56399 41188 36505 20734 42559 57914 56577 41709 26040 45718 40354 51826 43928 62650 60449 64408 21143 48631 61987 44826 52991 17746 59842 17349 11283 48613 15354 27307 44796 35027 1505 28424 14414 59926 31697 27158 13308 18342 9447 50042 2687 63592 11170 36069 35313 7006 12676 8738 5246 3475 43820 23683 17900 39915 40459 46552 52596 10540 59096 42328 41104 47578 24107 54413 55515 16477 22582 49402 4356 8899 42852 27568 33070 16283 47647 29026 30837 7524 61894 554 61890 626 30577 30558 15851 26792 57944 39430 42625 46699 20102 60979 35039 33538 15762 16127 55539 63150 49174 51719 59459 49021 55499 33676 45755 28514 60119 59728 13739 27855 60480 38744 60237 2123 43702 30582 56937 19740 59271 1985 36143 44423 58980 52628 46652 59664 48933 7361 22991 47187 50760 43257 42607 43531 14648 51963 40692 45819 38862 13440 58212 18726 56666 39696 53427 52494 4690 23752 26728 13015 17392 59496 43524 12088 20176 49085 62864 7723 44675 22653 12606 20710 60192 48005 56894 64398 11847 24530 28594 3801 21520 25435 51082 32841 19138 51621 5407 2152 33194 42085 52806 61067 28545 37182 17464 36013 28913 54613 47996 50745 12612 40010 49836 7829 12786 947 35575 29211 33528 49318 39373 62259 14700 43108 51017 63439 54731 49625 10293 6868 52215 29939 42216 58110 55193 49020 57483 16023 7882 41211 17280 40563 30111 38726 55574 2591 46771 11793 56163 54373 16359 49190 41544 40205 4889 63457 54424 39763 2237 26587 7704 20240 28879 18518 18227 26941 59166 12690 47504 12071 34061 12660 4700 16918 19119 51492 3861 59721 35696 36907 55738 54966 21735 11416 38501 36421 13929 3376 38137 38828 9513 22676 36068 36549 42280 9621 47931 7232 60811 32980 23758 6572 27730 22105 28250 45570 14043 64000 13223 54035 36303 37494 59627 62836 30338 28105 61744 7170 1245 20971 57774 41335 27529 10818 45418 31233 8558 18106 48049 4957 10187 48619 19795 46991 12924 43662 17017 51646 36497 47013 49053 60301 61318 14997 28340 63000 56072 18448 49976 43769 30753 25982 40511 8092 57261 8675 33214 29502 18960 43188 3181 13437 9240 42771 26902 35366 6709 64164 2007 34798 35070 47157 3970 6675 9028 24089 16995 50226 8299 38621 16739 46536 13491 64116 22235 59443 13751 42184 60336 34615 34226 26701 61214 41319 13408 38437 6359 10227 12878 43045 217 49899 230 28037 8034 50857 29372 9060 54301 27788 58467 38207 52936 24382 30318 14925 12397 64410 60602 59372 18473 4631 19428 31037 59801 58262 35669 46163 41898 37122 39315 37236 38734 19918 55399 27960 29265 16322 52884 35284 18383 26554 49610 46328 9626 55965 44421 10583 24069 8812 41989 58919 12490 12053 22976 48133 39684 49563 25243 43715 11844 46643 43453 43982 62871 7951 23579 47220 2842 8676 51550 34279 4820 15968 44195 1652 53571 7758 39567 10582 15952 16458 30011 12523 37204 35921 57827 61650 3199 21963 21383 40331 56160 1303 34446 60580 42432 29095 497 57447 36047 34176 43770 6319 50847 37643 38073 34761 11252 56334 7703 41622 8871 44888 853 34479 29567 53876 28375 29412 3036 42310 38027 37007 19884 18161 35762 37730 30360 27215 8278 21763 46059 18210 13792 21467 41928 56874 42163 15914 39831 59991 9185 41646 46163 34257 55227 25778 31119 47796 47 11765 42980 37690 55811 17571 58499 14341 27273 20678 54642 63941 55794 39840 44421 24702 17482 12211 62823 63474 15051 8912 13299 15192 22241 7118 13869 56669 46043 5142 52014 26292 11477 61587 590 16598 7569 21018 51132 62774 10442 38148 50109 12642 12922 881 29764 4400 55033 15344 61595 40277 56290 22536 51291 14553 43710 45166 49972 53408 20012 11650 39443 26822 17980 2786 37099 11966 21889 61231 45898 41915 9472 21903 44671 62738 21910 34318 41495 48867 45604 3167 19292 1106 35910 63770 27856 18338 33134 19614 54968 42224 4149 58977 53901 46442 4372 42650 12609 3963 52257 57425 1055 50541 12183 37548 7688 54796 28327 1898 30698 3919 25005 19944 51558 47469 23913 63896 58784 45493 44285 1069 39327 41960 38718 34532 11968 28953 12312 11382 9559 34017 48693 18648 8018 41472 37411 46156 940 47191 12242 42918 42555 55753 1509 1602 2120 11739 22910 24442 20850 20767 45750 22070 53249 56970 49676 4118 28875 28225 56040 38279 2065 40680 15000 45671 55103 15343 48395 51187 10822 38497 16862 44757 33985 19282 62252 2281 27924 2208 50483 58266 57117 52911 45813 19646 58516 19731 14095 27216 59436 37394 212 47469 42406 20835 12938 1483 29887 20904 62368 6018 29286 60172 42048 53237 45637 6506 33643 18915 5181 18449 62439 1764 37567 58145 2015 3655 13550 58431 17128 191 52533 33419 12562 3764 55026 54560 24351 41405 29439 19729 46185 9234 12420 40560 28125 42411 38602 2117 43724 46141 3310 2646 63466 28897 9923 10838 54551 4085 43709 831 52788 16720 583 45519 39950 8149 8013 60858 3308 49686 9966 5038 21599 6457 6883 3505 16317 15733 1785 25589 22911 53755 58443 21373 12113 53159 21558 33350 43006 10630 11484 4524 16426 43567 22215 41431 27110 19770 18747 5262 39167 48374 48581 56881 38688 4202 1731 39966 8179 7877 45469 60238 34212 60597 15303 57919 54792 52143 64439 39350 18959 59571 9582 39241 3123 33104 4968 14256 33961 33931 22039 56757 2698 39956 39692 13028 59592 19584 43117 10204 38768 36907 8045 9613 50496 51650 51317 7095 20271 17823 30826 42037 22965 52240 61492 22026 25317 23742 36122 33649 63130 30711 52630 12149 28700 2380 19632 8073 64034 58450 43833 9118 54192 31382 16227 21431 26755 13438 53104 45234 9425 60119 20979 64434 30828 9086 5111 50830 48341 40269 11922 45108 30212 51771 41552 39873 58101 33536 49471 45071 23132 30073 41604 49807 63489 7240 51949 48000 19805 43762 35721 21043 59477 23702 43348 56180 5873 3155 5079 55784 58327 63947 46385 51855 21135 40242 43372 22633 20188 30670 18677 2857 54460 8513 47912 53711 15028 33707 21749 22822 38263 10314 23002 28660 26960 1250 35534 20037 47459 17918 55796 57875 27559 56256 26814 45424 23215 10511 55647 20035 11889 28710 14927 20628 61046 49276 54400 41796 35558 9179 16827 21128 43849 62211 47856 55755 41358 15331 40809 16670 44560 64087 63980 15020 4726 58587 27596 59474 36219 831 39239 7915 62179 14427 40678 18928 16415 20874 59793 25726 33944 17040 17232 8212 38256 56652 36905 57197 64261 53482 7332 47905 33537 54168 28998 35291 49417 11439 11353 46293 63902 3694 17647 15916 43100 19523 53408 3373 16177 52067 20210 19637 6167 4910 29829 63788 52336 26851 55445 54964 49300 16777 2667 20739 46037 9350 10697 32894 45828 22963 14949 18702 40971 59551 2332 52099 39382 20267 46128 26414 48216 50951 12289 4560 21671 54188 47938 20081 53291 64394 44944 33792 56087 64393 19598 35777 22162 61042 41669 14546 8167 45282 22338 62554 56812 25454 40797 28681 62549 49985 28467 38823 54161 29688 33934 29251 35303 49994 55158 9076 19316 54004 44308 30085 54537 26975 62970 31696 50429 35075 41616 12474 27836 21212 46512 52241 59890 59614 46073 56058 49144 24735 3691 62141 54776 62883 26627 36554 46551 96 52470 5028 6972 15756 9771 38773 57219 30770 64492 39413 20562 57096 7505 31592 28835 3165 62389 2756 54445 7773 62418 46008 7866 47006 58221 18538 22180 58406 23458 38118 10519 49793 60579 7807 8554 54969 34689 1233 26714 11408 33900 63524 38792 54377 30734 30022 46411 33743 35539 42051 4031 11442 51840 40138 40125 20282 14941 43848 7838 2738 27462 59658 45892 63967 40726 33197 26556 20658 5985 42517 55082 35622 55280 31602 9693 17357 39434 57214 45403 8142 20802 57302 59366 27533 22357 31472 34139 55415 26923 29890 59468 58975 11651 57912 30601 18640 38993 5310 36692 35474 22531 337 27905 36392 32979 9194 55684 52230 47398 11109 47647 16787 21720 40492 3999 13182 4511 42611 6450 51608 58355 55817 41675 39992 15516 10498 52399 25743 58265 43454 51591 54031 40838 22380 43628 48603 5112 64261 51489 42605 14527 27084 47643 10251 54243 55955 7923 29224 38958 4625 54650 11336 62716 5789 29114 62958 16965 15820 7333 27505 50684 17448 7224 16415 49227 58151 8993 43118 28598 37385 24143 43910 4738 20087 31360 14779 38963 26824 42650 7463 41470 34041 16089 5464 890 1089 41188 9327 41685 57190 30617 16110 46707 6479 987 27413 18585 29616 60991 40125 49913 38654 12523 54873 20038 49959 41014 6500 33293 19163 55723 33082 58769 47732 9317 18001 38732 52108 10692 15431 20555 20670 49699 885 14336 38489 49305 48967 50079 62857 34966 18119 18613 17652 30222 45679 943 26394 22879 43462 14454 3093 43166 31362 45346 58321 33824 44864 41621 47706 15559 7978 24448 22385 55807 47191 25400 58198 5696 45790 62934 26563 52262 32928 56470 50996 12810 46411 16456 21471 19131 38839 48483 19493 52525 59950 59577 55396 25136 56386 24086 17266 51551 61407 25251 21208 53146 2397 51589 15623 40940 14774 55693 42040 4351 10892 24760 52236 45424 57879 20170 62007 57447 49313 59594 55246 3642 4696 11888 46519 53122 1973 38749 11722 5637 6717 1109 60878 48483 53010 22952 39900 62214 4718 57835 44684 42232 31708 29304 18870 35011 26151 13865 21545 48817 35290 63934 39052 48088 53069 55648 28202 45326 54322 31286 5261 13337 18796 61131 58211 14635 59252 22034 24277 45731 20598 19440 4920 38557 15329 3879 3664 44369 16175 1563 41060 13028 33763 11811 29173 9686 25321 48264 16109 33272 49333 52925 62367 44420 23933 37797 41042 35667 55221 40641 25720 13993 41581 8601 49913 10499 35874 20233 46706 22987 37388 1787 30659 60959 51950 13291 40158 28280 29878 36398 19173 28020 1401 9990 49201 12570 24344 56603 12100 20462 47743 44879 11429 48900 50983 23453 20219 42262 58154 8386 24725 44081 20318 17103 19943 21931 58903 13693 40527 63301 62233 42248 33880 10132 19401 16981 17373 47831 6681 62511 24549 6563 7221 24450 12872 38097 35218 53145 388 34871 21560 38444 46266 15271 36993 51941 5813 58047 49707 63766 20731 35438 17131 20983 3176 1138 49498 44753 48998 43750 15176 46147 23559 61401 32820 51683 5631 2990 7321 39390 1117 30330 63514 12286 6728 49780 48894 5178 54737 40014 18417 41864 54061 11563 56253 8798 53758 43184 30210 55384 52012 27018 50321 28903 46496 49333 25843 26429 18296 53032 11461 61402 30553 22784 35138 27012 62867 1190 48784 17498 30294 55061 41016 22241 62760 49759 52715 63900 21619 63505 10137 6339 55205 43238 24803 48177 800 35756 58009 1572 46585 33116 59859 61760 12972 41712 33448 20178 42245 37566 19320 18287 58997 8596 8218 39170 52808 50763 17383 24797 46525 60263 45027 5010 23948 18679 47236 62007 35002 18917 57448 36371 61743 60000 59976 14782 25495 54122 26729 55604 18992 12496 9146 9121 11157 22300 41935 19510 16883 13886 54575 19133 38356 7934 43998 47777 58666 23395 4342 14614 894 50799 31550 56296 6039 12429 27358 24819 45602 57291 28090 41952 50421 35852 43138 16013 60417 24701 56757 61067 18090 22855 63946 3123 40419 31247 21849 23201 48678 55247 26127 45228 40755 38232 12018 343 61360 6675 53812 35681 44714 2135 30645 12734 8373 29877 43326 53644 13916 16781 61117 48773 1487 19586 54362 56466 42055 22796 49743 37299 20638 50048 26666 41512 58708 64192 39602 55038 17694 22870 3144 45225 43181 23985 41357 7306 62774 32815 42438 38204 51744 31385 50233 42715 7821 54806 35850 36134 21873 39727 53202 24527 12790 52437 8796 9488 63193 59450 57741 6992 48779 51750 63610 9085 41782 1002 16058 30026 58885 42421 38120 60517 7550 56412 40946 27811 11158 5385 56527 26585 12158 61018 48468 55447 17763 30967 46574 46881 43653 63065 47844 12999 876 33649 1412 49038 27436 12450 63983 28883 39847 12889 61818 4558 59639 57900 3931 61150 46037 47740 60731 4673 6757 26218 48886 23521 20365 13521 6330 19387 45958 51642 30413 42509 56461 4718 33739 26554 62106 6620 2325 4767 25075 35308 3631 22531 12171 36686 8887 40419 38155 50456 35860 61050 41973 2318 44559 16714 24849 8194 53800 47275 63869 47372 54276 14264 6665 8319 998 2032 50500 49623 27705 40023 27298 42769 23503 57954 44312 47688 25322 14418 30343 59570 48022 56140 18830 9273 54710 63124 11560 29309 28231 30771 11634 18292 14144 42366 57073 5902 40797 54541 37711 55129 57949 21376 38298 23373 5825 28623 21699 26721 27478 53737 41716 43812 61539 49498 14755 55236 51188 10534 56107 41733 5635 16105 38091 22913 38115 22086 20495 18821 46321 3105 17875 37342 37211 47685 7320 7557 15719 59176 17885 40968 25532 6739 56159 25612 60629 16874 37482 25714 63730 43026 0 1326999287 +1024 29247 27094 59477 16870 5218 15437 2727 27046 40098 9303 40877 3483 55825 50935 53522 26882 59030 17003 40474 57685 5322 15392 36515 60917 47898 51525 56000 33721 10769 35277 10652 47675 54499 30714 37009 40442 53459 6156 60434 46822 3212 29382 12339 39899 13169 9916 20490 27548 26646 48217 63433 47537 2232 45196 43495 13182 18045 21698 37447 44992 21765 53457 42048 35123 4119 19475 11373 16919 55984 9862 42958 30130 54866 60587 33487 51711 12625 39630 58074 21146 47931 27608 37127 2035 60321 46781 46221 58258 59931 60822 5023 11705 15875 43207 38580 63551 2115 57422 19016 51991 56977 9173 29107 25292 6208 51433 64110 14073 37621 26852 42943 4428 35730 41041 43390 24601 53564 27285 61518 12922 42444 15497 43319 57142 24543 50321 18439 3351 52162 41681 64491 7600 9827 36099 47970 55092 8309 12909 21482 45934 36700 17780 50667 48185 51333 38231 554 15642 27477 44272 52040 5039 38319 8552 7017 14746 42558 37308 14725 4015 20384 37073 25985 43786 1856 44587 13213 30302 16893 7823 57258 266 53353 25129 22772 52650 30445 43042 55610 22615 40126 61657 5907 30304 52881 60818 40941 42090 2736 59310 34214 20940 43923 56186 18440 19316 61849 52355 14655 9179 24756 38351 49172 8750 7735 27424 50940 47283 44558 63888 5426 57747 38755 31150 50260 2701 27157 17322 22961 47553 10214 7770 12575 53405 3606 24751 19890 60308 36423 22984 36355 9521 7501 31097 37468 24184 55570 39501 30477 14301 55282 38138 17643 30638 5620 45722 29294 23347 26607 35776 54570 20966 42679 49762 512 35493 43736 46622 62204 46716 42095 33612 25102 38689 9180 20433 43107 35492 20801 58119 57574 8877 6898 9027 22021 10798 1433 56952 33289 38688 20653 28361 3508 38992 62156 17921 51769 4656 54630 2294 28757 30311 42980 58112 55090 57146 2669 44792 51060 28493 40306 37930 40183 61225 6977 42049 57162 20257 101 61441 45593 39693 25268 41774 56908 23393 43001 41261 37421 18160 547 60846 42691 30531 36311 43623 35118 24428 9189 42690 51033 22881 31428 59320 54325 4200 30607 46028 52505 4030 20694 22641 33051 62910 20230 43783 24143 23835 33844 57967 51589 61277 11818 37078 36400 3027 33401 55087 11031 9906 44092 27253 33571 38341 57948 50702 41385 15544 25581 27106 17360 24420 34831 46906 13606 43040 37720 56537 23919 12249 23104 14550 39865 52215 20320 2405 29811 4271 57632 8756 15276 59197 44487 20735 50362 34156 28819 24721 58664 7977 49428 9670 3225 53777 34820 59279 1380 19273 5670 33697 7284 2956 23799 56136 29598 13188 15646 11114 47482 44166 3526 44822 62280 51754 62452 37553 22129 4553 8692 59038 16052 3998 14577 56752 53530 45771 25063 58104 1297 40648 14892 10129 14743 24922 19393 52040 16451 50060 31230 18083 26091 31654 5248 50248 25542 50322 10900 15647 10397 57208 14281 9632 60440 50339 49417 60755 4038 14978 15745 28820 8327 59636 37224 17539 15036 56957 14772 43589 45874 63931 13029 11839 22105 52189 7803 56603 55019 45820 3756 40963 34551 21013 43687 35373 50664 43824 36479 40036 29110 17658 5210 20638 46469 12336 21201 43204 36535 35744 26194 43281 58642 28079 27938 57780 63660 51284 53386 19763 44427 17602 45791 12201 44771 25080 44371 18446 33713 25055 772 45499 3920 6798 1968 23781 47801 57817 45078 13464 32908 489 5483 56044 5076 58136 12479 9127 9448 52533 43227 55128 52476 17820 31497 12560 18124 29021 6172 23653 21302 50629 57699 39732 15271 26717 29015 8327 5115 58242 38999 49491 29406 46546 3310 1465 30405 36147 36488 61309 46447 25279 31580 6203 2448 46252 38011 62406 19500 53434 48059 46726 55118 31701 63332 48412 42537 48910 18195 27377 41786 25675 30632 33797 55336 11658 42826 25581 10289 59890 59387 19907 56036 50315 26239 62395 37245 52851 7783 53447 22283 63612 41455 53854 25940 44866 24870 54622 13173 4047 13516 44530 10434 20193 30277 53047 22037 58807 40087 689 47156 64373 17844 632 55030 54407 57871 17924 2478 12328 15272 42063 29468 17486 39810 44166 18268 43214 53847 47135 30249 31193 28282 29448 62251 49615 10797 43691 10890 43774 26971 3069 40171 49930 55146 18893 24962 42447 41123 34166 59202 33794 19528 46913 29369 50741 46405 23771 3717 17124 17025 36613 16061 55635 16731 23094 4426 34754 41339 24422 43721 44567 55369 3217 29895 48718 23017 48804 213 42069 54337 63042 51148 38538 48531 62422 34463 18091 13357 32905 20861 5225 30938 4121 51391 4165 39358 58591 61611 21448 10612 15987 62729 28066 56928 3338 34437 50946 31116 50217 46226 24965 1582 42934 1988 53314 25506 53999 38215 21167 37491 41083 54786 4996 54505 27982 23744 43196 15160 42764 61041 56123 7388 35919 15578 12076 26451 6837 59169 39222 25561 41336 45387 60669 31071 37839 12883 62620 28365 25352 47866 62530 60136 6921 42566 20558 26455 3715 485 23882 24532 16173 26557 60233 11159 8303 27637 45177 11164 59390 37499 39018 54493 27279 8188 26864 8853 45153 28260 16326 130 44220 8018 52725 3928 29024 24289 53785 50300 46460 51009 48079 24171 45325 51422 17934 19685 14075 27602 56905 56055 14239 36367 12030 46872 21357 47862 20033 19768 47521 8484 6643 28032 5281 24911 24241 56219 1416 28803 48888 45550 46776 53108 37404 14221 42277 34165 21462 9416 25129 20639 36373 15871 62074 36073 17512 58543 40892 63639 11833 57564 49869 733 24539 22380 15856 9168 16409 10070 7356 41511 7500 58301 9695 38358 59741 10224 45868 21750 34241 55155 38590 43483 52642 33095 48871 51414 6572 61622 39269 49903 63614 14235 25094 6042 20840 42561 27794 51513 40308 12961 11225 32813 35983 50520 12238 48581 3559 29383 42252 18292 56173 23861 40225 56413 19638 5325 43856 54908 1358 64072 35857 36534 29349 13951 34789 23132 26557 54438 59281 17523 45520 2204 2272 40017 17077 41129 19502 49453 34606 53389 59968 51886 49338 19570 61914 21593 42260 38300 55546 15833 2624 28569 1702 49357 41532 15751 61611 61574 26268 27759 4506 24330 54925 44586 42522 60114 29402 48516 59178 56975 17574 765 31546 41435 29753 44211 61549 11779 27737 18774 11047 54674 59106 59519 42509 47113 22219 30901 58295 41689 14774 16604 35935 37884 62817 22312 30167 24190 10777 11570 48645 9468 44581 1994 25702 44151 53433 57875 42891 26009 30619 10090 40364 3497 6750 1928 11743 8475 20298 57783 13825 7927 61021 38496 20104 35798 42994 27302 61315 40554 3388 55749 47032 54814 48301 40548 52923 49839 47030 42656 24419 59012 43219 17276 24583 54574 26664 61218 54456 5781 38730 19940 12918 55907 40474 24134 21532 14230 13436 62029 31467 4250 58202 54007 16726 19520 26582 38198 56572 39869 2404 5967 30440 3386 59631 62408 41083 14009 18979 6480 55505 38448 51301 13400 5491 5451 19415 20215 16342 36671 38143 43492 63837 30428 10232 36792 43844 54123 63139 17177 15220 35287 788 14523 6765 18571 16621 55477 51388 42893 22229 25191 39454 38791 6008 30820 53640 6194 46732 41719 23962 15426 6228 1914 53991 41397 2542 9174 47583 34069 13678 49438 34100 59909 56132 15861 3669 51977 45021 57453 23917 5671 48709 44557 55992 19730 49902 55383 59226 36126 63237 25081 1164 50919 49365 60194 37034 411 20161 8545 3752 62402 28136 24754 23409 41664 16427 11548 12209 46171 6709 16028 42535 29107 53180 35019 22148 18303 10721 43723 52208 49826 13856 61628 14603 12431 53310 958 28481 13894 30087 12143 6394 31001 2223 55276 18313 14395 998 56736 20783 60532 11177 42130 40589 8333 6205 24612 17767 60364 11063 34526 14458 37559 21209 54331 52944 45653 156 25578 13764 6591 37642 19303 45014 58504 14904 31017 23388 41873 12737 15142 33450 5399 20373 15254 44816 42520 4778 11931 36014 37370 29494 52075 470 207 33161 13940 12880 21054 61985 26799 19046 34867 35965 44922 58798 63569 42729 21679 60566 405 14496 29156 8351 13167 4849 45181 33506 53588 49309 38556 23432 50161 57410 1158 13767 27072 38183 19950 24763 33712 45855 3701 25659 44366 49532 16382 51027 854 51630 46799 49040 54506 6925 37982 3815 28895 4988 59924 28075 54939 40530 3799 56812 30734 62382 29370 63401 7577 58702 63939 47652 56372 63891 35598 29827 631 25324 53112 62211 13224 47999 1567 2882 17844 35495 43239 2481 60243 11033 16937 572 3772 61238 53732 37239 34871 40277 21986 55120 18841 29733 40703 39734 39978 3641 41302 29423 32922 7943 25123 25094 39961 15 42317 17410 36481 5512 48229 58129 54829 9829 45316 19919 14025 28911 31186 8966 62726 25509 37837 46140 47715 23845 10594 38251 37546 31522 43085 61348 20776 17383 39944 14810 60304 34910 8321 24833 62927 15769 28120 47833 11425 7659 22198 17037 53148 20410 17869 23569 42757 12351 60358 48790 12598 21099 60577 3705 57712 55720 6840 10119 58470 19184 62046 3591 60791 3588 11758 29274 49665 3847 39100 55424 58499 59670 52877 24202 20925 1196 25025 31197 43404 6482 29715 14744 29530 16792 28852 24632 35708 9892 61902 54278 20033 26148 27530 8589 13601 47380 23355 5130 30959 50166 3139 20447 9844 51353 36488 39505 39308 51085 32954 12622 47111 25498 136 16678 12833 39852 40859 51332 10363 31106 8448 40403 38485 17297 57143 4795 43499 24962 6410 55085 18518 31653 40380 14908 40911 44073 35461 21060 6322 56801 45567 13139 20531 57045 2715 9745 52297 47679 7953 35727 19037 39746 41428 50655 57734 3875 3205 29999 52357 43345 54811 36127 57336 6269 4999 6816 21756 42620 37561 19001 51259 20900 30299 22072 44878 16003 23822 27553 55324 39060 52682 26949 41867 18539 61140 41754 36751 25475 33852 54367 41147 55653 56669 17703 11761 15891 62462 16383 2942 4954 38993 61566 51723 44848 43874 5121 20788 17756 47206 21763 8413 34641 29567 45986 19290 15733 29050 58575 37589 28642 10744 63062 55029 6020 54687 57028 12220 9468 22148 13197 62402 20079 40323 54648 49382 22030 36720 30138 36757 45417 5306 17569 23154 50916 7397 24299 34581 13758 30445 10904 4010 30529 58124 28573 52326 60294 15997 20044 7898 28003 34302 56144 56511 32855 56072 27616 15506 10709 13894 15749 16989 18619 33406 29568 4617 44274 10036 18968 18658 97 17187 3622 53829 26480 63181 43426 53086 35856 3186 3775 29901 29972 41631 24179 37238 46673 46695 16098 59262 22239 11930 10056 54422 1631 3418 17319 53003 7576 28900 50055 27041 9547 50503 33655 22508 49951 8671 12402 47722 28177 36401 61797 18653 50490 38949 44094 60711 2576 15369 49470 28436 35792 60498 15142 9076 43268 14171 48020 59749 44363 10643 55884 21395 46819 58580 61248 52871 30358 38302 37760 16144 29333 40156 33156 38206 45533 37402 45526 43864 51686 27100 13562 44017 30487 24566 27028 17217 20983 30511 13230 27614 54090 43222 22619 49464 46691 41140 20499 6529 2223 3870 43694 56991 7391 9025 49915 4656 55466 15115 62800 20900 11614 26796 9641 20651 52430 26304 22152 36820 59246 5518 37477 19499 46794 564 18112 53482 4040 29549 17067 30734 44485 23278 1346 28505 12965 36728 46874 61341 1611 30286 27391 42134 26909 15260 6608 29593 36088 34334 20318 17663 1272 3326 61500 2794 21034 46597 51177 61852 40389 51197 20691 23148 41759 5273 29227 44190 63574 47231 62562 48390 50588 52392 44736 31186 17308 61810 39504 25788 17628 29462 22394 58330 4129 38029 22663 4051 29 38981 59882 7361 4348 1953 18711 26020 38869 37780 1221 20346 5094 23872 59207 37696 946 55244 3476 29597 45153 19055 20164 31035 30497 62359 40697 58189 32991 6022 24121 19559 17641 12453 4362 30721 61644 47849 1139 29361 9061 25536 59930 26287 25785 37063 6562 28014 25681 60571 42503 22063 42525 20960 7373 50707 62491 42714 42079 49287 20992 45318 63358 51154 63589 49867 41705 38983 18384 50781 11759 37192 25669 1489 51582 5477 43342 35211 35191 8107 5622 18973 20435 11987 16219 10542 18297 37709 27450 58563 20783 48326 44034 3175 57950 41064 51443 47852 28598 55947 6802 35844 21335 21838 12330 12973 48509 2326 36006 10850 20182 47085 31304 52454 25157 30474 21133 11149 50848 42861 28472 31504 33946 45183 51804 30711 61690 21166 64192 59194 38326 42468 46925 46510 6506 58690 7739 37576 14091 52746 3939 22430 46019 177 26252 60765 20678 18141 16599 38523 64212 41741 30925 9442 36136 4665 63439 6667 30352 24818 13160 5220 25547 46242 48747 27610 10382 21301 38361 25437 53748 19951 61940 37069 44580 26639 14216 49809 52093 51213 30737 33268 25138 8397 24536 16610 25959 58941 35508 7755 30776 14145 32827 56478 24166 40175 6764 4703 12426 12067 18603 3751 2779 61070 8490 899 24263 57792 60685 60697 51523 49152 64167 49259 11232 12321 59056 0 3476174128 +1024 7286 17022 51861 12232 37847 20109 51930 47659 44302 56687 6443 58144 48891 52855 19259 6401 7399 12056 56233 8003 36629 49907 25341 26859 7998 3784 63698 27369 12388 44883 43450 26408 22578 22491 29891 22198 28824 27305 12267 48063 46587 46693 38657 9369 45783 47257 24366 33146 16529 26552 4369 17915 38187 27486 29541 64129 61953 38818 36292 8469 60462 51765 14321 10454 28242 61800 61290 37610 24201 34617 48513 10454 21424 33028 45009 55945 13244 58292 24874 38619 57252 10753 51037 60884 13560 13667 6454 52719 55426 45335 61225 23728 50036 58746 64232 49541 37288 17851 58417 9110 42633 5566 44930 15598 35276 10059 55702 59256 58514 57896 7889 13827 34968 41275 4406 33987 6705 1231 61435 62579 13183 13044 1967 30984 9118 17439 11087 25954 42090 23439 53692 16780 56889 59897 33212 45448 462 57413 54317 26828 24849 43183 48330 11757 2465 58952 60904 34781 24251 10463 7824 26019 54411 59761 63748 59729 22531 3300 20054 27540 8979 21133 53417 46597 1278 44395 30617 57407 29217 51496 51435 15739 21877 60770 22833 59282 43137 37588 31707 34538 56716 29313 28633 313 6317 7565 19925 39082 38324 47977 14034 53512 23177 58991 61043 29203 37891 2254 60928 1702 15077 29353 59845 54373 40321 44264 46484 40073 62473 60340 49543 1533 30453 30464 50550 36247 21953 44824 55548 49408 53808 63819 44354 60771 62220 36790 19049 22362 62452 52410 44678 41271 47261 18949 44628 4602 36561 11650 20426 42566 36960 12013 23106 15039 31629 49542 9471 45227 63918 60666 28833 27408 28255 4882 25713 41322 18641 13056 58553 43684 20381 26358 40675 7901 24941 57347 47936 35569 8406 12517 46064 10892 55366 8358 33397 37900 31205 41825 44709 48881 9480 58755 40607 44544 30173 1214 28848 34709 30472 3423 58066 28693 24801 45202 53075 57571 43636 23433 56355 61181 36986 58708 42008 42640 46258 39658 40838 64436 4673 223 26778 43385 12146 14537 2116 2213 61036 55237 5953 31166 38593 57829 4226 4435 13172 53994 20946 38640 24931 47857 25211 43360 55797 605 18315 8459 56471 39782 12894 59948 11572 36819 52558 37397 57926 39963 34506 33344 5948 6408 40506 28052 33251 8726 11931 62138 13851 40325 36446 37197 34716 143 10242 29066 3375 35760 26465 500 40266 9982 38264 28236 63420 54626 48978 27854 7415 61198 55872 42548 59185 46530 4275 11003 3673 16580 31213 39466 250 60466 31034 37004 58820 19920 40651 45080 50778 13123 7988 46364 18078 58620 8252 26833 36162 28650 40902 51299 42523 53313 33713 42547 61554 30436 54884 56857 37752 23559 4165 43900 59441 935 48714 59346 18446 5366 17622 2831 52331 16388 6251 60071 59474 30024 34506 49378 57704 60757 36301 11191 26906 11214 2048 27687 51278 7323 22694 8555 36646 47809 21899 56633 5403 570 24888 62745 54475 10889 26557 33357 3302 56810 34496 54065 41589 52145 21032 18156 53104 60002 104 30058 4167 53111 9987 63239 58684 39165 56455 54815 54720 60060 15196 1171 28753 59605 7333 35202 63388 28386 45769 1151 7789 4344 62682 30128 30969 26264 11407 50323 16641 45825 62027 30683 39916 14833 34545 18121 18077 4586 35524 43215 28075 57762 22221 42958 4260 4262 26118 22020 24702 52519 16206 10016 17374 16063 42151 36482 47055 63379 46360 58677 33900 61344 13472 27277 46034 55949 29255 21514 5872 58742 4285 45241 38547 40813 25086 1593 18315 44509 36347 60402 58969 6333 46287 34497 61370 46373 46975 59533 39380 3871 554 29408 41551 26509 11642 3018 39909 22832 5215 13605 64119 52618 17618 5117 56536 25109 47884 34978 24402 5702 31324 59434 11067 17710 60167 46480 41750 3069 25616 9385 24293 64474 39398 24277 36152 9593 25922 4296 40181 16603 47168 34498 30729 48947 53567 28082 24846 7179 5465 34358 22958 22666 40950 15567 59471 39423 40685 13192 8556 63559 35411 31685 18394 8105 52167 53979 39251 5540 21499 54176 40776 22787 15712 21265 12348 2560 17279 15796 57315 22118 29331 46781 46864 41968 26268 35041 55878 442 12517 47840 37408 63949 55321 60238 2060 15884 61072 27795 53257 15831 61405 5565 35462 37389 9360 61825 18036 53727 27211 18369 14342 1593 43236 38118 50876 38418 14533 7419 8259 62809 31654 36160 10145 18042 63153 35622 4255 38950 47749 5194 40213 7153 36109 36921 63990 52461 38695 24494 46040 37039 35921 1818 55373 58583 12060 7101 40850 12144 33472 22065 38780 23197 54963 11293 14227 50933 54536 23539 41417 59981 60891 51874 16809 64097 26866 57394 18658 40085 63141 33853 27736 39333 45202 44918 10750 49910 44373 4974 62650 5664 34367 39679 30873 1896 45085 49005 36808 31061 38446 25403 41966 29061 14802 55498 10682 3907 9702 18999 11919 32848 1060 43077 15483 39226 5140 16988 560 24020 24979 28075 37750 25271 38274 26936 45638 57190 6773 38206 62800 62012 35015 14817 56598 34837 16958 44651 11378 17720 22100 28658 51926 9886 35431 13655 12062 61705 52289 48271 40331 56461 55881 13798 51004 8897 25291 7908 12310 20209 5495 3484 33890 12369 47378 60734 8731 55097 26713 11950 23739 12883 37222 47778 53004 23542 40982 33116 62141 12634 15372 47384 8500 26092 16977 61823 26773 59172 47641 28443 53831 18809 35702 23140 49977 62703 16095 14115 41679 48071 35532 17404 40753 48575 2313 12037 184 17531 44891 62461 4809 21187 55776 43565 34834 12520 7211 5614 58664 48607 25709 16194 63644 27918 15720 11695 32800 36525 45459 37378 48176 19816 39842 27644 40203 20906 30535 57504 3872 47874 57987 57119 30673 15770 144 6601 859 29165 35957 57121 47877 14078 56468 27565 13806 36965 50530 55040 36743 2846 58061 51532 64021 36393 46536 25002 43718 13368 1408 45639 22792 20414 53182 972 53964 23437 56114 64167 56152 59756 63755 8083 6261 22451 24357 7335 13635 41063 44855 34784 25257 18707 37798 34918 20868 44479 4092 56433 22751 35944 44499 20376 64229 50192 2973 35283 28101 3266 31007 42265 38070 26547 57659 43975 34718 16765 20935 53052 6994 56481 14934 60419 28731 44916 33139 2460 647 17538 43534 8952 14187 38631 48922 44997 54597 22470 63118 24789 49925 39681 62390 1845 738 37465 11805 51689 53232 36881 9980 26817 1225 55340 33491 21079 8525 5401 6342 38814 41919 53981 28969 17768 33128 51818 26779 33406 55323 38490 6089 21917 11310 38512 845 15334 7698 63619 57484 40127 40719 40967 59019 24329 23364 33603 44333 56326 11978 55716 44029 1423 19969 11452 58492 8793 56083 56375 60560 15174 44122 51014 5089 11046 9780 59908 52090 56085 24111 34647 33232 52119 25113 28623 985 58569 21445 18270 24356 26208 38869 11471 46321 19775 24024 31430 15762 4657 26867 2723 5634 58476 53892 31249 5263 47959 43546 24573 22642 17586 52522 35313 29639 28033 37818 17671 28770 20747 49936 40152 55545 38823 56501 36682 27727 59720 24311 16093 635 33370 30269 51660 25849 39235 58089 37136 10423 22435 42481 53294 12356 12600 55292 23286 61959 51703 58788 6301 18340 30681 51769 23019 33605 54157 18026 24081 35818 44293 47535 39025 2414 11187 20951 36068 21655 40864 1308 10945 55394 41300 1597 59416 49207 37144 33864 63346 19333 3845 28871 59649 27822 62242 37651 63339 15050 56756 57791 56069 42608 61288 24339 45424 31294 50205 33616 59277 7754 51457 22785 19408 50770 61418 4385 54300 46871 39661 24785 38292 22547 8133 39253 43524 49764 27298 36267 14665 35146 62227 26494 2820 49436 20377 13925 16905 29410 55183 17193 52844 6718 54183 45047 30431 20314 19750 19857 59181 55087 49374 20091 20732 51039 54776 47628 28982 20310 54529 56747 37112 15861 15684 59008 28579 30408 39674 57586 40062 23487 41825 3607 38702 30227 7196 8646 7502 25856 4791 48102 19882 18451 50078 20320 16817 12863 18567 10843 61870 58667 53859 59804 39055 20523 8253 50547 35699 4957 40035 58786 46007 62928 11232 17125 4280 27315 61081 60468 22665 54106 26770 547 23482 23385 33555 24825 6005 6319 64425 26612 34221 51295 54799 53657 51697 2452 35311 57963 36412 32931 1899 62266 10589 35003 9531 7871 28413 16236 34383 60675 35834 58994 11362 58787 9118 20094 26824 35952 41247 548 13251 35269 33365 61448 32952 9218 25990 407 52735 47981 2192 50630 38481 41751 59095 20467 12728 3592 18177 18174 49841 18384 4680 24917 44244 13945 56504 33869 12039 11738 8349 33854 28791 61331 3525 42319 11737 40998 48287 60642 4736 53234 51353 46942 64309 41307 26586 47383 22077 53838 59131 17759 45823 51023 28807 53950 14345 25685 54000 9928 52234 21691 55453 56790 30008 8813 47554 53641 13912 61139 34026 41682 35327 62766 2647 22265 50799 64506 12836 9846 28601 47681 18349 49689 57394 13140 52394 10659 28567 58018 25090 49183 25173 50469 1648 14619 21679 5414 62061 35769 45137 63907 45212 24947 835 59951 53259 7946 21015 4357 11287 34501 9778 62720 42415 42842 61057 49652 21511 62069 1223 18870 33997 29607 27238 21975 23920 62381 31040 54769 33299 16363 13967 19045 62285 36430 43513 58795 49913 63836 44006 43269 37984 17944 26225 5777 24134 59741 631 47857 25758 17409 62156 37785 20417 49464 40747 34696 53186 24752 2633 51686 7766 44295 39059 4613 58604 15380 36496 35371 858 20789 59636 40099 7477 37253 20658 41845 53171 7480 1827 15689 41958 28926 14207 31240 48564 19099 36334 48101 7249 9391 28916 47238 1399 44244 23663 39644 10649 40938 44467 29920 51018 28676 28339 47050 119 17313 6412 539 21522 5144 53875 48047 5317 50626 41063 12323 61387 48613 15799 58382 25828 42330 31408 25080 29868 729 35055 49937 62308 60411 51501 40434 6256 19521 50892 28466 41446 20399 27820 38351 3462 8577 6137 1344 51324 63951 8097 45592 56163 12442 19010 22573 62262 55133 61727 47606 55251 53622 46158 46962 46218 57350 7344 9874 4274 9485 46372 62007 15197 60260 55345 16489 23540 58204 40347 43580 3939 28934 31554 44560 14714 53990 26345 61029 63581 57687 22077 42917 6665 13820 33675 6731 25816 47301 33665 19987 37472 61487 37407 23597 41615 55946 55973 34613 37357 786 25898 59330 41205 2366 56779 17597 34279 42225 43840 57003 7026 16373 55873 57214 26288 35387 35164 7293 52089 63819 48916 56967 55736 57578 14961 44415 39628 17951 14572 58916 39068 34467 3003 59004 27919 51881 3037 52768 17742 50431 577 43310 36973 40848 6336 42178 45931 29299 17177 41940 1175 19962 3041 4791 24826 16275 54368 2224 13239 12262 772 17447 38321 29111 35939 23522 40674 41793 61480 38738 7913 53072 27944 53212 29437 10065 37718 14291 46918 25998 55767 12228 6122 53394 4742 14829 23739 16121 58082 6848 19034 40518 41461 8605 56961 13436 3456 43116 49346 14171 60212 56005 29140 57522 48974 63749 63714 30609 3083 12528 31283 17006 17425 59257 8370 13281 60566 7957 1476 5000 31090 3737 12335 22009 1987 63123 46536 37865 22536 54443 41701 5068 63596 33968 19822 27427 7082 57536 54951 55195 63211 33763 63612 8331 8540 26220 37607 23692 29070 14189 64130 45618 50508 3544 22877 48715 4462 22756 6212 40970 39914 62782 57403 25788 21543 29237 29851 5718 43908 45019 13135 59976 63551 25128 22564 48913 12208 54981 38077 49520 46793 50392 9836 32796 35384 55167 58774 54753 17462 21068 47193 16084 37008 22956 1932 10948 25894 2946 45489 41319 11673 21055 41082 50210 42648 32803 32843 22013 29519 13940 38933 53556 8634 37313 51475 18748 10040 19857 19636 29153 44923 47489 13937 50878 16833 20109 21741 15622 7457 62734 13090 24968 49176 49846 24736 36007 30744 18779 22538 14781 60027 24716 16367 55886 1606 11328 24428 39188 35156 44660 50780 52988 11570 25355 2997 15247 40611 6021 26144 57542 3969 34905 44826 53670 49985 521 46800 45352 24562 41374 42706 59012 13736 22299 39321 41355 48690 37351 38760 3118 37679 55843 53157 12476 1445 46566 46380 20726 60433 20088 36842 29494 33488 27455 51688 7373 23873 26865 6949 4087 16843 37477 40503 29238 53923 49589 44868 11420 8003 60780 33156 47651 47035 54383 1129 51568 52025 2779 24367 38870 8586 44913 63950 18464 57111 28699 2243 42384 53571 11081 5828 29860 54310 42872 14968 7867 25688 18188 49734 39724 8649 24859 44182 58250 33362 17659 7179 53595 14831 12732 30309 26106 8158 40639 7725 9438 43466 44643 56737 12605 49872 56248 18949 51714 52400 11204 39451 45494 15293 8610 55096 64237 16376 2714 63936 18559 2241 46311 30155 18262 48684 33879 58110 57481 28152 38465 62672 38273 26602 5602 44044 44158 23620 10968 11599 8618 43213 52876 21155 7331 21175 26231 27871 42318 523 51917 22997 38493 51269 53615 59968 53206 34085 19545 9789 1353 31604 5311 58755 44073 24852 6195 56572 61582 49875 3215687898 3477001464 +1024 40269 47686 55193 12293 60579 51390 63319 23343 62934 22382 49805 28309 34263 54629 16385 26480 34891 59770 22857 31739 31238 41931 34932 63684 20457 20852 919 38373 19738 27916 61089 58283 48558 63424 53087 4413 33578 50759 34547 17495 63852 1797 29691 43313 48154 49882 21117 45855 23018 26144 6190 39111 31115 15502 28574 36901 17961 59854 31456 46231 3302 50695 35218 51172 10905 18253 62463 1645 18526 42570 46760 50096 3005 16251 48136 41308 42905 28707 25994 8964 13235 14522 53964 57465 5965 22387 43693 63626 44478 37209 23684 59178 43215 30830 53180 18260 17685 16607 34682 55863 38143 7201 2729 61965 34984 64313 10282 10199 41031 25373 45805 6381 57162 3483 60357 33222 15052 41816 52910 28932 43757 49404 10262 42582 55427 14451 38539 48490 53898 9154 60755 39209 13429 39632 61834 35863 5067 37414 31070 39614 41960 15475 116 35851 8612 18397 1689 22934 2255 38999 35807 22937 38327 39176 42232 373 42788 52014 21752 38257 39030 15313 27521 30149 45218 17219 16699 55809 35262 57900 51451 46255 62571 18149 18725 23130 4453 20752 4348 40857 21998 19115 19255 60530 17343 28838 7645 22006 36468 62705 62966 6943 56107 34688 4946 47349 23675 49161 21247 36961 46189 23510 57902 2062 35296 57647 10083 19268 60820 14388 36734 3772 45428 11057 14099 7649 41432 44759 48822 35169 24128 54211 22197 36258 2462 24190 37630 62495 55534 60517 46116 19872 8870 39962 860 6447 10172 14211 41402 41731 18781 27624 62644 46590 9136 7130 9209 31332 15385 46690 40080 44510 61986 52603 42190 37025 63022 31114 38336 19926 63095 30013 15057 60896 646 35082 9954 25617 53676 47862 62547 47165 26996 8561 13675 7049 61110 34469 49448 3029 40450 44829 30721 53099 11693 13667 64132 37744 6876 58979 28948 29418 54109 64302 34109 55365 25664 36924 37156 563 60537 47546 51915 51069 46487 10928 49471 13224 12577 48590 45077 57551 48063 2894 1224 33817 3488 14743 38879 17941 33821 31150 23905 6475 29290 21939 7165 19451 52147 64226 21822 3149 48982 14701 23683 3905 10708 40868 16659 30073 35071 46398 7641 30365 54077 14699 41484 23013 57241 58026 34853 25111 59511 30367 57483 12889 18896 40958 54023 44438 41280 23723 20545 17796 19721 9842 20292 36006 38422 54287 61382 7280 13096 12192 50243 2654 8798 39986 9828 26845 59170 24637 63667 7373 623 33980 40897 53695 53397 46967 11340 11189 13444 5893 36465 14412 28395 61408 22023 63135 55464 54144 8392 11332 27765 45954 20704 8146 10033 13561 30678 7402 53522 39656 58643 37548 16289 2752 58218 3013 43549 4321 62631 63438 35365 10673 26545 12905 23574 57844 4765 10818 58070 55596 11197 57738 8708 52176 15264 50276 21835 1479 44844 19595 29879 6894 41846 35725 31378 57020 21126 28433 26683 21344 45667 17154 16851 38787 47097 26997 6217 64260 432 25399 31593 38548 9223 58689 16534 34937 47673 54887 49355 20779 11339 3077 58991 54141 24581 14548 5645 61900 22649 56899 57829 60004 2064 44405 3516 33012 2760 60191 33514 17965 21722 7881 42728 61651 26559 38819 20625 55013 8632 39798 11219 44074 22689 10056 27422 53152 45114 63896 22409 25236 59236 38926 63136 9062 20436 42554 34733 5047 29761 7669 49023 54641 47951 17717 38809 39880 18190 10122 34463 672 21972 19784 53333 17952 39105 14128 54254 37148 5808 48316 5479 28142 28004 5145 30610 724 31397 37839 22760 27413 46571 2860 12808 20500 61026 54967 18223 6681 17115 21745 16112 9521 31313 60560 57867 36888 33984 31104 22310 54617 11869 30883 20335 34154 39310 53715 21513 57343 29198 20161 15065 4219 62171 10750 2268 40882 5821 16482 14808 34661 21321 1375 29709 58815 59006 4723 53324 3051 54493 40423 18745 23793 58308 42966 31639 64304 5200 56306 38056 33621 12863 31522 31405 8246 60177 10951 20261 23398 7104 48802 22023 35548 59194 60230 21058 44590 32796 33162 39666 55003 28238 25029 14570 13237 40073 6979 10199 14072 9228 7619 3029 53156 35844 10529 54770 40210 15764 11267 5864 36271 24535 4528 54053 25196 1394 1588 1241 9910 46869 8665 32887 13719 55563 21035 40630 54342 7349 39633 39665 34886 17991 58187 1817 53059 45174 43837 23419 15533 51499 32984 61321 41145 38016 35034 53144 28106 29671 6277 29108 9247 48775 25121 34823 268 42943 52270 14847 37413 35776 17194 60955 35108 50866 16175 4980 21793 10609 15927 16098 58752 33705 5134 56155 43200 47491 14682 50757 58940 63565 56144 30797 14774 61814 6260 5934 34762 49412 59762 39628 25487 34350 12480 28013 47372 43393 50681 4909 16347 54216 24026 63577 11796 54530 53409 58492 48369 64157 24146 48921 10370 53238 62585 6285 34266 41030 39129 61650 43331 40603 33013 17243 13814 21669 21027 29722 40369 21869 22288 58306 48771 52565 56408 62495 26899 33351 37021 54193 23577 51407 6116 32993 64129 43687 19440 22746 54709 47795 33579 19532 28686 20747 55062 23056 40251 57223 3140 44572 58924 14030 18889 10780 60338 61484 49052 7894 6699 53449 32944 33418 19360 19680 30684 38568 40100 62111 15509 23671 52676 33382 62354 15748 12734 29039 10491 14334 48100 1045 61306 43585 56013 35740 40585 45115 43001 20357 38432 40846 47856 6563 128 26555 22238 59549 11208 9939 12800 7946 34410 42330 33297 46225 7234 49761 23904 58685 1471 53649 13373 57537 543 57450 39375 5323 30599 30185 53312 51464 41066 36812 59044 12465 25338 34096 20499 22174 54087 54345 36141 52729 20682 59316 28998 22645 49184 41642 41331 49731 62685 2047 56697 37698 52424 48394 29885 56403 56011 29182 3293 31404 31292 23201 36999 2133 44117 6219 40565 57274 14388 44073 7201 33028 19321 26459 25759 19895 10954 24109 42273 8067 29392 44412 10890 25516 47789 46501 24261 5781 47414 9957 34441 48864 51667 22038 2635 49777 7639 62738 40972 59706 21961 53412 62726 55224 50410 4605 59556 31638 42554 42651 18240 907 16849 39424 21190 47223 43788 36605 18618 18575 11134 22891 56246 53048 44247 41212 40383 29783 5139 57442 7437 36570 6877 19069 14356 25008 1151 743 48618 58350 59945 34722 28034 56535 61669 57811 2775 42188 61532 34008 35212 31578 20887 54076 51510 13272 28719 12973 60074 61361 8784 7145 54004 21680 47594 59475 63301 9612 13602 34527 15446 64356 56939 59269 64061 19741 63894 64361 29278 56005 36463 3115 17072 3830 22346 42995 22428 56727 24119 55815 43216 47644 55228 1722 51938 15080 3089 16697 3354 43196 21229 21804 62386 4207 2498 11337 53443 19549 282 50698 52307 59366 63809 58264 49657 10792 56160 62790 14757 60166 15167 33132 4461 24405 41832 2468 26366 12261 30548 10128 5762 62751 16424 15702 21064 50999 46844 6390 40242 23674 4270 63474 59825 40501 27427 9769 7106 47625 39820 7654 60660 6111 13296 59140 64043 24875 60434 53274 47498 17653 34536 8178 28004 62598 8799 44483 44548 3162 52660 56740 17210 41233 19788 8023 43151 29449 34209 27411 2342 54439 40974 26471 41536 33401 38048 34344 17372 14905 47212 2650 11086 12476 28649 23409 9288 57000 58213 24243 12399 13815 54381 10050 25156 54088 35354 30827 7962 14009 1398 17981 20437 62096 30522 33268 50999 62453 48738 44435 47677 44824 10065 61726 42615 55265 13306 13718 44768 43346 44665 14680 61733 19269 26749 36094 60426 38254 1093 36901 18227 16130 1087 43231 57556 52761 8693 40347 36922 39924 10822 61465 12910 343 43561 14118 16190 58453 64077 36361 61660 7995 13841 4330 12805 4954 30037 49078 19504 43824 34788 11431 20276 32817 49800 15863 47503 35223 5382 37331 63565 32946 58586 39959 40453 25940 35526 21775 3060 27081 11010 16374 43576 47391 45608 33882 47308 42004 7667 28892 60043 7502 63964 12193 7818 30307 35057 36003 59307 62105 51676 36596 50598 55393 23770 43249 7338 59330 21450 54186 31580 57583 58004 18784 7712 18282 1292 21549 45712 13043 29578 57791 50908 43644 37166 1169 16520 15263 721 41862 60585 24300 5038 34856 33851 8209 33845 48864 16700 5394 51280 14437 16599 22451 45894 44271 28149 13459 51682 56168 3632 2658 50523 45822 44984 55370 62192 33247 59326 3653 45592 35138 21887 46585 30460 7325 19368 1535 19013 38054 50782 2391 39669 19734 36219 52378 38710 52776 31519 19786 15862 39918 60958 21302 20437 8106 37511 48185 16608 4601 40010 2001 18650 61588 52951 4509 9161 34183 52649 3940 60572 35689 145 25547 16049 48019 45490 2965 63814 44221 42671 43104 57019 24588 5019 24777 57646 56688 25268 12279 35291 30913 16109 36988 40146 61119 55835 48094 47877 11053 43145 3985 63640 34446 37590 5164 12427 64145 24298 4689 23319 11655 51913 49984 26442 11893 58174 62955 27804 1912 24190 26157 60810 20231 11082 17605 44253 34477 42667 19075 54130 55308 28661 38724 25955 60853 47609 61027 56237 7197 55981 19974 1893 7720 3308 36455 62198 51358 52332 22448 56058 30808 48133 16985 34118 6349 13215 28269 44256 49981 21013 9717 54831 50621 7663 37373 11653 16947 52035 11016 7073 25113 21792 17189 34918 35947 49145 21912 41188 49021 17007 51073 23360 26890 25207 22882 59341 58808 11957 17792 54597 60429 14525 30074 51212 44611 18293 33889 18433 58952 44283 49025 59212 35432 46108 28550 47778 51846 55801 29233 22436 33249 27402 18529 62362 22386 44686 27967 29956 20265 58856 37218 23928 52617 19040 39711 50837 15403 34135 64172 59317 54960 36507 14108 49080 46700 5282 7394 30368 29871 62771 44778 42795 9278 14518 17574 34639 63291 38836 49337 50095 38464 60626 48046 55722 7952 31421 40125 37705 28654 42932 16820 33662 2966 7436 46541 56650 25190 49517 25784 21362 43973 28723 26239 23803 12844 38827 6069 23847 17228 59746 7881 19958 42513 61939 12284 30228 14497 53074 16896 27014 38098 17855 37318 47751 43063 4079 9103 8308 35029 6318 34750 60895 20632 27617 20272 10277 10779 21787 14154 22926 61971 5837 51002 11298 48047 5921 27035 38363 15237 30938 7498 24678 21082 31315 57995 47321 34848 23396 74 31331 24781 35996 10497 47857 17064 38987 58345 38714 59536 46702 41693 32979 12965 4044 35506 30627 54903 49341 6107 35813 297 39655 5 50490 2370 38567 34312 41739 11204 47467 366 63016 335 56981 57738 34122 29474 2873 60085 31278 31492 33182 13350 63434 5829 62411 18612 57067 26889 22213 4573 26828 9931 33689 59351 734 10635 23324 61488 48169 18365 57570 16353 17561 14233 27048 4744 546 21330 49853 57515 57789 35330 63309 46109 58792 45899 24571 63053 37918 13490 11072 19338 41234 61320 35618 30901 17371 56343 29577 23885 22527 4962 41379 42820 47681 26865 17216 59653 56785 6197 39030 43762 243 23797 59848 59278 47595 2233 24578 11217 37797 12872 2659 5747 59888 62166 48362 51038 53927 24514 7138 14548 50275 19256 55478 56882 25499 5388 26807 35748 58838 12966 53371 14457 57630 52059 11699 9936 49752 7052 53256 4523 19993 4136 23912 47199 1935 37165 11194 15747 60703 17396 35113 43428 9856 43210 61302 39721 45674 46459 13606 32882 35302 16625 64106 11992 15053 30687 30236 29146 45016 54657 22123 50167 19794 19688 22938 38740 16093 4148 8056 36871 49100 17291 4191 60030 14681 25065 55420 14080 51859 62626 35284 37356 23358 27231 25456 56791 30200 28576 25036 52577 61374 7094 21110 7071 28157 17039 63313 20917 25522 29691 4049 62220 21756 14788 50745 6836 16255 29624 30516 53707 14552 37150 22196 11517 54393 7979 58871 54933 33576 14375 18338 48052 60006 24453 46265 25867 30980 52224 15316 15186 52906 43616 34545 52900 37970 16931 7717 21732 53531 21250 12626 41057 34853 48894 6492 45914 33152 61091 36072 27495 35955 50850 13112 12765 43177 54194 52854 4508 45992 46968 25585 17760 41208 53345 9596 36970 28271 54045 30196 38754 39897 20877 7227 44548 33481 16048 17228 52121 42256 20350 49660 52627 1025 4094 41686 39562 43274 35316 59288 36201 58586 38592 3246 15314 49313 45986 22668 37590 15331 38998 35300 6204 12714 24733 40567 45322 53399 46200 4182 17911 22112 4628 4495 19002 61017 25554 18573 18267 39506 7955 61742 29570 35656 60193 25320 52974 45235 6320 59439 40912 59823 13256 8046 55589 36791 18669 7887 31582 27494 20471 62580 23315 11080 35759 31067 44548 11675 32874 57944 39442 50474 29710 2218 13360 18957 1701 24425 21643 56283 25986 45902 46956 44140 3310 30887 60331 21213 24445 63769 36039 9154 29266 47798 35212 62359 56208 8222 50742 13047 1861 35909 22086 10555 47967 30585 17587 44611 3446 208 21070 59874 19969 5677 10398 25023 11330 25566 38478 46055 18053 24777 30606 63237 20184 9600 37214 16165 55250 1619 28865 64305 13523 41930 36999 54816 62126 29 36810 17443 24080 5164 17786 55239 3171121942 1284262346 +1024 54007 45481 3454 19153 6425 10879 54664 42851 22975 5345 10669 18641 18377 59092 14415 3920 42936 51694 33842 59595 13229 11551 58777 64119 48948 19819 12746 43787 9506 42580 49340 14568 11918 51219 45958 10298 48073 45413 59671 4997 47399 57195 43406 48222 54917 47511 44508 33399 28633 16579 28897 16196 56695 14632 46868 32948 64018 5933 11316 64493 30105 63544 4530 56381 18364 27058 45896 34286 32786 51077 23000 31506 28566 37704 51023 50998 13883 50768 38954 27332 58648 36750 28104 9635 53488 27642 30279 5805 61331 41409 14333 28646 12650 6079 61485 27613 46947 44230 3715 5256 29118 31208 49350 60757 23177 26165 44370 6064 3238 55635 6280 19037 60685 48010 53616 12747 38620 19742 49248 40914 33371 38325 36895 836 42230 49078 18133 9369 12336 43285 33266 7858 51016 43957 3547 38944 60005 36235 55148 49027 21012 30501 19334 53312 34072 22537 6579 6321 63954 24346 11600 53740 52230 50473 36988 64003 27823 7143 55824 28709 38534 33496 62545 25860 5798 51153 29746 13727 5628 10218 24501 26940 62367 24659 47736 39956 52851 23654 5069 38762 15284 20083 38141 38422 4922 900 52418 51099 55487 17240 29715 26658 30215 33869 53236 57046 59705 43481 29149 5415 55664 4779 51734 48514 19386 28890 11911 34609 27447 43048 16585 19410 19084 10389 27596 42477 21047 20166 9039 608 15437 15514 2961 10090 25269 21894 57660 16828 7509 49075 60016 46706 29090 43698 37038 5767 29429 14780 61320 2494 9162 1501 27898 57160 20987 25828 22343 26674 46639 28858 15792 35103 42550 56723 50308 20866 22211 20965 5192 25811 34750 56375 28256 22306 12333 49671 15274 31542 4178 34596 14792 62458 46150 12648 14594 36330 30277 16851 36720 4897 59801 20475 63538 16973 14009 56151 41786 50472 18322 31485 21551 1154 45026 1899 338 17369 53146 53783 38353 18231 33358 41602 11205 3084 23700 37413 63132 16325 26979 58010 53196 43275 52744 59627 28517 24262 44732 33127 5403 63545 57803 57507 43801 46344 48787 41360 43401 34106 53754 8473 62845 60696 11553 29228 44121 33862 17876 63021 44394 47204 30370 56513 53545 6107 35958 58128 874 54483 13715 35075 19909 61922 63508 36239 61451 48191 8690 49121 49502 22082 54160 54392 37283 53716 2993 11761 15876 9100 2039 30372 63651 51464 18032 6337 16483 24427 11220 39185 30467 55271 4910 10740 39504 8298 62236 9617 36772 24189 18888 2226 36388 22299 41122 60320 30851 8845 21046 56050 20762 55460 60553 6103 60445 35416 7933 43555 14793 19148 61384 1770 47720 14586 62121 4758 39562 24853 14166 52359 62477 29760 29979 11233 38735 61233 22656 10149 53061 14604 3535 15401 31505 5380 57996 22876 38691 16856 32833 33792 59081 61703 2441 60533 11363 44550 48562 29022 63478 10660 43567 59108 24758 20966 6552 11651 36096 51497 25427 42302 5513 60555 19582 14656 62750 48846 11011 51370 3081 38026 64092 26768 21615 32800 16025 29274 28563 45991 62096 13738 53210 41954 3080 47819 26379 62832 19543 1698 45135 14050 30745 36716 61440 4836 30168 24317 55326 34021 39334 63842 848 22206 42573 30775 19762 17636 19792 9998 37650 2829 54275 26868 25556 3340 47621 42671 46802 49859 55376 54952 49026 48157 13377 57072 56249 39017 5986 63784 60262 18208 33650 53157 12861 1401 60782 51554 27989 18478 59293 44342 19340 59623 16270 39701 13017 38542 36038 13659 12857 23221 30162 17177 20574 42433 45666 4735 39717 24282 64335 49887 50373 48833 8315 56573 29986 24859 47648 7802 16775 40243 26308 1938 57697 13927 39365 15073 53207 48512 22197 30718 54209 31452 15958 29877 54981 23858 50362 49267 23201 8549 8491 10668 23522 40239 41364 21450 37402 51913 62929 641 16915 64393 60592 12407 14871 30283 62399 53296 47015 57366 27466 42607 53909 34484 3091 54507 53254 20039 35279 49780 29490 54137 58286 17472 27401 31323 9756 22841 46497 54931 102 42087 6182 49046 517 47995 29565 82 35304 63543 23873 38476 33060 59764 2672 8747 48177 61374 2173 28405 49443 38409 61550 22299 43039 64506 14073 36291 26424 22807 42552 60820 9414 63923 19264 31739 17059 57613 41180 41804 12670 46206 58715 30121 60076 24071 50450 39206 59914 60459 7800 39144 37335 26541 21878 24350 17579 7544 29142 30184 26769 55399 38498 25388 27444 15477 53588 52504 56090 43621 47759 31116 20397 4889 48560 53952 4805 52482 6658 20448 31451 51437 37732 5646 19531 18358 14944 62601 25451 44700 4592 37153 47130 13532 26164 50952 53198 21322 20711 36320 37924 31023 58422 8371 51329 41760 3951 34717 40769 25964 2102 49393 46940 17679 27273 40442 14759 49847 24741 37153 57296 40372 59694 50844 11647 12131 41641 13011 36815 6903 48360 4561 59285 64399 24362 44137 34181 29769 18489 27304 42494 39192 57753 19755 48173 53381 16214 1478 58038 4981 48951 30163 11826 51801 36423 61600 20462 27760 12787 11667 13922 12162 48519 50857 62086 27672 46517 46599 13371 46856 14298 49857 44435 24890 60871 39631 38242 43195 28734 58499 13607 5714 61441 8490 42564 45588 61041 50228 41290 45460 37643 63070 14128 5180 55077 22501 8558 18980 18148 40839 16359 15850 33071 34952 42902 5097 33153 55983 46059 14241 4412 6170 6464 6733 24022 3253 63411 18114 50034 23236 5881 1326 59124 4418 48652 37708 14291 8327 52340 60177 50869 4268 19587 64109 11945 16861 47107 29521 27841 29890 23437 5554 9642 52803 26486 5549 25444 26435 47296 5368 7094 10467 48217 24031 47469 21926 59880 51179 18021 59621 37916 4189 61461 22148 23394 51013 28029 62475 12685 31372 23416 30187 51954 4405 2501 22007 49174 47733 23687 48029 12275 42392 41587 62693 28837 12748 38950 42919 1225 3864 12318 19144 12166 53259 24801 14554 36013 4203 62721 53826 55593 2187 29303 44314 18495 30253 16021 59361 28434 59613 26338 60703 32886 21744 57499 14961 39398 43271 38519 22510 36659 48698 48798 219 62010 21419 10831 22864 38311 21475 26637 13300 24633 26952 18593 533 63683 1506 9387 59464 760 12933 18555 15033 37222 22792 33146 14756 63624 50252 24420 3269 15646 37671 20113 4681 40145 51107 36629 12 54963 7034 14403 64066 27614 17471 13872 51343 8981 52919 62725 45434 12304 63320 36947 32999 34620 19710 62107 46570 87 46921 5649 57360 59375 53467 56862 4849 37632 16893 21394 63732 41439 37781 21350 44328 44342 21267 51613 36398 19027 57420 53113 34424 64439 5555 20155 9260 22412 56856 8363 30914 30753 14072 4933 38535 46864 51095 6724 16313 47464 1672 52823 55672 56414 25188 54642 35702 35105 62354 46750 13922 45863 3766 8666 9571 42287 7193 13087 16248 60014 52501 21202 7371 50175 34956 45271 28869 41262 36659 26903 28020 59916 55911 57630 56897 13148 7476 58389 44170 36838 37243 36733 53034 60528 49450 45993 795 13930 48912 64032 49380 4914 37885 777 60769 46110 36858 56217 54219 28009 31354 18200 29650 3564 56642 38399 44815 58657 56689 33954 27256 27686 62548 33632 40185 18928 41745 11339 14518 24059 3078 40906 38693 39531 29771 46864 57514 10652 10795 60007 6866 27958 64082 21894 46321 44401 11244 43940 34201 45556 19595 14837 55598 63186 27994 59542 63632 17108 47912 55332 57400 6568 35800 283 5547 41917 11141 1726 64375 6961 46664 19955 8643 19600 60286 3061 48649 30341 20394 6310 18429 61575 27082 24696 2998 24571 18173 35060 57519 23532 41229 48972 55687 39224 12846 14846 53757 50544 32976 34309 61136 12351 61466 15283 25424 13893 14254 15433 1065 10950 13832 45306 18566 51705 4114 40833 14347 18095 48054 58825 51485 12034 55522 994 10312 8875 19926 46911 37648 14556 6344 50133 12855 45062 50440 629 24699 15056 33819 35615 35552 17120 28419 57411 57787 33147 56057 5799 60488 15957 54269 63936 13068 31211 33210 12417 26385 57641 19129 54833 26693 27246 30180 60201 18214 5564 17106 52917 56875 31151 34647 44353 58144 10449 21225 47209 59379 19784 3860 12819 20297 10961 52398 13043 51089 28609 4575 45447 47314 8022 63307 38577 36565 24686 54794 12290 61968 58889 55729 12377 42565 61259 5996 47859 63929 53725 4730 37477 2088 39183 33981 9601 40981 62326 41188 9796 28863 35405 52184 45452 3351 38904 29448 62193 38503 50522 45989 7404 63382 39194 59897 6073 50271 53515 10694 30488 56402 28445 28814 18359 55159 28511 30797 10831 17345 5637 14657 12253 29701 24817 2660 28673 36356 58385 27626 60482 24746 37223 47184 14516 15179 62935 43683 47150 22528 63297 4165 10107 49033 18697 45918 50058 16132 16344 58123 7904 35026 63515 38609 63236 58724 50349 12803 61237 60121 3934 12040 47455 60351 34649 26934 31694 52745 33828 51350 21662 6851 61398 29615 62974 23951 18438 197 33495 46276 6982 61656 43223 50560 47869 8233 51413 53246 60486 32821 58969 5241 8752 1124 51522 23296 60902 52508 27392 58438 195 50332 58633 2305 3740 52385 44399 43924 49041 44510 7822 26945 4060 60163 62065 4643 36984 6429 471 39122 23279 1676 52797 56796 33508 61643 28934 3393 45624 60991 15341 14299 35391 10785 2617 3196 28540 61540 691 29504 24140 44576 49366 19361 57460 2257 37702 7075 63611 11431 14761 46998 36282 64493 42087 28809 57651 5029 36372 55271 5256 9217 50767 52559 17293 16458 46429 19691 62508 17355 52123 11282 36825 54784 64097 42327 19063 22690 62637 51451 14266 19663 60340 24192 54674 50085 51973 43103 47233 9618 21466 41931 36452 3968 3999 39392 63846 55495 35750 34501 1240 52449 49761 47591 24391 60054 52518 11842 37111 4809 21477 27362 35624 13931 27946 20040 43495 39086 53268 34778 39959 30980 36824 14409 40927 4700 36005 55766 53609 42257 50925 2665 27547 33158 48371 2680 60593 18307 4080 44900 20382 62880 30136 24114 13126 49551 52791 36190 31055 27738 2197 41355 23220 41886 20716 23078 805 33313 27217 23609 45801 6034 34696 36264 40259 14330 18695 39277 43737 34881 7303 8056 62570 59738 52412 41557 14821 1661 33988 47853 17127 31256 30933 20851 20587 9933 22460 63799 8826 56755 17512 48702 8128 23898 34938 49257 44381 54755 5320 57997 41182 40025 995 52898 20441 36939 18678 25725 29032 33648 25586 6763 47281 20723 25356 34013 27802 23536 19501 25621 9402 5152 4342 44493 18177 8580 44150 59581 54308 62743 42467 61886 39870 9684 20141 45819 62977 63750 5734 18776 60487 17394 5868 40480 54871 40300 60104 41536 39348 23272 15615 53989 5744 22836 2513 4528 549 171 38117 55953 51583 4881 52048 45632 47143 61456 26017 27558 54530 39530 32984 43795 57727 4774 60628 12904 53608 18786 18045 4173 34181 33141 21641 53074 55278 12683 45610 9062 51779 20957 14369 33594 24259 49048 34990 1332 17157 37486 41047 52177 46012 31600 59377 38149 10016 50024 35870 60276 19947 44516 3877 52566 2901 56995 46910 12418 9293 63451 52171 38788 21866 27658 54972 63986 19172 20187 21268 23006 3785 37453 35466 45275 554 13802 44586 30687 57604 23041 52981 63905 10062 24506 42964 7139 8771 29278 20655 54222 2164 54541 10841 57381 20406 34112 29699 19533 42649 25212 25081 41971 6119 62588 338 44125 11443 15245 37993 5115 47731 44300 24486 25919 8285 59084 5783 7114 62479 16946 58931 16125 59990 42278 37851 48258 41052 13626 47910 59180 37135 45457 49305 5654 37952 61040 22661 11206 14363 1347 25797 21591 52766 16387 31497 34035 10880 14768 53058 16868 19709 16398 11149 53307 39741 56218 19949 7812 30553 59381 25295 59644 53137 1553 36963 12082 15163 57831 47086 23479 47067 11514 4096 11442 10462 41251 18003 40440 2533 2863 4212 18609 2182 5854 6348 48330 22376 523 44325 60695 41691 32777 51553 34409 29845 28548 31120 43226 13038 19233 22736 32838 12182 40007 50160 51537 30178 1007 35401 60786 49333 48574 20729 45466 21592 51545 63792 58490 36799 15506 51418 63510 45440 36091 47382 33547 31150 222 18966 3591 24447 41879 49379 51567 53431 10824 6707 63347 62813 346 40719 39978 36935 5302 43043 29613 21167 38942 41729 39131 55760 15453 15971 33955 62348 49842 62162 28489 49396 17081 11949 34538 3416 21413 53610 42197 10042 38926 46963 50524 3734 5583 34233 63241 27167 54203 64338 12615 18646 2576 36546 48123 44914 42825 12015 60124 35155 46523 35125 25037 53943 60263 57998 7824 3926 13572 26790 20153 23552 55945 58593 598 62180 36510 377 62460 21382 8089 23185 12813 7198 2224 33944 27733 62285 12355 40910 47065 30389 17405 54582 16352 58571 561 22536 9349 34826 53759 39591 52501 45796 41383 3706 18977 24973 43027 51529 31660 40283 37581 27952 30680 4565 59583 64159 43581 26540 7433 5448 22819 53934 49827 11503 7348 27812 53175 41050 11788 55191 4246 20622 17279 45133 46775 54098 36557 0 1334586459 +1024 30925 19598 11456 12469 54 8941 64206 23177 55753 61291 60379 49190 18781 15827 64493 133 16059 54000 53413 41510 24420 3266 23590 13046 54852 59660 52884 11426 20791 38828 10235 54069 61616 59646 59691 4387 4422 26661 63719 2539 8975 13375 12686 48839 55648 6951 36033 31134 35309 21521 22147 31218 11076 37677 46033 24495 24569 316 30579 31305 1564 18304 50911 12068 49248 21253 45189 40509 52812 43094 46253 15995 39291 24867 26336 6895 27001 59529 23324 64045 54185 17647 29642 54958 20596 30491 43799 1470 58311 33173 22671 2457 7453 53176 51958 9597 49055 54787 63571 16588 10790 22819 38300 20823 45013 40993 15898 57883 2432 28081 59266 22838 9562 1539 15077 46922 13702 62437 3035 21603 37131 38866 33278 18055 26516 36677 18233 35466 34275 57140 62271 22555 6397 62397 10667 7118 18727 2664 10649 11121 42026 6439 55708 3650 38507 5206 53852 47379 1519 29852 22068 57741 39144 51022 1209 6991 34367 25499 55112 1546 33133 11542 4078 10492 47660 22009 46273 15048 5879 41400 25211 62288 8092 39064 49005 13470 63255 45772 60343 17077 33434 42220 37811 61770 49552 11457 30270 53481 57351 10820 63128 19776 20772 31028 53118 30594 8165 53123 42722 8022 22823 16933 4871 31564 4603 19401 61421 29607 57562 11068 11887 39791 58333 39297 44970 43883 47002 9006 53635 41930 16820 25893 62688 9955 10284 62023 27321 55068 1207 60309 53913 47623 6651 5015 6848 27344 29647 41324 9688 11858 41274 64353 3173 61567 56890 58984 40061 25435 1116 22316 28378 45165 2659 28387 60311 29968 40985 59610 58089 20436 9228 4244 33557 2962 15694 62425 58959 1890 42888 30743 28329 38808 63226 60399 34742 41610 31444 13166 25581 50713 17244 27977 4025 63739 27659 9032 54566 36542 14725 25461 23191 37870 19176 21064 2099 21771 49853 2256 26414 36224 48816 38719 27143 36181 27386 60815 35483 41639 34504 57993 38600 45302 8294 62965 61599 59013 10679 35173 6463 24477 2018 29734 37830 40261 48634 24073 3679 59821 25676 4450 12725 17050 6266 2452 8820 48676 50673 44443 38277 25670 18077 31532 59232 56474 44065 33089 19719 9979 45391 46387 59084 64121 6206 24190 7498 50573 47155 47373 5328 34636 47214 56391 3006 64417 14299 36587 24540 26895 17278 41675 62427 40076 50778 13264 33445 60843 14047 62361 40310 10454 44633 33524 17718 52531 29885 15883 27695 7656 27633 55712 63858 45413 17949 47521 7741 16693 29143 25566 60611 3590 61828 37550 21478 34613 61337 27347 62793 12080 16373 34109 54847 61091 45874 58488 56210 41499 8825 40622 14171 38132 35123 45660 17743 39827 15919 16066 16780 51977 59186 17860 41115 27496 62730 7932 49928 3041 12852 22387 60700 11212 10269 33779 50434 44381 11407 13681 58773 50460 58026 49117 50440 15930 27671 52884 33965 30947 35595 922 3111 45399 54968 37242 20929 7845 15902 38491 52081 43902 39502 44082 37750 11446 1770 24204 26233 42389 57781 24957 63464 26250 55006 34737 43428 34051 14057 20054 35046 2428 62116 12032 27938 56316 38182 32951 22869 54598 16670 29314 39437 24680 39394 50575 36437 39894 13279 15218 25372 6588 34661 45772 35498 30816 55811 50643 58979 62090 3030 28131 660 45892 52249 43690 49709 21120 64350 62893 41641 60197 27680 59117 1815 4064 63467 61827 6074 43276 18951 36178 46850 8981 15067 34725 21588 1067 30813 39180 62538 4656 30282 23977 1311 5520 56326 52956 4512 27672 17116 33604 6319 8513 1991 19557 15277 21980 25091 9582 3140 26736 58769 63494 11488 30081 32930 54073 23411 26349 18193 28377 30071 51319 59275 62662 63069 7606 33968 15973 5321 27605 62367 22792 14596 55760 37331 58083 37500 33705 12721 34592 40840 2301 9641 60002 39675 64262 28179 18855 827 44172 36559 47499 34753 35407 62424 29425 46247 27829 16687 50802 38475 56202 19803 48574 47494 8053 50835 21812 38396 12396 44250 38451 34038 44382 20862 14425 53711 32789 51955 25531 10542 12943 26985 7575 16685 30174 38305 59207 48862 12018 59333 11862 39733 4463 13076 2724 50699 34734 13411 47906 36007 24977 16785 36533 57721 62460 37654 1981 9605 936 62718 3801 12390 56907 39262 45027 56223 19229 20594 38260 58096 15558 7524 42227 4845 50200 7240 17067 42790 10934 62423 19876 51396 27694 61378 56398 9378 62034 234 61738 59908 8544 50969 26352 10002 64241 27629 36323 7288 34934 35972 37296 20523 8108 53658 62323 2313 48121 56339 14092 47442 20883 11944 37123 12444 40908 17630 52565 63513 56245 54931 1605 49078 35278 12415 15191 63625 17473 54547 50134 35372 39841 55872 20321 6817 56115 30590 47660 49372 61711 19228 54267 28040 63860 39307 32898 33068 48850 21606 53886 57562 35711 45352 35064 22175 58005 22997 27886 30883 17659 43862 51684 42453 33790 18020 26231 33679 39921 24280 7319 36597 22186 4056 31532 46328 28618 46695 24030 6425 34126 18410 43107 54869 22826 11589 15239 13066 57531 8133 51120 28078 20139 36143 49817 3822 24216 26319 40921 60491 35027 57279 3966 27698 22824 34740 7073 25769 45908 63133 5965 20849 63733 39482 48678 41956 50028 34308 30442 42781 23890 54909 52028 27827 28418 39761 55547 58972 15705 51092 41452 34342 39906 59942 4743 6732 3165 1420 15724 30421 6381 37681 30164 38251 45822 5272 53537 45678 50283 53978 26362 33769 30913 5051 35437 48768 17258 44485 37377 38252 14333 24137 49999 38720 55914 22575 14535 2308 43621 50067 40930 63288 24922 34570 7647 15861 49452 21721 50413 54163 64224 14467 59756 41471 51998 12845 60716 14733 6939 54344 60043 6669 52927 5901 40580 28901 56421 57717 11128 55638 11313 4802 51373 39411 22646 21904 28568 34005 11813 43503 35581 14217 45215 54505 62814 6045 49540 34489 7395 50479 57562 36776 40737 11405 24599 29609 39632 24075 15895 38618 23000 35890 33791 52653 34080 54801 50754 34303 33820 7982 47890 38833 25651 8090 38207 55067 5408 17315 57320 50585 20648 3565 14509 44393 45252 29834 4867 16721 3442 20830 19118 22882 31740 26198 22023 25036 15820 42013 63601 39876 21722 25553 8336 57252 5688 51021 22015 58298 24132 62642 63660 3100 45768 11751 33303 38412 23121 251 61454 61018 28564 47414 26722 4611 44916 5667 36883 26291 29091 33867 27499 53209 26029 3306 61119 38766 49277 7850 16941 47016 4850 38681 8682 9937 38178 51121 20424 5115 7489 25259 51501 17863 13005 17551 8698 1103 25163 11496 56563 33298 59775 48282 6609 57365 50380 15283 29802 24861 2402 48326 52930 62587 62 24114 38310 17607 15977 40348 54995 52183 13454 28167 43186 9771 27217 12829 23136 37008 35294 28490 42764 27176 58806 39913 40102 9795 18316 29685 11743 36616 15716 57302 7126 34709 25288 33965 8993 51915 7262 51643 19431 40616 27266 25837 63496 54646 28929 10625 30535 23651 4869 64373 27335 64119 3876 13419 37564 23438 50047 43950 23992 61637 30317 45048 29583 3964 34795 47869 7641 950 23196 59378 30808 44612 55262 1218 56140 5320 34210 8821 21176 14744 43937 40598 14692 9179 40871 34143 57272 37399 23776 35793 56596 33734 21296 39567 40808 26888 37347 58124 63270 18153 50452 53989 2440 48560 24599 47175 61890 21588 24982 33284 7763 43793 45309 56843 58758 11760 64083 23181 57780 53352 23141 46356 54804 21125 23726 54106 30073 7971 51675 14747 60191 44506 14758 16339 6901 41074 53184 22754 46125 26308 43555 44001 5066 12331 9407 50006 5533 10650 45817 54226 848 4778 40021 32806 59120 2621 2067 60627 31447 43588 29885 18374 7024 45539 13759 35735 56732 29641 647 1974 47075 34598 61728 52806 62364 54878 48494 23720 14902 35636 8246 60176 23319 55295 2060 25483 43139 27028 9832 20729 1145 9049 27263 53233 46362 15982 45612 27706 17561 52741 42378 6419 42002 52144 40261 45719 53380 26625 37994 29994 24672 33884 26086 45034 62968 50331 17579 43938 43109 59363 466 37666 57137 13251 26775 13722 39100 33785 17774 51856 61512 25478 25000 31441 54393 62973 2828 30327 41973 22451 492 50726 35047 51973 45193 14992 41764 63037 25446 39998 30115 18579 16731 30533 37973 35011 5445 48341 23915 554 48795 58123 21374 23933 28759 11112 6150 34553 13528 61041 22990 36307 63737 18979 50658 37048 50618 31240 35930 62193 51140 3058 27105 48851 53397 23665 11146 47920 17675 21763 33449 18550 61446 14138 1433 22169 15467 43606 10650 57896 43782 50986 61317 56458 62717 14067 21423 40297 13626 39159 14858 22700 1243 25668 44645 54884 6672 3135 21281 29879 25248 27172 21932 33856 4087 47739 36387 13622 55015 13468 18069 16223 14702 34556 16806 37111 54964 23219 5372 34754 22670 24986 52045 9185 44504 49122 1243 14038 30121 60090 46050 53157 44482 41319 11893 2428 57681 26735 58412 29171 27760 43201 30644 7892 45520 1615 23917 11164 63159 12642 46238 4830 38899 47120 39748 64182 56843 45050 50450 50387 13627 39807 40096 20860 47444 5462 58902 26730 2088 4848 18651 18057 11740 4066 9161 46474 36080 24483 8067 17516 31732 54667 2705 28900 54496 14712 31652 22673 50418 14334 56261 49458 47734 6370 47732 236 15664 24403 26265 2910 46315 24382 13215 26349 40089 61304 17253 26403 56279 31098 56172 60134 63543 26567 56467 28426 58443 33855 35730 46211 60382 10816 39334 38496 22653 41032 28110 13429 38664 6375 17080 55227 61109 8553 48486 10529 40988 17788 26966 15507 1716 3078 5411 58263 41406 64394 36215 40806 7741 36636 40132 34048 2294 45889 35912 46037 53006 64119 54467 54922 16195 18560 55702 15800 53111 11438 51092 39759 64214 6597 26764 37964 24662 62253 25918 38579 6595 40153 46702 344 16548 53796 41256 57203 37966 57367 47488 52352 36599 10625 53162 34139 25728 23041 5979 36969 4871 33837 22243 12982 10085 41996 14023 49147 63987 30515 40098 2279 61294 19028 62115 40540 51564 45572 27263 8540 33030 64012 56033 33243 46700 17310 63431 14850 62101 33585 49458 8202 52023 55206 52136 127 19618 45775 56076 38590 53337 5932 57063 52792 3557 20308 15649 27492 48440 4653 56254 24043 20947 24569 44971 53420 55046 28356 5283 46536 42024 20648 51189 918 34094 51962 8652 58959 18840 39639 26187 2609 51073 21666 20008 26410 30351 3028 40555 8594 52593 11371 29595 18518 8884 52791 61311 27864 3112 14651 64236 19971 16502 42238 33593 63824 692 63586 40538 12510 9207 11406 33431 58878 41961 24836 28485 40101 12269 45874 59893 11975 55620 38143 40651 17200 25007 63389 29971 12216 12879 64030 44528 46036 48005 7416 9541 18166 60106 48125 21796 31090 50037 659 4981 61228 29406 53255 62623 60181 31592 10891 45597 50484 38573 28842 55429 25598 34982 55101 53870 28620 15614 10012 60539 47626 52954 10066 23192 10769 44877 3682 30052 16497 14322 61970 38185 39788 21014 53953 8275 56755 13128 30388 11110 12318 13551 27215 47342 27801 34092 11721 4056 1799 23142 3248 14346 1163 22007 23560 28657 24035 14316 46946 46133 38726 45632 14608 44081 4928 14435 26893 14681 56917 24604 51483 33394 62515 43239 61087 32920 29430 52620 30028 27702 3575 55028 51570 60424 59184 33051 51893 128 38003 16881 52383 40658 23247 63182 54673 16130 7118 46118 59143 44922 37093 11070 20255 19363 64207 501 48464 24872 56935 13714 8064 44506 7849 11911 29196 35529 29015 59988 8780 4667 17163 62289 49973 38102 40993 2652 49264 27181 35597 10937 36461 11987 28589 27114 60814 8874 6753 35149 35554 48639 60296 50686 51522 40006 36322 56758 6142 37724 53800 61450 56875 3237 42134 52803 45136 31241 26930 61445 58775 3403 28431 36343 59427 9076 47369 18325 8951 6772 9553 13525 55075 7200 44393 11335 20580 59938 49478 60337 58938 20082 26410 43871 31365 24048 35518 22435 45876 7792 50982 57004 42277 11629 30640 9066 11632 36621 3705 57606 47554 26316 49554 20113 38360 2635 8823 23917 14228 42855 11607 48295 62718 51755 43949 11600 19437 15143 50675 7310 43644 24023 14926 54494 35938 55702 42588 27084 22312 22750 5414 38450 58888 25257 62310 1305 37511 25610 56963 57472 16427 9010 53120 29017 48070 48438 58305 51616 60504 29414 52434 8029 16282 59082 42173 42475 7543 40255 11758 49225 42578 9683 45454 48279 36766 1252 31050 8246 5856 21584 11331 2462 56519 6768 60086 46312 36154 7104 41059 60789 28071 52450 27950 51244 22957 61931 26775 23728 11309 19833 36523 17216 46359 56268 20019 20855 26561 58987 11947 58224 52050 53164 50998 52335 49243 10507 34248 34601 52804 4293 38677 31262 8030 12218 52840 14710 13229 23842 21300 48117 15801 56149 53483 31296 53412 738 4482 4185 61286 58013 6551 39224 63953 25669 21726 20069 36386 35898 48374 37566 25109 45293 61057 42341 18275 4307 22025 8344 16952 36771 0 1312916838 +1024 21039 26876 61170 60355 57289 34522 39588 13327 37724 23777 20620 9306 26234 55484 10962 35920 61731 4149 25636 50648 44043 60869 22063 55083 11856 42962 32859 37583 7329 40394 53071 51667 24807 17745 23 76 7155 48103 22733 18977 38643 3451 16087 12665 33923 50193 25854 5370 41109 16605 2904 40271 41829 57142 13170 1331 61325 60684 23824 27077 33448 48834 34159 54086 3514 24714 45881 41269 50931 35059 17037 20905 19028 57163 33668 22579 44198 15673 6763 2 55283 51998 28100 60324 40846 6137 5385 1707 7082 6047 21806 30228 55780 49385 17780 981 25675 499 37409 58821 39368 18483 57412 18483 18001 60523 22793 44592 35542 52049 40106 13187 9956 39721 40902 37988 47233 36170 16365 718 40491 46029 1891 29211 41850 10714 29786 5338 40729 59007 16097 8414 13744 31081 24808 11327 301 53130 47466 44406 60311 7865 27913 37467 12170 48702 28502 48771 57256 28199 46491 17973 60438 36545 55044 45881 43369 6789 28664 58477 16652 60463 44677 49577 11967 54714 5309 2695 50864 20704 16588 5184 53434 17546 30534 17263 54578 191 41507 2502 64398 63595 51805 62465 58331 27579 17404 62801 38740 56106 27194 31214 22368 11484 29937 42652 177 8081 40420 53172 25907 2751 26790 32861 34667 63403 17174 63715 17620 14964 52633 18764 55859 21187 34585 34502 24337 2437 22354 46576 61455 49653 8264 48988 61272 11117 7449 43328 1655 42253 40185 17752 57289 51165 4177 19717 24943 26579 63996 32891 15220 24449 31486 25818 225 35914 1195 55764 7956 58603 42046 28521 58443 24228 1481 55619 61223 62462 21638 45880 28161 11050 17933 48229 37132 2911 27398 48388 25744 50288 62110 23552 24580 26152 61023 41574 9448 4939 63735 60117 34682 45583 20330 20296 54696 5724 32872 47656 21278 42610 29367 33922 48458 6339 35895 15125 29019 27250 11285 27832 60417 33106 17782 19173 58782 27537 58430 63795 27864 27408 62520 57129 7236 42547 19404 37156 21726 10622 51098 1754 10621 33251 10075 6788 18875 34045 63443 36284 63278 49090 57057 46675 61991 53504 64354 23896 44437 13591 38344 35743 56457 29638 28608 62817 25588 61639 12293 27690 9127 36018 2050 35332 52872 7579 49851 33201 37574 21349 51756 2887 39376 12290 55590 3095 18320 26249 490 6316 29938 18941 17186 29669 38308 15581 14770 13273 1064 47743 36484 36540 23208 46733 214 15681 13053 57982 52468 61679 50638 55595 55375 39101 32774 43333 50938 56654 38536 40759 15158 23214 34136 48809 56519 44556 4460 53284 57808 43657 13696 50918 58321 60280 18130 13284 42628 52885 53829 38011 61375 3635 26931 36195 41056 62179 43119 35464 25424 25467 42355 16814 37406 15737 2446 27530 20833 9232 35641 36017 27237 18263 59122 8851 54519 58118 35700 12732 22273 24128 26158 25527 57105 9878 30640 12622 23246 55200 52345 63867 8165 26601 61336 46616 3333 26100 16919 5382 51638 43426 47898 37006 63938 21561 31237 3307 6017 34446 4254 44620 40274 58781 27708 16481 23994 57432 9705 56345 33134 53243 30197 44269 11919 14519 55 26675 58977 16476 2775 19749 10214 27455 20351 55714 30980 810 16273 41988 60888 62978 20084 43883 41166 46450 58288 47112 37533 15849 39036 23710 3656 24518 30126 8149 29049 12047 43425 53361 54892 45414 59920 61823 9532 31599 5922 58237 21660 25149 25121 49603 28198 20460 23783 19371 60724 60654 31476 19422 28227 59459 61705 19449 419 50219 30041 2796 55540 13003 8986 17311 47980 41772 8009 15548 41553 35730 54532 22830 54569 39493 42400 31501 10886 17609 64205 12643 40225 23492 11240 62453 38337 31228 28882 18235 57474 47205 26349 40377 56412 45481 46559 25819 14725 51440 59411 19366 29883 52693 56620 42907 25335 25220 29074 17465 63247 28244 43837 39760 30613 61620 1591 36062 5175 38327 23897 22925 53203 40901 25693 44377 20535 38233 25073 26645 13226 17998 22309 39585 30870 19939 14000 12033 51714 6305 39049 13823 1662 48964 20114 1988 4608 16740 45084 32768 27808 46418 17144 773 16212 30185 41196 63472 10146 1988 55373 40761 30623 23143 58668 64347 3771 9923 2239 52833 3234 21389 47389 55992 4912 59271 43389 41416 13732 41572 12044 28427 52503 57925 30542 61104 58116 64197 19702 40262 15080 15060 22546 15460 16414 40513 2896 60501 53755 25333 62827 13686 20968 13671 474 14146 21121 33334 41443 36853 45038 30015 16923 49811 50714 4666 36207 20156 18393 36178 9960 23084 39894 44358 48736 42122 13302 24034 11860 30477 38901 4169 48094 34006 19033 49030 28654 56907 49940 4450 31396 52762 41657 7859 1166 50768 3172 16041 49045 5714 58348 28687 55128 10854 2590 19585 35826 6996 51385 4456 38161 62145 10621 24428 22614 48128 28031 3798 19297 36765 50381 9376 25596 26531 43112 33073 49713 35870 37806 13060 50340 46078 63179 40076 62538 5456 33385 11623 21446 25495 13362 3467 41625 57278 4827 28824 7202 61650 22776 2391 8845 63643 38145 23754 38199 16671 33901 24418 52289 22830 63166 41950 2107 63835 46334 46059 12720 61853 27813 15681 62100 49191 15263 49489 48130 6265 30389 33743 54167 28623 12000 55201 30806 13283 38203 25204 31354 20805 60962 64400 35871 54124 45526 43251 35314 56512 41651 42312 44307 54523 29199 15444 19563 25661 26205 18161 20994 38355 38214 7970 34706 16606 5963 17105 51342 44753 55491 7050 16605 24956 60271 58657 49552 15356 50454 24916 10650 59535 27226 40578 20768 40135 30774 37293 30448 36904 24617 58532 45097 11854 60039 53002 44109 11490 12421 23768 49059 19752 40482 1897 4802 1462 22671 13838 21467 52679 12608 39975 64153 56175 999 49728 279 52379 53281 56954 60550 16090 15429 39314 23295 52021 44599 9503 50795 43886 59326 50400 58379 57548 45074 49935 50074 55450 11423 5786 33473 57741 11575 48503 14421 49369 33777 26902 48773 31643 49088 52611 10875 30448 1547 19713 14285 24638 17908 30836 28579 35058 57551 2395 56526 16249 40249 42517 37421 47420 52095 2418 20547 44962 53025 9199 59506 30868 17372 45505 57285 57705 48467 36593 49496 2523 21216 34678 22206 26663 14994 23354 32997 58716 3960 42958 52601 49911 63308 13487 33119 568 17774 49156 12241 4027 21865 37173 61338 54107 19553 5670 51687 29589 23498 40880 11008 60260 6599 61632 15059 61463 45499 44003 45198 59589 58207 31464 50424 47965 43514 26983 31719 20907 15313 17120 22549 21791 35858 16309 27284 6089 51233 22442 60320 52145 4969 7107 53243 20044 51488 36463 17646 19383 54821 37356 61903 33193 53922 55554 43803 350 29028 51116 10946 25383 38247 47069 59831 24770 45093 37091 25435 57873 31658 54697 18505 12616 23444 41278 38212 61563 6938 34971 57613 50134 12931 61893 51152 64505 10532 3924 6310 23131 12776 62850 6157 6307 21875 10813 14746 8037 8446 60657 19452 50221 42058 23514 49237 41851 42586 33732 54945 2459 11600 17033 12456 46717 28645 42910 45460 35679 12600 22636 35720 25299 3884 47205 42332 10460 1912 2964 55730 622 19272 28613 15676 38743 62027 19581 29663 20299 33755 22346 48138 1512 56988 41602 46568 57252 59440 16236 23722 54398 25987 48265 30910 19944 36396 52610 56688 46549 28110 50289 10479 51146 15447 60911 33255 37007 50011 63970 53438 41466 6797 19194 49600 49133 673 63695 60974 12041 5147 23764 31375 380 30652 23646 52333 8438 12604 21039 41337 34992 30862 64233 53642 25775 10026 22032 28655 46168 8371 12884 30226 62557 28677 46317 42943 11425 36930 50541 60431 45529 59306 28799 59696 27709 50798 34692 9614 58599 17238 36859 50659 10790 57120 10056 11382 55341 14146 5923 6634 11897 7637 51544 48553 34511 59999 58090 22838 24723 45632 62260 17385 53774 8227 51007 53968 27130 60227 57483 44442 15237 11986 25751 14025 52661 51117 64195 14040 19017 31276 59950 18980 35147 30369 62684 55133 13022 45132 29864 33836 9241 16095 33312 7807 10046 38209 59715 24690 4213 19502 2070 11396 38047 44339 58967 50398 16235 23091 17505 48944 2734 54693 51123 43468 2295 38394 15138 34879 18825 8003 36842 13259 41217 5257 8578 12010 11730 52864 55727 59188 5016 33361 2 21770 15193 4008 55344 63799 56491 13156 25024 31003 46017 1323 23717 12159 58702 18067 2776 26889 37160 55219 51233 61736 26620 48133 7881 12970 45475 2650 259 27317 30440 26889 16840 45077 33955 57407 49820 54100 61994 1274 48825 43251 26949 43289 6511 1044 12088 5930 52488 42349 41174 45083 630 26699 38166 42162 51567 10544 52667 15361 17247 64116 58185 31576 13755 12978 14173 50992 52341 9824 64275 8858 1200 33070 55436 5394 7043 52027 12032 15149 43593 49513 59050 9066 9297 52597 19033 5862 20832 8211 19445 36540 61526 53881 29651 22640 52974 3113 1681 49587 44994 21660 1701 33900 26218 490 40204 44656 28294 26501 15489 17521 8252 56223 49368 18930 31429 29472 62354 34304 38256 19554 10299 57264 8602 22807 20382 4549 23924 17867 11180 11879 60530 42696 11339 36809 8595 44836 643 49016 39802 59347 17439 39104 25994 11043 29473 45499 44508 31485 53640 45731 13630 28566 1208 54442 42533 49901 55319 56765 7041 42162 47758 18591 10328 29759 52981 16223 3786 2308 21820 52050 16397 3229 38330 22469 189 8655 16319 63427 56996 39239 20293 42107 25896 52417 54322 6210 58725 15689 19073 40919 4471 22014 13445 9989 43052 37731 23574 33753 50775 58081 61301 53908 40367 58403 4789 27422 58914 16315 60225 37227 34226 4276 38898 21770 3450 61430 6061 4291 36376 4194 45983 6214 23797 60749 22409 60760 4043 9905 39775 2582 404 16107 21212 23685 33062 63414 53806 31319 33994 20207 55320 46815 51746 41904 15487 53847 15610 38455 35741 27069 55341 53135 15937 37896 3534 56078 38304 20653 43349 56906 58402 9424 8308 35633 42594 29031 61288 62030 28878 54802 5665 12571 57513 22108 35528 20130 7582 62779 56378 16877 2058 57723 35999 49108 36624 49412 17138 57255 7297 43439 14542 50543 24782 49977 47585 51844 43501 534 61716 20629 47106 49784 2142 889 17635 20094 51896 41801 48037 10431 6347 15589 33767 55185 18356 4403 455 2042 13718 40450 63224 20358 16148 63034 20300 5433 35654 38599 56320 5540 34076 33178 50355 59909 9772 28836 45831 38072 45722 61115 46914 47735 15962 5208 34261 14180 11311 34077 14943 25665 17244 21487 48680 8459 18536 28926 10540 59121 29605 47439 34630 57195 22520 3221 11683 6852 63503 27969 2891 24300 18948 63793 59883 47599 23465 39504 49108 8190 18536 48010 6515 28815 7383 60894 54628 9848 36280 62600 11687 16413 36449 40399 57187 3867 1073 28462 49793 56020 22882 51709 3389 18128 44861 52666 61546 47924 39480 245 4480 9457 29212 32827 46023 49213 62381 24853 17206 24058 60118 16625 37061 42430 61417 47090 44421 7431 18660 22785 49211 19321 15086 3503 33784 38317 24385 39753 25129 18715 14480 32812 11250 61534 30945 58812 46966 62272 51523 12855 13911 49625 49361 26230 41476 62943 10364 61803 10863 5241 13488 62556 54309 44531 47249 43477 16287 10107 49541 14234 36355 33219 30078 47154 43723 22792 45970 36678 36176 5930 59421 51971 52542 45138 34619 22890 25534 18357 49775 2537 4020 1620 47377 8186 13053 40169 50865 7958 38937 63209 61514 31235 6313 39845 25886 9327 18273 48357 28897 54724 20733 6025 64370 43287 3489 16186 22422 44748 46813 56572 55794 59084 47583 54314 22929 42470 62720 20397 59825 23519 59304 38095 63523 13385 37062 62267 3542 12149 51101 60014 64415 42875 58452 33637 27342 8635 39258 23057 922 35356 63575 3163 21951 48617 40384 17652 43001 23291 54194 56630 19645 5944 50060 6105 14600 59427 29821 62652 26700 43788 12300 17451 54705 57722 60216 49369 62346 29362 53705 54403 22468 18515 3083 54573 42408 38924 35022 49305 57982 6255 47478 56767 42560 41317 51237 35911 20408 41686 4874 10925 11735 4922 52685 25277 27966 29918 36356 25341 15745 58178 2906 41775 35846 15674 36175 40544 24253 35674 12832 50573 476 41306 22619 27349 36910 16292 12734 26337 18470 30372 51506 62042 10352 24481 62881 7493 26104 57039 40507 24379 33318 24299 34863 44464 18332 12410 659 57711 56756 29818 21529 54810 61654 36683 2692 34571 37408 12972 6329 23007 6581 24016 6457 58612 3057 59221 25786 21342 15160 35142 5788 16099 22813 18434 53974 35464 33843 46163 56149 23907 5790 45833 45259 55554 8410 7879 7010 60394 10650 29495 26716 3852 5027 30874 54612 59088 50626 31371 38931 31379 47650 60525 1069 5670 1470 34833 63663 53324 45179 21779 29247 23454 59636 60758 26441 56186 33067 4506 57159 55504 60835 8772 52134 10369 61490 9566 49483 13592 12014 6488 11044 17586 21337 54276 10693 39374 26266 42451 12760 53671 62195 60856 30920 50473 1353 3144328013 1314153757 +1024 47085 1952 13561 53055 1360 14104 25525 18415 47583 15103 10495 23898 59927 63387 47368 5685 6089 2010 42986 9268 46612 10746 53316 8988 22793 60671 31523 52268 57849 19836 24679 6235 52026 5711 25746 30108 16914 64243 21066 48436 23116 48312 13875 42828 30659 57484 4707 27076 1506 55644 42519 33284 10678 51451 12062 30308 60912 1907 6348 16241 14932 62893 61219 55254 12349 50906 52918 38733 30204 60183 24863 49845 44695 53962 56943 5085 19809 45560 19957 42799 62104 27287 29940 8111 19183 38057 11425 43056 51073 35915 13121 57051 41478 53648 4683 46993 60376 37909 30646 43686 17103 54951 18077 26502 59940 33803 37597 28292 14043 52033 52494 33265 31104 55862 3959 47151 26936 62799 36342 28634 14327 49018 28986 14292 37659 44002 55031 20976 30541 34706 30094 24576 8433 24859 19868 52165 1880 4780 59887 9455 10364 36265 26249 39796 37130 53563 12624 27003 24627 60262 20265 8944 49973 37832 45001 31507 9620 3649 35855 62762 55439 58388 24612 36550 59385 47428 34624 26391 30970 40709 17846 55384 34371 46545 64424 49902 45215 57230 59365 17726 21589 49787 47166 34225 35316 21699 31183 37864 55194 23740 44203 33268 16895 59434 553 13879 22356 20762 64029 6646 61119 58810 5833 14554 5848 43052 43404 18347 39776 18704 37399 47740 12415 53999 51903 57952 41689 14067 59855 55032 1050 2572 34983 48074 56158 62290 58733 52790 44306 23416 51239 30444 28889 63889 11222 35834 40464 60962 56154 55556 8577 18092 58346 26154 6796 2189 20404 30603 37119 50507 33350 28049 20254 41006 57377 28161 59546 7916 58459 36296 11677 57031 37014 7871 23653 57963 42991 14708 24323 28132 28152 44800 19063 40926 49204 23529 39604 64315 10950 24716 15608 5279 13508 63770 46256 9088 44529 44186 53179 56131 57235 56241 25239 27020 38319 19407 157 43900 54940 29825 12018 61465 37875 35472 50926 45614 7773 8352 2827 200 40680 6211 37531 3599 11739 57844 51179 30733 16657 6679 41491 14860 27240 17578 15252 11567 13100 62598 6255 48191 19597 62392 62451 47562 63363 20115 20787 9648 55538 63758 34299 7748 15268 22403 46357 41053 3500 60227 20834 56701 58459 18137 40975 58453 46776 21323 3557 15968 31187 55525 41464 27734 23251 17552 30432 40201 19121 49422 49377 56415 48767 38430 9107 56712 63156 55286 61469 5276 6377 58603 7839 46169 13228 55663 38758 30912 57682 35219 27949 3288 13905 36720 48483 33792 43016 49957 12372 54232 41769 4039 52741 20832 9484 62008 6191 3969 1016 28712 20354 43081 26379 20598 63121 35789 19093 54746 16612 28743 52082 25724 39036 16096 50339 46034 62642 48817 33687 50830 11608 21590 29604 57297 26111 29654 15322 46957 23315 58702 38798 41800 34654 22915 14502 60557 23781 46489 4522 39350 23254 26362 6373 43587 12016 60337 17107 10587 36622 63299 1109 60607 55646 35229 56500 48993 46721 26021 7289 47491 43268 35054 61990 22153 63784 6204 45623 23222 16927 4157 63361 14841 4239 58916 53319 34984 40493 11948 22960 54451 1823 23536 48075 23030 59039 2722 7366 16233 59341 11705 34344 27012 37581 12453 19028 22046 27636 29549 9620 63465 56878 39481 6928 59438 55872 18976 56695 13737 62978 3180 23761 51090 9780 15041 21098 54071 22154 16031 43328 1673 41623 23858 25097 62145 54798 59221 39112 23024 12689 17158 49197 24505 41943 51642 21515 55356 6335 62535 12079 12 51865 6039 36508 3115 51141 13597 38213 10264 25592 31258 41047 24050 52397 33966 13398 38682 56899 24911 6631 54775 4465 19873 1932 1810 344 50917 20383 35152 59613 49394 60809 7476 11407 342 1066 40541 48886 45337 47617 37780 39953 9468 10245 51082 53730 45714 33705 15288 16667 57901 47978 10298 50100 47133 28712 5531 43779 7863 54890 13819 60189 55683 42108 11616 38721 11784 33168 51783 38141 10458 14835 33786 43035 30376 30393 10924 50199 20180 28395 37225 41396 40578 11319 21131 30053 17047 49956 23795 59472 53040 59345 349 35873 54229 28762 13017 56936 15761 37141 48560 30044 26036 6445 40724 27739 39012 5089 59680 47012 37890 11963 15314 31386 36410 20994 1944 14589 6760 6701 16827 61434 45472 15780 18617 15725 41294 33855 31168 29738 61846 18858 23300 3249 433 38305 10026 13682 22723 12473 46900 46434 20179 6881 1384 4219 32969 36355 3373 43080 37349 10391 23600 7466 41124 21734 10620 17913 62694 2408 23212 45508 29651 64450 32955 43572 58455 54275 36300 24235 2037 21982 5273 60780 37123 64098 23273 24616 34033 11840 19786 28700 8382 17281 62809 58181 44005 50568 47424 37600 39209 12703 16954 24915 4025 24793 20599 20296 51223 64330 45903 48865 28720 59930 52933 59730 26411 12726 29365 2513 10417 40481 44152 14833 23049 14849 12914 49771 62670 54497 24541 54529 7255 14530 43387 8080 52116 55505 23702 22038 25715 21489 50357 57124 2514 16081 15976 44238 1691 55035 16838 24496 34017 42167 61249 16824 54600 5583 61730 28997 42684 23104 46691 30982 19315 41786 4759 10367 13010 37442 59620 62102 7430 6808 32827 49454 56430 42292 54626 18526 3955 36394 35953 7761 17007 58405 56940 57266 49050 59306 42011 60684 60157 55479 17520 63650 50622 41475 33361 37871 46586 54746 43537 58161 5435 29221 60985 53768 18954 43982 64428 17044 56859 36073 61091 31716 35463 48687 18854 31010 59316 12251 36183 16468 9383 34666 25015 24610 9920 31360 51565 55241 16519 16860 12766 62659 9451 18410 46315 46980 55487 10072 39084 12380 43840 25242 63433 2687 2373 6383 53041 25420 20339 27835 47542 40320 40387 44346 13060 8700 61200 28166 57611 17437 13624 19982 58911 63967 29137 61888 19624 55513 5395 36302 34294 17635 58349 56897 28314 7205 2645 23336 23969 45587 14211 27957 58070 43624 50718 34354 9317 30587 37265 17119 9255 53250 42669 27489 47520 23454 36295 37142 30611 6150 55300 27289 44120 26908 63748 1960 42640 62918 7089 40931 13335 48678 43412 21866 56057 45095 9219 60887 48422 40961 41410 34958 296 20282 48752 9151 16563 35143 35520 55427 58916 22103 47518 13847 49307 46234 17692 52083 30527 15672 11615 57266 57427 49185 54671 333 59359 38421 62330 6896 18033 49368 36553 53323 57974 2451 41005 24802 48666 56896 9632 52615 8597 52394 64018 57068 10006 59424 50213 57744 40649 20611 40774 21635 21077 50304 61242 62702 27300 38465 64385 20731 9110 38553 61127 24288 40712 51493 38468 59367 8251 4568 63332 36707 15788 18738 10266 32833 16737 60546 22696 29913 13711 22678 24446 37858 29381 58038 41657 45010 62131 35538 9293 29069 63686 59423 64133 2055 30019 6368 49168 20084 59071 45431 34894 64366 2890 48573 1485 51328 2454 47628 46239 30620 64028 35321 18870 8053 4519 48510 26465 30756 44062 11976 3431 35002 63640 61026 48446 53696 16952 59159 41796 48020 19563 61030 59491 50594 6623 46333 8905 8832 29009 64232 718 35312 17123 2022 6110 1606 21192 11635 49932 5869 6464 61566 20629 55340 7618 8943 24530 14736 25211 57095 53679 44524 15609 44328 39507 31243 18689 58721 499 6014 39551 14775 16325 11034 33950 43873 27757 38762 4624 6222 18015 20559 42617 51 45332 15138 49678 34411 37900 46188 15977 64493 19100 3467 7611 62440 50148 11019 16599 42869 38360 63501 27725 42687 29840 46728 46841 57556 41337 33911 11573 20285 27399 4382 29392 51613 3579 50400 52872 29755 64351 20072 39683 42325 43509 58415 16473 57440 2761 30646 47160 56499 37784 55157 54928 2255 614 39805 18935 26140 52038 63385 35837 56989 45830 18733 37086 40354 26962 6736 16673 19957 33535 44051 55185 52292 27214 52722 50854 23435 28841 3938 48582 50783 43818 7635 48310 36877 48006 57895 40574 21907 28643 14132 26783 44206 3628 16011 7105 28150 48588 52175 13342 28404 1682 24846 53972 14086 48919 29424 59275 923 16394 2063 39411 45170 41393 39974 7067 52948 16119 27536 30939 57090 4978 55485 28991 47763 52465 10478 42826 29648 50460 25802 34467 30907 62435 30124 50214 26068 47695 46027 6261 57044 28620 3320 17688 36242 49067 58884 53979 24359 25749 36464 19805 55619 39778 44518 47325 44371 58367 15987 19634 14999 38706 46670 45070 23648 11293 10125 60752 30505 35148 20436 31531 59067 37811 33315 26909 51416 12638 1463 3964 12987 34707 60727 63365 28467 49119 28520 49098 12049 21974 57636 49817 51103 5000 40721 49124 19985 14483 21628 64396 40482 6731 36401 34397 28223 19979 50582 3374 6791 32989 62349 35267 16395 10208 3717 17019 54257 39213 14016 32975 53146 50803 4940 22552 58940 53448 2193 25660 46346 28569 19382 53702 16577 43960 42994 20343 37821 64309 54393 36093 35473 20682 31445 60217 27846 49750 54101 27272 32929 34341 35085 22040 60977 33927 38536 60893 26122 58569 29839 31163 48302 46774 51931 38438 58356 28918 23721 35910 46611 13839 30321 51063 44928 21437 51566 47029 39481 41224 9506 10101 3354 45788 4269 24143 13128 22209 51497 40439 62457 47335 1321 25052 17154 51430 53184 43653 58342 35149 25166 4946 18512 26710 48947 50275 16040 61488 26110 27153 57222 46216 17544 55486 61554 63175 28678 41999 19797 62627 45992 16802 15871 21434 28552 41043 51505 10268 25391 49283 7389 13639 15805 42176 22477 3608 40981 25216 10718 48641 62051 41961 44416 48600 54546 36774 44831 63574 29178 53816 4069 518 43869 62814 33138 18911 24983 6345 15159 58142 35479 58848 49657 30925 37274 46120 9496 58242 38562 27754 19852 28543 14112 19711 63483 50278 5346 61801 3661 11463 11 22866 56850 44356 18948 23863 42773 51752 37193 14645 25725 47747 54131 27747 37707 47910 48305 45763 28667 49665 55956 47356 2408 63045 60974 29205 9535 38428 1977 1846 17142 21422 12624 62830 59218 13614 10408 37137 46954 20923 54883 57697 30156 36678 39385 4699 42680 46226 1271 28488 21333 15210 50630 9977 10688 25123 19214 40770 50660 10171 32808 37137 300 44965 43823 30054 50228 60715 23566 52921 27147 62193 38663 59702 10676 52312 37353 40030 33121 44606 5603 14722 24050 1662 38003 10374 63414 9482 54784 22229 46171 17195 11154 33925 56975 22116 49900 29431 22913 54920 27418 56152 50379 25262 34136 51864 33653 8102 44027 13298 25612 6651 7516 11928 40298 3864 17542 5482 61688 27048 49641 33107 29523 8919 36291 9999 40218 16362 16601 57753 36056 7345 9322 63720 40164 13774 31152 36816 57325 18945 59013 61573 6309 37606 60206 4194 45713 9104 50490 33248 63868 11830 9019 4540 16328 8447 56821 36636 46065 9291 2311 45294 12129 51244 15029 48172 61646 29463 26988 29552 57144 30943 11600 57047 7025 45237 2842 10993 21442 38970 63837 47047 14202 8324 22345 4504 22770 33727 6918 35567 2125 16992 53174 58933 40480 19045 45804 3147 6602 12958 50050 24039 35399 2841 56749 7905 15974 57698 50492 37565 40160 47438 56762 25686 60642 10332 52326 1257 3090 51074 37660 4196 25848 11922 17399 19029 29559 21745 54699 59535 45301 17501 47513 25207 40245 38391 50731 28873 51238 27587 22132 18816 17464 30763 51618 51377 5114 51047 3418 3795 3126 21813 44988 9447 3320 34956 46805 33166 9069 9205 17249 21315 32916 60081 4441 55038 2538 36540 23269 54630 64174 7150 57191 6103 12474 64429 17910 42615 1244 40091 55813 58759 53248 16103 14867 53822 58557 63740 41814 43764 49344 45742 19309 2842 25110 27514 9812 49786 46120 14979 61202 23197 9364 15683 37882 19839 31402 43944 37034 40470 15512 33331 28566 40979 56678 28603 8130 17887 61968 12330 8050 18838 18002 7960 6705 46983 37728 9254 4058 28479 49123 24815 11748 18262 12303 10944 62959 41391 46678 22442 2209 51770 34702 12584 33343 49473 58779 9728 39916 63510 35327 60024 20879 55837 52549 7991 12287 50328 8040 13426 39881 27421 357 20716 23731 16075 40604 5540 36406 57696 4519 44757 6807 28134 36216 25495 22891 30086 15337 26967 27525 3486 55983 1162 24868 55285 11381 23687 6586 63629 7413 29073 6834 8781 63286 10537 23212 50532 24127 55094 27988 30349 21776 14172 43256 39207 5786 33804 36111 4852 14234 2465 62619 1763 50544 43302 23498 45065 9951 4153 22488 63744 45261 14853 54662 42334 20652 25847 26868 1127 21027 33949 49101 3845 52928 50175 155 62309 56881 21256 37875 23822 45722 16256 49955 57502 50166 17356 11241 44648 34892 15504 61097 31638 12720 1275 61595 448 40375 52075 44870 24181 57651 27782 2255 64071 3341 18732 12311 33307 36913 48413 31534 34780 3548 41841 59466 27011 29126 55662 44549 2286 39452 13055 14231 59562 31537 26111 60117 18212 31191 63802 38357 1562 57446 17165 59210 64032 8132 11248 30959 63430 45473 22949 8540 34557 50783 25276 38699 14755 61380 64072 39284 39625 59164 3812 51160 33741 26463 49097 18375 34936 0 1323995792 +1024 14924 4192 5760 55997 8040 2497 26541 55725 5575 10497 30115 53936 44055 37923 39488 34456 3023 57363 24575 30181 3370 45082 5285 12722 54458 18652 20335 19196 22444 40507 30267 19136 9861 60779 56408 42476 3256 52510 61101 26330 9908 22050 58080 61703 15865 11051 59399 43131 35782 54134 64249 45641 56925 20024 6677 33400 52287 27874 27409 42849 7319 35159 23221 52178 7525 48642 48535 5883 4516 16692 11572 13696 17088 22281 7634 59608 28783 37675 19040 33036 20629 58268 15091 48698 6539 37786 21256 6897 25765 29548 1953 23875 22356 42953 22524 43022 38452 40693 35672 44311 56301 39015 21776 4554 51339 6045 36362 45228 48051 42176 17661 36342 57704 41574 56299 1373 26430 14792 12172 17193 12860 16416 7654 9779 28862 22225 17611 38562 17743 28250 36673 59602 34160 15016 8351 31468 25524 57143 3230 21942 57530 8536 23971 40454 58592 30840 54703 53510 58891 59792 42088 46804 46224 40634 38757 7228 5782 15800 52277 39219 11884 48356 44758 15510 62964 14288 42368 34782 12340 21477 26833 37180 7356 31187 12154 39743 45011 19658 41158 43766 57292 19047 10477 41499 27967 33321 50531 63037 4494 47110 49938 24826 5582 21353 29704 55009 58161 37725 18591 37839 47921 1380 26005 58916 6502 25069 3301 45291 12797 7394 11669 37424 34113 42586 48931 44165 44991 22370 2996 58364 40706 247 23041 41633 47832 34065 57427 8708 39808 17231 30991 3310 20940 37728 27894 52816 36341 62705 26104 53502 34540 11610 45546 42430 7140 26656 1561 50917 40515 24220 1236 55881 14358 25358 6217 18353 48300 61589 17369 49243 880 47894 7844 13297 40133 17882 5993 59688 3937 15496 59366 2635 42432 54587 9988 49803 3448 54210 42486 52866 61126 42972 41926 25552 38506 32904 45952 63469 17119 3461 19487 941 42792 34928 49630 45885 64215 57826 8434 47927 55005 25925 21844 1071 54501 34371 15910 64331 16050 14648 36719 22394 34623 44234 49239 27488 58455 40535 40247 39177 21214 44377 57258 48965 6417 44408 26459 47184 47263 62338 14997 8208 58519 35009 13664 44433 34211 60375 23875 16859 11016 19669 43478 30154 41566 28338 6295 21852 13615 53446 58878 5104 4096 49117 2563 2580 38612 18190 109 33029 26334 35634 6892 20695 18258 53042 40899 42694 7623 63097 57692 30889 47139 48815 31436 25719 45224 20003 43358 34231 6772 338 57208 35137 9095 11282 42154 51002 61863 6649 56921 58614 14038 62796 46581 29031 22010 28716 11546 62942 61201 61356 34644 10489 28257 1022 51583 5992 4894 29531 59341 10537 53703 40693 9632 59977 22797 6737 31479 38439 53656 7201 14362 38349 10694 51185 42072 16421 44154 40040 1473 6633 58573 20602 38735 24030 761 54698 21551 23912 39009 26010 36773 37808 52590 63770 41278 26044 17859 1708 33097 3927 49024 50608 7165 48180 54768 25841 35339 25634 10607 59416 357 5337 43148 21045 24051 17238 61308 61671 21904 43851 58288 9782 50717 49306 11549 31434 38865 51853 42320 6529 17397 52468 3397 1492 10941 975 51944 35406 18373 13792 16830 44520 10986 46246 48408 26999 64494 61236 62858 6903 34421 38763 7045 47779 58673 27777 41869 5761 40128 34077 26866 7021 20053 19852 53864 41405 56838 20224 20964 38169 15263 57135 6336 45005 18835 64432 35187 56059 36197 56773 41992 24287 8240 1280 28446 50737 31092 55310 27634 12455 54647 45986 64327 9548 58553 19407 63872 58234 47126 13452 17676 51681 24242 25723 28686 51872 12559 46448 40080 9548 59216 27706 9813 19621 1964 38250 6175 15954 16341 34430 11140 24163 455 43247 48299 40664 8716 52174 64354 62205 25228 39960 40347 19316 30394 17980 49129 51677 45644 33361 44746 58271 52811 63249 17373 40245 38862 45722 23981 62492 54565 21083 17992 44890 9197 53568 19138 59123 18756 62318 60525 52063 59745 8456 42363 63600 7113 29290 4282 36699 1111 13472 28278 60323 8449 50143 31690 26614 52767 32975 35255 15535 21261 1655 31060 1015 48816 24355 37314 46872 1221 55096 35389 48976 5576 23271 42286 18962 61270 51257 60287 31340 57475 58929 44907 10620 17847 53536 57567 53749 56906 60405 34646 11453 51530 19164 21430 27035 1774 9426 46259 46464 3183 38024 38771 52291 60102 16179 40680 3979 57735 64012 10353 46409 48468 27626 51966 523 33167 27916 61297 50346 58367 31262 45415 10882 46345 35027 56519 11702 57722 28268 17805 4140 19407 25689 21660 55226 55038 48256 46163 30271 13696 43075 62113 42266 21620 36679 4512 8430 16129 41651 12728 53893 23029 34226 38912 36572 54517 22464 31578 36041 16906 39044 20896 41634 13617 56997 26438 34523 43789 20150 54266 46795 22907 19775 44180 19711 4945 44709 13518 137 16332 62500 1702 38847 64146 7946 53502 23846 15127 17885 2175 9998 48117 15883 62047 37421 18739 7060 51512 43209 21086 964 30423 28377 1448 60715 8414 21910 13287 38616 24383 51434 59041 58966 55635 61197 20453 1243 24992 60846 61689 52701 16542 50438 49666 56258 23164 52973 35538 42736 58612 44227 12099 18429 61580 63841 37095 30337 15629 1313 47556 44167 61760 16631 45675 41826 50855 60251 33473 3071 54301 27374 3680 41143 52579 19366 47873 40048 5572 15430 45432 35493 42297 34340 37239 15158 23361 29533 41310 23647 2213 318 51028 61523 62921 20985 51741 28620 22356 55071 15206 33611 1577 51102 38132 19993 11844 9756 61595 39970 29885 36328 39076 53573 28388 43196 60610 25075 40225 20187 29203 10082 51903 62005 63374 27233 61315 27305 52997 14114 57861 45821 41762 37095 35112 64025 56903 55553 27326 20942 18007 49566 18372 27658 18576 30295 15898 15890 12407 2716 10718 13484 12469 43914 28083 5121 19098 42860 23752 39839 10765 53695 41383 2147 35680 19421 45551 19746 48986 26072 13475 4160 14318 4505 25278 27287 22859 56089 21188 10818 21789 44905 14653 3962 9073 17848 34792 10226 24596 37173 51873 52559 60665 20550 5436 48536 51544 24522 19765 50472 52466 41136 36854 18229 504 27360 61289 57457 22431 30322 36902 23763 63002 527 56542 49157 64011 46382 10966 9367 17873 63217 37946 60565 29439 43939 36806 39034 54149 57060 4421 59510 6861 10568 46716 50381 30518 44003 34721 46204 51894 47579 22252 35857 49414 22835 51834 60599 30161 31264 33425 5226 30102 49418 30047 8263 19350 11333 59573 48448 36796 11840 727 15097 36883 14768 64089 15784 51411 48146 61710 33229 5516 21204 24777 57939 38681 49893 47145 52950 17756 14093 56375 30439 41140 6514 57355 2449 62602 16284 18855 56507 59712 29958 57927 52574 31697 26846 36167 34344 26518 5138 21026 61173 4972 17892 33637 14549 60761 37577 7355 19567 46834 30744 61844 23316 15128 62932 4787 29498 85 15485 22488 55203 7265 51485 37831 46002 49576 43266 31647 28579 48039 24401 24504 46342 46636 47160 7897 17968 1228 62894 18840 25417 10110 31468 12340 26509 63207 3014 17982 28221 928 33096 29355 43993 7943 45775 11722 60432 49510 36659 39036 33965 117 54427 12798 49055 22804 17593 33716 5758 49394 15555 62116 11351 37067 23811 59356 20402 44438 43805 30887 63276 54292 60738 44026 28393 59767 54019 53505 30580 25522 11074 49064 5314 7782 14264 34440 30563 4079 22240 53749 28004 19408 36612 54051 15170 42699 24460 1179 25447 10827 39605 21894 36471 62474 62110 2914 15672 17169 27514 37850 26027 13655 8521 46790 8207 7990 49296 51759 47132 41896 1353 56826 55045 5490 36120 36925 1065 52111 46804 56620 10824 42881 61976 7296 44856 15160 22243 29306 27453 17335 62005 11384 20953 3782 27193 53803 42210 33003 2113 3654 60554 24708 35917 44760 58126 24432 57138 26393 56338 36956 59597 19370 56232 33504 34 43093 46824 45572 20413 53658 60498 33023 54834 40484 18048 17974 38576 11062 39571 27686 51962 49766 46800 34730 52145 29183 63404 50609 48678 26240 12265 19963 8190 46048 62718 28034 21649 26850 746 56271 6667 39279 15711 20633 18221 43404 3590 5833 40014 61656 49076 49947 56569 46087 20631 22416 61714 10166 5844 37900 17812 48710 14091 11272 9957 39142 31126 48607 58826 35191 18637 52280 53172 59842 42587 14105 32986 28121 5794 46053 26848 50341 64269 28286 55612 59737 22743 58156 31094 8930 23842 16239 22746 16151 15169 48912 63600 19569 10182 47044 2738 8084 8737 43694 5460 55485 63859 33725 22411 25731 43083 23741 34922 1885 1700 33399 25709 28055 33387 18302 43301 57546 2370 50965 6022 63838 55118 41741 10293 57408 51482 52751 49128 4537 762 44635 56768 44774 3519 3517 7407 47137 49939 46935 44441 61691 14853 9564 12509 56871 19441 26458 43386 44566 60471 63561 10516 25909 28009 8591 36397 48006 39910 27989 5078 34328 45349 13154 3904 9031 49788 18169 31052 5546 4709 17733 15953 28766 47150 15373 46882 46549 43856 16597 58532 35001 11117 60114 56264 55557 49702 58234 37388 60102 46262 42360 7381 39958 40818 55414 36389 15328 60660 20339 60020 3738 16656 59711 39567 20488 33270 33051 14686 64189 3056 43106 53721 30107 5931 30539 10494 61927 40912 20894 57067 48604 30153 31575 54552 44922 59523 49364 59791 63661 56754 18183 13189 13091 51583 43874 25155 11569 56212 19544 44630 40019 57461 4470 37024 25747 34998 22511 28310 26684 56285 9337 12434 38819 36131 2469 17782 5431 50906 50834 40670 55727 15385 13146 27626 6947 37817 3971 55821 48832 23330 15318 13250 35123 27127 17302 27263 40618 42209 35707 13582 29492 36074 42661 43933 6820 8721 55473 59200 58175 52112 26320 31737 31071 51810 23403 6297 16173 4950 59198 16542 7473 22945 40224 15486 45781 53730 18273 3391 1013 42489 50022 24244 27257 11569 3912 38194 51659 3140 12939 41312 18984 53160 18834 21122 25494 20785 54948 61437 27815 4187 20694 22257 15304 33490 42338 45111 60540 39660 28422 20015 22465 41283 4754 33846 15691 8388 13511 30272 4207 44926 45078 43475 5370 20572 39666 17600 37810 11819 18037 62055 23710 57433 53743 11581 10645 27356 20412 64072 20353 42135 48043 3603 20072 46853 44050 16208 15888 54081 27317 21351 34501 6107 12253 43606 9791 18469 9240 18799 51442 20358 37348 42908 55548 25122 54335 3402 87 50442 22669 42413 58918 28962 40134 48100 5555 25056 9221 16571 9838 24910 49435 58537 27571 44452 47846 4147 22477 47857 56678 8492 40249 53915 55581 29836 23841 15896 47810 36700 27604 60834 36148 51394 56482 45619 57087 22004 41931 44642 58242 40503 45016 23437 14240 1416 30152 18417 40307 24442 22745 64419 14970 30856 34838 9235 21224 58182 7619 19551 2205 39693 50389 38855 28157 51617 17945 60620 52686 36643 2920 7629 11246 56792 29855 56596 40331 46268 33619 52604 497 64111 10456 8210 49538 58927 5978 6399 18856 29816 1403 34376 34795 18981 61030 3880 40093 14022 26797 18812 21262 30741 19163 30664 36791 57186 19533 36683 36415 18949 19091 30789 39490 9784 48018 27382 19455 63152 22364 45126 28870 62898 59057 61525 6199 12208 59965 57501 43512 2639 57196 18777 986 47848 58696 1622 45581 11330 52522 11402 22920 45044 21348 36301 56838 50891 62168 48083 28436 18285 36271 50020 2044 18838 51905 29081 51034 15694 38990 52008 7494 9745 1994 48416 33808 8245 15723 12461 56779 30355 43820 28839 59808 33252 33252 27996 21023 11862 37331 14166 15902 17472 10439 63978 48204 46121 46869 20990 4858 44976 33569 44460 4449 6838 52907 6151 63906 29111 28695 53533 52456 37187 11731 11261 13454 3664 1491 19018 4346 55676 1770 46585 33332 21968 13002 58584 18364 60754 55976 58724 44134 56860 9796 20313 42532 28979 60551 43933 43502 50369 47388 13859 11690 46375 46597 54078 28291 31734 2237 33486 53728 55573 46482 49736 21294 31123 46892 52636 15836 30275 48753 3801 58722 20419 58505 15148 20957 51278 36292 43666 43747 43418 60085 45076 12672 9883 50189 63380 53357 47407 25046 62050 60089 60944 53397 49664 56872 51556 29673 12483 20853 483 62976 57346 20410 62507 34636 16750 59241 18057 57738 45707 63561 46385 10085 1001 20874 55254 28813 63637 11538 58316 50828 50978 11798 53013 43247 8390 20981 56644 28847 50030 3444 7251 5115 30942 47385 50505 10140 40263 10807 54857 19240 56383 62268 34204 29953 52449 62055 61732 25383 57346 29320 39927 3890 35212 47072 57377 31392 21285 44807 50382 54797 63157 2245 57844 26742 45215 16184 21053 9859 64074 43348 39904 4244 19994 45283 62819 24388 27309 44391 32947 29993 35766 20130 56454 25759 28876 16840 64047 60185 62738 8616 40987 2915 28697 6562 40002 43302 8450 51123 2677 26528 5568 25797 40004 30268 61266 6798 2243 44062 60865 34931 51912 2596 26793 57047 41801 35480 60586 58837 23480 44161 49789 54160 1255 41611 56370 35839 48823 1714 17524 37687 4271 26669 50073 2087 27918 0 1319260513 +1024 12572 57271 41893 7598 16008 38307 13914 20707 26190 53136 58545 52637 64219 42468 38238 36522 1858 26526 33823 45968 59450 42433 19582 3551 63067 28072 59332 18602 3521 19324 50526 63443 21660 23134 44680 23239 60431 48809 63479 60256 28786 59238 16889 45633 26517 3831 52482 6323 38875 61279 30787 34240 51157 1138 47370 44495 3032 18101 13073 45498 50581 58375 44091 59090 6808 28220 3143 2969 41515 44094 10942 35783 59463 51077 50034 29590 52062 43393 40683 50565 59331 39133 29620 49818 31355 281 58835 41 6701 6664 54723 13280 39236 54349 50718 36166 42616 60239 51343 51800 5173 910 20952 29842 36536 6361 50739 62100 36006 23070 21948 59465 51066 20197 35735 26686 41330 56511 12597 39976 6158 801 55248 2811 25608 42136 7339 25659 1144 21721 24826 53184 50181 43035 16585 33111 20130 40693 51771 45790 62243 46845 2602 26577 8772 4371 29929 12538 55928 39836 38507 34184 3351 2998 58159 39987 63707 36206 54197 21671 5672 26864 5380 61899 30652 3431 33138 47874 37802 11832 52686 17664 5900 7689 42778 3558 50290 6305 49602 11204 26609 38232 8436 4236 60275 13566 32960 10434 469 19592 51858 55928 50519 2989 8059 12263 58989 17685 47096 4435 26308 8982 34423 31676 2366 3879 21797 8888 12910 31169 56447 7564 17573 40170 57378 30112 56021 28792 47237 15682 63546 53646 61863 38009 25469 40285 53245 38081 10533 7667 25959 31330 28570 33935 26526 3847 48073 35696 54499 15007 20403 15972 2762 59623 52005 43913 32794 394 35286 41838 41020 56966 22265 23879 39825 10809 54352 31424 44070 31526 58896 28641 12888 36370 50638 45160 62292 23658 54184 1014 58301 17313 24626 22067 28872 45915 28874 9050 54069 30580 34516 24790 19846 12098 16390 22695 23685 62833 60030 43004 36169 1689 61413 41176 5957 39113 5816 3852 60353 60962 35136 21298 53013 22488 55854 49320 62873 12800 2946 29630 12082 27534 50623 35930 44279 31717 20729 41587 46534 19476 36949 43693 12013 22467 48667 62939 37042 41308 18380 17068 36817 44692 62447 63229 5930 57300 36258 50579 37854 60496 17790 48450 24983 53658 49859 9388 54555 36584 59477 58461 63764 44375 31657 51266 16718 21172 48685 7664 52538 15274 56174 61898 44956 41970 42874 63466 62730 49555 1201 14544 30826 43992 33559 13605 56045 5161 10939 45818 13101 36256 20872 652 58769 16930 51587 49855 13409 3898 30638 8050 44350 23087 57699 3326 45741 50412 23212 57397 11941 45496 15981 94 3696 10931 34208 42490 48764 44681 27710 5043 64103 47755 2444 52302 56025 14732 60408 37477 19920 17403 33689 41048 26257 61392 11306 34567 63200 18919 38587 56659 31028 30053 44055 61301 17153 21401 3617 16050 5549 56097 4120 18441 41163 45908 18072 21935 4997 53671 36295 63332 49770 35364 18881 47092 10144 27461 29398 51163 42917 27778 11874 39869 3762 28301 39777 62603 12290 15416 62280 42464 24056 35128 30171 60217 49360 47412 39658 35178 36884 6706 33171 51663 25030 10793 3683 16658 5990 60962 42148 19261 39415 40797 60512 11958 47602 40583 42780 11853 50687 48396 30168 15075 53496 11988 46109 30755 11751 59581 53199 11861 10034 21636 54520 42133 16209 61128 15063 49278 34808 20681 20368 9666 45301 12860 37860 25730 11013 50424 23592 54155 24771 8045 30393 14850 48289 6077 27688 40965 9267 6028 44274 24132 36583 50397 51048 54284 9972 57294 39606 51229 38982 1404 61075 3749 47697 18687 38086 36577 43316 46725 27773 35762 50243 62415 61437 50669 62059 9569 18797 24253 45810 10284 16065 57530 11985 52944 5143 34889 40761 28428 22820 14772 59400 48262 1881 42793 3738 64290 44960 61070 40691 15593 52723 54131 44301 49259 60881 7354 40017 16423 13873 25001 57020 34713 57661 7245 51244 37504 38649 64070 6461 3321 17792 19662 19747 27056 23304 40455 11492 31526 36277 19271 20328 3857 51753 14631 3679 50433 24529 42681 33196 57142 52534 1276 48569 41812 2360 22455 28513 49657 43109 19164 55718 10032 29894 13619 31712 17627 21453 52178 48434 7429 1479 35695 16691 39313 60396 58226 43786 56532 20670 53257 8103 25495 62017 61901 35236 15551 5235 62541 21993 47963 36331 46542 35883 60276 40506 45850 53661 4419 1883 29340 36880 12429 39065 63650 57564 44858 25763 6061 18053 7916 28258 20415 1811 40825 14604 11964 47771 48758 44942 28236 8097 48135 7659 22850 44750 56459 27015 36881 35670 29767 39471 35486 21119 35789 22116 38482 63547 30746 47999 8125 60459 4262 37247 17813 53336 49696 56080 15110 16053 320 62047 58879 59173 4825 39883 19959 34580 39814 45585 58662 20351 60666 34980 30221 53504 46299 19882 54582 47754 23896 45496 26763 39182 8887 36621 59245 3542 51047 64043 48228 48392 26227 20196 14965 46390 33455 36381 40983 38169 40591 17773 291 24855 52231 2607 56784 27 4180 63087 31481 48957 30511 49381 11185 7781 46043 17591 58745 56686 28232 61935 51343 26776 10272 49140 63624 51739 28675 40330 33854 14763 3 8930 57265 4330 16960 17120 59078 2926 1584 17907 30728 49425 41681 25850 49171 17115 36599 24583 8751 34574 647 23125 43127 18519 1280 49617 30489 28199 18539 52879 49807 2690 8670 48683 52347 17490 6987 17106 38947 43109 60025 57307 7680 35827 49770 55165 60270 39840 19744 173 58939 31035 5854 49075 51968 28986 36765 33556 24186 49974 19176 35384 2301 11939 12826 610 24133 6267 1678 45041 49072 35530 2056 47775 17909 35727 52588 45162 47621 48057 36215 57083 34694 54486 51771 14048 49385 55512 21097 30009 11217 2280 29034 23535 22441 19670 23487 14922 50079 813 40843 46498 41543 27991 30789 1917 20926 57357 6884 2175 5864 14987 44230 11088 62456 53378 43676 36340 17122 27640 55042 60174 64418 5116 46560 42971 64160 64362 43173 56546 15548 21088 42626 12954 22146 61634 48273 55988 6110 1704 36473 6657 60553 31378 29245 27318 20301 20905 44117 33605 62058 62016 49748 41648 21330 10655 10012 8895 13391 36545 56676 59378 62009 15441 56121 1553 47493 9700 4060 55058 38438 57663 4697 18430 25174 5329 2424 50413 23710 39121 56424 33757 33911 15534 47616 49911 21920 39688 4632 47128 53157 13891 22971 50215 55175 40213 4343 57473 43742 59363 13491 39039 15290 38096 28288 41468 38287 25382 8186 49018 10896 38639 59867 42112 38805 19132 39082 14052 44292 11317 55170 3800 50580 9937 63767 45819 28449 20347 46070 15734 54095 12977 58989 9811 39003 40839 4521 41932 37071 61297 15229 33170 43938 29723 51758 18954 60299 52666 285 29082 28376 22032 18556 39970 50703 37014 21598 54183 38987 15046 63151 14528 28532 63560 22492 58704 9634 606 6413 59882 48297 59708 28845 21164 16559 37185 62461 54677 45974 63825 46536 21611 14788 50918 17859 42289 5785 49418 12290 2816 40029 23596 35438 52899 22682 58777 54035 5497 24622 44964 37300 35653 37044 1727 35245 3597 4553 57615 27300 4128 42457 53997 43669 20943 5207 53016 29307 12979 63407 55606 16611 61716 27439 40372 46501 22689 20806 21249 14795 9687 17953 10415 41063 50333 18176 26558 37853 37803 22068 25257 9723 4217 45661 57787 54421 44007 30117 26837 11528 26891 59679 22650 62318 24844 45519 26936 14256 38917 18250 45728 7222 1022 3327 35783 17914 16421 56154 59848 13516 53289 33570 3765 8439 28770 48906 43306 24735 62279 60778 30409 567 25262 44372 10746 51471 1067 58655 19555 42116 7063 25996 2579 37805 56529 60476 20782 18399 46771 63092 47826 26596 26666 30763 21785 51349 30281 26527 33865 5209 19636 2905 29474 54896 57050 15734 58333 25500 13151 43617 25950 25949 37557 24393 36278 22946 7463 13198 22112 49465 23664 14896 50759 59756 52037 32889 47594 34697 5004 9830 45778 46507 13619 37394 4696 62914 18837 45064 64365 9358 8306 56130 33376 18399 36638 23529 44742 55673 50390 58734 11765 58326 16037 8600 25182 52854 15184 50414 25130 51465 21324 35408 23925 4039 42317 24365 63540 10708 30409 36035 60224 2123 25893 57726 57192 56315 50582 13200 25427 2457 242 54106 48081 63590 62979 9458 49065 22519 25588 55898 39034 35114 51588 53315 14974 49416 56435 42122 51112 53750 37687 10879 23591 1937 14989 26365 9533 97 58945 25025 51328 9883 826 59245 18037 12338 43156 35944 15991 7273 9441 37144 52020 41274 56540 43998 60775 1312 64271 63091 60987 7799 58038 7038 45517 63243 34469 17651 47740 40346 60807 466 2365 29768 1380 23563 27594 49710 16857 55872 54194 38634 40534 54868 2907 19558 62626 45458 5190 10265 31297 25026 48438 60641 41428 16370 38536 59306 41920 55105 24752 34102 37172 53798 51677 2091 9002 62976 8461 60339 4125 14003 5388 19914 23224 44091 42144 19767 52507 12218 25898 8289 34160 4349 20764 7787 41538 11175 3480 33287 33379 1961 19146 15028 23579 18493 46382 23460 11987 42048 59264 38280 1919 49227 30737 20609 35914 23314 52644 2167 18659 17344 14834 9354 46549 17403 14147 40434 27955 767 58281 31287 47118 13851 54885 26788 47393 49457 35976 49092 54260 7961 16299 34056 9767 7490 20373 63954 12169 53027 62085 40241 39344 49108 64194 55838 34713 52715 15560 40137 25920 39106 46411 41729 27479 12875 26774 4459 52904 6708 25056 17242 54620 29770 61981 44722 44975 17202 6523 62169 59371 55847 62371 36381 11285 61130 51973 58778 25137 29487 40861 58076 15470 14890 27938 14901 42693 16808 27049 12163 257 43063 35437 41619 55084 47449 35318 7780 58967 33712 26774 60778 49661 61953 29611 26272 12776 40934 33915 49508 17883 45629 13420 62357 63195 39067 37279 46575 20321 40240 19158 42387 22593 22074 5456 56794 60076 15531 23749 19448 28038 33034 14426 30091 38932 15809 6753 62446 7896 51902 44701 28790 43477 44146 43484 28479 4799 11900 52864 54062 37025 64498 45547 33789 47406 12527 53540 12239 4302 48200 18768 11176 34536 17451 7179 52385 36356 52184 49304 57085 21922 60198 58909 43606 9449 28 14792 61568 54075 25932 31518 55493 30799 26331 49075 30876 11411 19141 59272 59872 24303 45606 7561 10000 33660 4997 37141 21697 16752 62047 24251 38481 18769 18394 44914 7591 58863 5053 18581 14092 22062 56415 26063 54797 46652 3823 34250 14511 23499 58742 16871 53089 23605 20047 39333 33648 41667 35271 34937 26477 38844 14222 33458 2154 40037 641 43443 3892 18256 5648 17616 60220 44179 29404 38855 8098 64303 6317 27327 55383 44331 63438 1872 9800 51726 16055 22531 10831 14565 50013 43833 35025 17395 35983 11904 12581 19536 60558 63580 44373 13519 42216 58005 43575 20002 45058 45412 28779 16311 14933 54232 18999 29668 45438 30602 38972 33772 56112 60533 17969 1389 48427 59783 21863 37257 12864 64252 61593 62467 34215 34475 14371 50673 41597 4219 23029 60390 9087 46999 61090 52762 26131 43296 3185 50673 63831 7704 18408 43227 28841 40539 692 25563 46541 9095 55455 33983 33583 45075 1198 12096 3486 3832 35913 43376 53619 4017 1168 47386 8373 30697 52106 54560 55691 40808 60605 40984 347 51688 63591 37049 26651 36053 17678 40675 53263 63537 22447 39504 28328 12706 22334 13188 58798 25798 21749 36331 9200 51815 19644 36321 19021 22141 50219 13207 61117 39349 17617 3526 22884 7662 15857 27867 13758 43384 16533 1066 8734 15695 37344 47680 54819 44786 3291 58767 55729 52847 24782 29807 3277 6929 44180 481 25914 47444 34833 50991 47312 16135 17628 47321 23657 2233 14903 32779 6217 4971 36797 48336 49171 6444 5700 43178 701 29310 46980 54974 5302 24041 60765 35593 56089 9091 41694 52151 59410 52312 53682 62305 36449 23034 23989 10086 13753 23228 10195 1499 50645 8760 49521 13251 37517 57751 24468 52912 60392 23763 13726 56751 33006 11245 23116 40652 59404 31457 8029 41791 11506 57694 53664 7812 40792 46156 62505 26721 42473 52965 63876 9313 12375 12841 32863 46969 42362 17165 63140 36106 21432 12532 54090 36430 42523 42522 6718 21761 36406 7889 4679 49439 30277 53425 23232 53913 44430 5439 26334 15363 11072 12483 4012 38578 26408 53791 35625 48625 56871 43619 60061 63451 57195 21322 4764 5852 23111 9936 4314 30661 3001 19253 8619 17981 38358 51202 21432 20540 17723 38162 48831 24229 21913 62938 63726 6873 32805 47671 42949 39954 44082 38774 50661 12124 49033 43563 29848 52183 51239 49094 10756 20028 37661 44082 41863 51502 25112 22386 21671 30248 34898 1596 49115 15260 4240 54341 40230 6039 31549 3411 57826 27661 34270 22813 30344 63282 23733 4525 58416 46996 22247 9771 59824 57959 40031 10312 20140 44086 44784 38706 7767 46044 45275 10578 34826 227 3229 20616 605 11475 4221 41635 20498 9191 43449 4100 20433 59566 23559 58025 29213 57658 6874 58519 57837 56943 59402 34964 9564 3315912437 1305908749 +1024 64411 59759 59328 37059 48293 32933 60337 1595 8668 58588 40641 58808 17823 38519 20103 25065 7363 33697 27714 50088 54501 41093 45609 21256 63355 16167 6443 6020 7390 20454 12396 53190 49114 60889 45844 35378 39322 52869 34081 8487 22739 11886 37412 29050 17261 64121 60126 21519 21752 13398 22277 56704 3884 62341 55544 30110 6760 35718 38031 38318 10313 58297 53213 24716 1081 19773 6494 17099 17368 4695 11627 49138 28029 42889 7488 2679 55679 15735 47020 21679 27256 7853 12107 42894 62647 9328 18419 30336 48336 59294 59507 33737 61177 50236 12875 59624 4765 49343 54385 23464 8038 21946 63427 49013 61956 45734 18716 21958 55975 14952 53184 4987 30381 12221 9267 24559 35363 57077 11050 33494 53594 40131 42676 47479 37018 4066 5547 2158 59488 48135 9772 31561 63774 24576 22471 29681 40952 40022 6124 56434 61520 34017 8648 7410 4003 59214 55789 56764 41578 55639 15993 1530 26659 41232 62067 46273 48210 43201 45906 34237 61562 26524 56037 15256 18076 1756 50462 35446 52017 30895 22935 61905 30996 43124 2086 12893 43481 39921 45427 13268 16394 29858 5469 61871 33641 14370 3352 60940 4267 20139 29682 6518 43754 8572 48424 53569 34923 48012 30233 48078 2538 60299 61556 31739 19613 48724 19772 27188 7749 60463 63034 38035 61660 12435 38461 52444 42512 35515 5687 35072 40471 29029 17421 59924 14618 62374 5500 32779 22565 24688 39013 15142 35039 5017 15109 33284 22336 38073 49299 26457 11045 41411 55862 12579 28727 43259 29399 42180 14322 35501 28710 28624 9486 48669 17122 64068 38286 36109 5132 21005 14800 64263 35485 14946 6428 15972 48063 51202 55738 19171 21261 57303 7148 5381 55348 34410 29027 54597 8415 27442 10978 51667 5388 41429 50325 2821 25610 64119 7820 43755 46521 22885 15808 56888 21723 56299 64000 3716 38700 48807 4050 2517 20370 47358 48951 50559 59183 53070 60377 56419 60363 52957 47465 7727 50148 40440 1652 28608 2519 35400 12419 40949 13132 57570 51763 27763 53637 53457 62545 60807 23 62362 14864 15526 28262 23139 54865 25322 10415 24405 34973 47541 8576 41825 45943 53198 12606 4065 21388 60070 19959 52092 49315 23936 54786 13715 56302 17466 50095 31229 2285 8781 3229 57654 25286 14124 64187 20038 33716 21365 47601 19120 40042 33317 16019 23551 45719 16819 15852 28 10674 1471 62627 63477 34267 9086 12855 1222 63185 23047 10159 4092 54183 59138 50635 36982 62125 56400 53671 8121 34770 29144 64111 28693 207 24869 1171 24460 10908 131 49355 64434 10169 8231 12698 13806 10106 43041 31600 35986 49046 42400 46717 63855 60845 15537 49450 50883 14141 36041 49319 58061 27590 50974 59878 27047 5136 33100 8566 43304 34842 49443 36467 53014 35502 58975 45248 50199 4022 19253 19294 45207 879 33368 53262 59358 21654 21424 40668 28932 47920 24656 63035 54182 53857 45756 33668 59922 20842 2868 55175 43005 59501 46516 27605 58336 11495 31659 55361 10910 46855 37651 3286 6344 19188 39078 44205 7592 58830 17866 16720 22230 16606 42159 45625 40192 31464 63100 39450 30412 10532 17798 58394 3688 38450 21798 39092 2114 11122 45088 6314 56989 1260 757 14974 35450 12830 24610 24647 43392 44630 3970 44844 59499 12342 1669 58988 54326 50175 43257 33541 57268 64498 46052 39552 31056 50998 54314 22853 61093 11908 39693 26526 32770 11460 59990 40534 8629 63233 33415 44256 40523 51961 31420 63483 58714 52251 24304 52283 12292 49038 49255 10692 39916 36157 10 51790 21904 34786 45395 56131 5303 5241 36686 8967 55400 63425 40856 53398 14854 14268 11283 19186 37132 59178 48765 1302 56257 11004 56540 56342 40444 39096 22457 10052 25012 340 13425 52829 62572 48308 48499 30059 27400 11429 42252 50595 19143 50515 6924 2907 24724 9097 39858 20959 62596 60788 52649 28271 39275 59726 60808 39102 49184 35938 48367 44305 44971 20347 10556 13129 30498 10035 10508 38210 21298 7081 10694 8810 36003 51928 39093 45554 29853 21674 5669 63127 59113 22481 52918 55702 60488 9915 26234 44489 55896 64094 13731 8373 59956 25211 5198 55843 28311 30880 55701 45377 43358 34808 16398 2718 52997 13834 21185 39730 40415 35985 60101 15671 21370 16607 8707 28134 15573 37036 62871 14569 14873 55547 21263 62178 20830 26594 63185 25052 34826 34729 49716 47994 1824 38026 24643 46047 59714 6210 28392 57948 40116 16819 6515 20987 904 27941 39097 56781 43849 22589 30802 341 4088 22802 15825 45096 53468 53122 30365 16542 63523 38494 50546 22555 9996 26904 62139 63006 6975 2937 7912 21743 38118 39556 204 51539 2362 26741 6820 64468 35016 54849 43470 33399 17507 3518 45986 30151 35364 35332 57877 23242 15710 44606 25430 46421 49543 25903 30980 11972 7810 45983 35235 8948 39577 15204 1722 21785 56766 35342 665 28139 6957 63116 45609 10596 810 60142 2637 18262 47247 30509 938 14521 62393 42700 49358 58549 2234 37661 29424 43934 6069 14086 3376 18513 18622 21885 38801 12117 63267 10157 59838 7666 59237 41713 32933 11683 37097 44694 20647 51174 27503 24414 46639 56879 58026 9592 51498 49799 52275 58789 14047 11937 45580 59833 62998 61459 41637 24174 59533 15838 5106 24561 12876 24744 57592 42179 48365 27781 3132 49608 3339 52908 39659 25399 44376 57132 44188 17629 48748 42073 20156 37039 2023 28901 28737 26765 9698 59750 853 50461 493 14794 21434 13779 53712 15340 22601 14040 20783 8675 28793 63320 16383 12405 44702 46762 23905 61843 4804 49895 56978 9238 11154 53552 53684 60974 39565 31327 61972 3173 29066 50861 55438 3641 40490 28078 21023 36824 63999 51187 18625 19863 36083 12754 9022 36312 13977 31296 33222 44664 63368 19363 62762 20441 62283 60701 14651 46201 35956 61849 20218 22529 38024 24675 23053 17566 324 19489 10759 29800 30624 62117 3260 44924 54543 4218 54628 9132 6831 11670 22286 7639 26383 58728 62067 51899 3827 40089 21827 45543 54596 5031 29564 12542 537 61658 6097 12782 29484 49327 22031 11775 33293 11069 36197 49294 57561 60964 27947 8707 44745 53832 14665 47772 63699 60970 16412 18952 24899 58043 2310 3236 50957 34424 61748 60522 15187 48495 14605 544 38423 50576 14549 4629 50817 23130 57359 48737 56922 30348 59828 8287 57860 18763 30653 38981 11043 61069 28388 55422 52595 22266 57728 19318 3311 49721 45596 8342 30051 44055 21746 22032 14736 18425 21610 23857 34861 6485 47986 45678 24249 63617 7350 62231 63779 33589 10907 52639 26431 43278 20527 19572 42975 29009 28452 51924 55671 22726 43500 51657 34170 52805 25414 21142 16163 51949 62530 47125 51579 16946 30632 3390 4097 984 8582 56739 46147 43350 29015 12846 33228 53185 49801 60253 56225 41680 45339 127 17265 26609 30660 35946 54435 54553 14627 46592 5288 58822 44616 18920 44697 40605 14630 62298 42836 22505 2611 8306 41557 10008 7024 8256 35836 52428 18916 5432 6833 29283 30920 25474 61261 19522 8235 36264 35990 42160 7487 28497 7478 35545 46611 13003 9222 43005 30117 41750 8943 57374 28303 21462 58105 37930 33439 21696 64347 46423 37318 62935 38399 58920 3620 30654 48190 58393 16764 56550 24882 20697 12711 62985 2695 39604 62548 25453 53353 46693 31538 63536 17183 38917 29203 8609 35101 26964 46402 44505 12662 45865 42660 1113 23260 9763 35750 21884 63202 17447 26874 53411 45141 31425 46802 43917 35493 51802 55194 56677 58628 59396 58513 46858 52965 26570 41639 38440 27596 38405 38798 18135 36320 10921 53540 64035 54188 55412 51201 8248 16389 10367 62100 46233 39640 29985 63029 54085 58579 64019 17793 35939 48214 10300 41578 707 54841 46087 3661 48202 46352 53960 5106 8112 7649 59161 43838 25662 38960 48443 56954 43460 14080 46493 35439 354 14203 31070 43975 12278 40667 26981 55939 14436 12210 8191 5096 37534 48590 22419 12873 9705 38890 35537 13112 63974 28693 62110 58135 29171 39617 42504 45004 15149 28080 63555 5631 20859 12164 57796 24167 42269 55841 58375 5242 25666 43029 8889 53828 5386 20616 17870 47137 39191 51244 49835 41790 25755 44703 966 39477 1613 8292 3943 43564 7024 56601 44742 43725 25674 20068 64148 52625 1642 29906 50961 42447 1837 21387 57139 33640 38145 15532 47329 61772 18599 51202 46664 28548 54625 2837 30987 54970 24603 49649 62512 32808 13938 35407 54719 35687 1348 60309 4078 7878 10557 26967 25084 22223 13054 9950 9591 53825 49061 14571 49108 18222 55640 34931 22440 29117 5004 23501 36352 35027 51267 1568 2306 13712 42157 29110 53217 5441 39369 45279 63776 52677 63654 41999 53754 54734 12795 15552 13893 42046 37981 23599 22945 7518 34348 48767 26212 45373 12884 55645 8871 40928 48990 45009 3934 50909 59353 43301 57570 58707 58643 63192 14854 8358 52593 6320 20048 21937 63127 34219 21018 16510 1630 50978 38118 7329 27755 38954 61247 14170 16309 60160 44535 41616 53026 53165 8083 34790 36642 48804 15435 28560 44038 14428 46303 42378 62260 10652 38962 38365 46133 57257 26761 17427 13241 28423 23858 57193 30832 15187 12082 52011 23598 24471 17015 56407 34299 17369 20038 33673 61158 27093 37502 39154 12758 42232 45983 47981 21343 16984 48490 61291 31732 24478 40710 7592 12703 44388 8172 24408 16482 60211 48540 60396 52668 53579 13798 16577 62059 62985 22379 20983 29330 53227 62476 26035 45727 23685 43429 12292 24892 31081 13618 6163 61902 18284 57391 54748 15645 13039 52209 33685 39182 63357 60517 27100 4646 48075 47577 58909 46341 28563 53135 1702 46944 21079 54292 31616 11129 5922 3235 44803 40908 48280 58712 47049 35200 57719 45028 28796 30007 58506 8226 17860 49785 31529 12643 23902 30399 53423 23113 17393 40666 37404 6185 42384 54781 21431 47041 17581 59490 11692 30670 55034 5939 57314 58893 57029 63846 32974 40914 14113 29895 29313 46757 30296 14924 19420 45576 4134 26557 5343 23708 6935 37326 36713 49885 59035 54236 46013 55215 3803 26861 8257 34091 62687 14429 23385 42292 45003 48694 24040 35719 64333 48521 25618 36839 61507 8167 60578 31228 42421 4075 3755 57969 39469 38905 27211 49224 7694 13739 64444 20701 41256 11581 51183 9233 53118 44658 64050 44253 56658 26665 17125 2522 42221 22700 50427 2218 694 55225 31661 64375 37323 20371 44398 45988 21282 5711 56210 57914 16498 27768 33332 26225 41518 18920 46881 2232 42233 64123 14731 19033 59428 60923 41388 46561 58789 31042 47913 25970 46200 61537 17930 23162 19836 36910 41464 3606 48039 11563 15981 64179 44587 52590 39908 63651 63950 24749 44447 1987 62626 42169 52283 28242 36770 40238 30629 901 33809 16754 47657 16114 29824 13546 22092 58094 30606 52724 739 34763 36367 4423 53667 50401 62702 52181 36076 9068 48489 50895 8829 55385 27414 39033 27607 9975 40072 4208 49773 17110 54633 21030 5622 48593 60996 22974 12783 51183 38522 6031 22541 32814 2926 48947 62646 14254 60576 24980 5640 58921 48562 43250 23079 19670 18092 38328 8460 58484 16954 58138 38493 40490 4945 50630 14545 13563 28927 22959 445 8087 13226 1386 2740 52481 10898 58312 5813 2955 15474 59925 45778 56297 45406 3753 29551 47147 26585 25847 33951 54716 64100 41086 48784 35992 63337 5412 26862 60077 4639 9237 60057 26491 12421 60750 17073 48984 50915 61550 17386 31539 25724 10780 2744 31611 14735 7454 3971 23292 53400 26582 56747 8935 64149 43248 8275 4865 57635 28696 7526 33028 64278 41163 17999 31494 10139 31065 55077 22633 4679 46195 46910 12257 45675 2574 4732 36506 16680 12365 4984 55968 23872 711 16845 42093 62073 52957 31324 36920 7784 34450 54333 40397 6096 40152 60481 33345 59846 48531 4689 39402 20529 49198 45747 38800 14332 12995 28448 29006 43843 56799 35543 20388 30223 38278 7693 55093 25293 17294 57123 28331 20888 30918 20081 15861 44006 22328 16668 1620 64361 2041 25606 58380 4905 3544 33270 63719 61497 63568 899 61373 9640 21988 45674 30689 54585 3732 29590 37260 35650 44238 54177 3832 30846 26967 63395 42426 43814 35541 35124 798 26184 48734 64262 24834 58279 21510 34672 15202 58319 45976 47944 57583 62950 31691 18183 20915 57673 19719 49683 36177 11979 5181 4071 21479 5986 53414 4838 20268 53273 9099 37360 17243 6835 51728 12401 62060 45854 40795 31349 39507 52429 17472 63195 18681 15308 31528 41508 43086 29327 54070 15298 15817 21692 22100 57680 51800 49174 6328 30554 53346 3419 46813 34372 45705 9131 54919 58924 5100 40599 61709 44656 47217 3981 61491 36489 16011 14255 21377 9431 23005 35997 35259 45677 13826 45167 47017 10210 62736 14594 61328 16806 61958 8535 35568 25577 45703 30972 28854 64469 33864 37801 7782 20248 7344 851 31500 3616 0 1310699031 +1024 19792 46022 24415 40282 15406 51985 26902 47326 41572 42491 52862 5673 980 53412 35218 3544 34661 47754 36418 28480 17395 33139 6120 5007 62173 38452 59099 60703 19534 61733 62138 31032 3176 45097 9518 50505 44328 33170 34492 18976 56092 15126 64076 54817 50227 51922 31710 63502 61903 48482 33438 21304 56969 50928 18460 30362 15441 57711 62285 15365 29378 13692 50654 25034 35730 28574 1293 39234 24100 33074 29494 43789 51198 51463 57454 19482 39816 26781 54796 36082 53873 34397 10396 40515 13809 57784 21466 3511 22842 51392 35781 61854 4011 46961 36015 10973 36677 53920 47067 51214 27917 15153 12548 56167 1234 55304 30242 42555 12733 40798 164 9841 50835 60854 64143 44301 33645 16826 33 10494 15784 40768 7023 22516 45724 5908 12908 38157 8291 61242 13087 33825 57305 36561 48429 26513 20643 9855 38914 38021 35750 12902 713 40817 29781 37666 5960 5808 37744 35505 1689 17260 43713 61226 46033 4120 29901 47076 46870 46057 22880 45910 20291 21723 16673 31145 20598 25933 56590 34902 27358 61471 51508 49231 40739 64176 56376 462 28568 12386 9633 19668 37758 62713 31169 53748 38040 35384 8024 63175 5137 36953 17148 47863 60115 20940 14894 57502 21032 33736 43234 2969 31218 46344 5250 1865 42255 60149 59178 12047 36977 28525 7254 40741 34514 31110 41400 49343 45265 33274 60805 51978 15987 46256 34477 40875 57325 37472 22203 57779 54715 30757 61650 7211 54267 61921 24325 6321 27422 33269 11032 63544 12643 36444 26768 42911 54772 46869 19007 37491 56165 18439 62143 49598 26766 14189 23438 2750 9714 28991 37629 22561 24653 7340 51246 42159 57004 12247 15001 44707 42140 41300 27134 48382 35344 6247 33062 51517 12052 3811 15211 63040 56332 58169 1187 51408 5060 1993 4962 16241 6641 25663 53728 54707 57408 43972 4801 10511 39100 54136 47378 27792 62066 16228 59637 44742 11826 61633 46738 55606 61499 5101 22438 17926 25452 57987 16351 37601 52111 37635 45248 25704 821 4016 41567 30294 37569 51590 52250 53458 19382 33232 52870 50376 639 27738 14714 27276 5874 60551 62095 33224 44338 19895 13710 59923 371 50525 18746 14834 51626 48303 26706 5908 41507 33975 13631 7852 56070 11659 27874 47269 16534 47639 42537 4296 36435 33762 57454 14508 43419 6297 17942 7806 35727 38932 63929 27694 57263 34851 20192 1250 34941 45838 44671 61817 23601 62210 50765 3682 49542 6378 1660 7511 61791 19327 2127 26725 38234 19815 42239 30069 55724 16614 60360 27643 29782 60016 38009 29766 64315 13489 19473 54554 51214 2062 19356 49382 45660 26380 4856 19009 61875 23969 4552 13086 53139 40131 11087 37816 44232 26129 20370 11909 46423 30786 4572 40532 3943 18909 53966 55977 38870 28154 47436 40993 37123 41354 10715 37253 6846 34715 47004 17702 39114 35463 50564 10037 54829 47204 41733 28815 40754 46205 8205 34866 55424 39163 47569 29467 7667 19627 18408 667 43734 55456 27662 172 42079 880 30060 39819 40097 37911 16350 53158 6619 38265 54185 2847 61016 62569 55606 50669 54355 13437 8740 42240 46163 26140 34989 46374 30701 30650 52037 58007 44206 53888 2486 49963 4350 24883 43956 61845 12528 59615 44330 57314 37553 45817 58421 12601 14802 47992 4358 1732 57096 1371 21376 46416 30907 27884 27360 20887 34526 30719 22468 20723 10374 61894 14491 45383 43311 17739 53454 6219 36636 4283 11748 36757 58378 20899 46936 7153 20953 8767 23457 12436 27514 9288 29093 36701 7886 3884 53514 42599 34687 45095 47047 13126 55758 25303 60479 12322 39699 11996 54382 45106 22284 22296 18592 41601 11104 59384 50227 48583 48293 28039 43624 33177 8381 38221 42578 27198 37372 28295 14313 26742 56943 37124 64207 39923 11712 23851 27209 35395 56270 23961 27802 34198 12011 18012 29364 20021 27801 6168 18082 19479 11886 58951 48879 4902 57911 33067 13398 52874 42650 28431 9653 61559 62879 3253 58275 55723 36768 53593 24765 62547 60171 63583 25125 23441 47982 34619 4862 62827 57149 26455 35912 63138 59013 64489 27418 59482 13617 58767 24724 39251 33508 55994 45654 2545 12504 51583 44920 18656 24197 47482 50685 45087 18242 23940 49410 19767 56620 63011 52736 11777 62754 7203 34339 33996 34281 47707 50839 57410 48901 52619 46673 26533 1708 17803 2336 15233 52248 5968 2318 10656 60413 38674 51718 39535 23743 45827 36380 51814 62419 17496 13107 52191 61419 27592 33416 15116 22954 10060 59845 45938 17546 45883 40912 26415 26746 13485 8396 35251 64164 38116 36188 45378 62724 52736 2055 34688 39815 28750 17827 55113 38845 39322 64125 46856 29623 34946 30358 64018 33677 41600 44018 41832 2593 29268 30194 1987 64349 57190 45084 14641 3577 40497 58161 12932 18031 18581 2516 43216 30425 43141 1083 28180 63515 47897 12709 10272 27568 26750 47772 33881 35015 3297 19821 52855 8082 10870 5638 11182 58463 22211 28645 38687 52161 10295 33254 51516 3651 23517 20940 10408 45941 52882 37478 20995 64134 40792 59867 26206 64342 14007 6747 17351 53317 17691 45482 4816 23726 8739 34230 62152 60229 10453 36135 36218 63840 4660 59592 26883 41887 20746 60012 28095 36276 26608 42388 21101 44344 7441 11324 24437 50197 54034 28713 25878 51331 56041 1 38998 44422 48260 3412 55246 40576 42977 51863 8754 16058 10314 10321 48948 25938 63679 55038 53212 26920 62902 11067 52185 52703 55520 22417 18014 22482 22595 37728 43519 59618 47608 27215 55242 61443 52985 54854 51446 55276 35355 54314 48583 5852 23278 5358 50750 41242 30973 10430 10735 4908 61468 40688 46235 58348 57543 30074 30284 36465 55911 38109 10615 60243 57361 40240 63059 59032 2494 10622 46706 23514 3151 55140 53229 56085 7429 14719 34476 58899 20190 14527 58296 30429 52150 5916 47201 44632 14002 4548 13922 36044 4124 52423 22350 51934 50483 64197 54000 16770 45985 28529 9078 16986 19776 2715 26661 21331 46100 30377 34586 17497 61834 43004 54408 10707 60343 46223 23599 44727 20303 21003 20803 12040 46686 3002 4607 30475 9763 25785 6600 38304 31708 2844 38308 6362 17630 24800 33733 34229 58351 42292 22405 48420 55462 52553 42054 61981 43983 35239 43618 25399 56360 9533 28234 30620 12610 58390 48037 44448 39417 21138 48087 16827 18180 58413 25062 18162 9446 58831 37771 4134 1439 4846 41817 57666 59009 6845 58380 47805 1970 41874 54452 59957 16704 37176 48928 6670 47513 42899 15956 56914 29556 11139 3095 52119 36508 64489 55744 20365 6319 48057 42076 5158 33984 16992 53583 22635 33443 45643 55086 11214 4519 20181 57352 53730 49840 22956 36939 11908 8405 38677 9119 63481 8520 39373 24669 55190 46295 49799 13984 4525 58348 9741 60855 47738 21527 49290 17887 18869 37316 15583 33819 51474 23330 8538 18148 56772 9941 1921 28919 54332 19966 49473 13296 33039 18872 26497 20167 27915 37552 57952 52879 16206 37004 18084 20719 60655 29723 27500 14135 41607 35666 5896 24104 24231 42754 2518 10645 4895 46323 50412 37925 17030 27590 4205 41403 40435 26394 47761 27213 46886 44407 29762 7164 5801 48739 3607 62442 27226 8855 8914 1858 43441 59487 24852 1394 22408 3045 28901 25277 60007 59525 62145 18122 47093 48942 27618 48296 52865 32971 17875 8138 57694 53518 10278 9513 27117 43916 24552 5117 59190 11913 35053 20475 36523 39905 44377 50691 17711 26641 43886 20699 269 5451 25838 19551 11763 43588 32800 58069 64139 2406 20317 26798 53956 37280 49747 45308 42505 50231 45932 41301 42787 5334 48423 42382 42429 10611 25233 21897 30987 26979 60567 46559 7242 10610 30276 6754 28149 15304 6933 62091 36934 39013 30024 43652 52235 35091 1705 41177 30681 22736 17494 60275 25466 31270 34174 59603 4966 5390 51024 4216 51812 45210 19047 59545 48677 4283 27036 34443 52017 19743 58487 46311 9919 17165 15894 23432 43845 36631 23575 35262 57030 47048 52997 26689 12240 13156 622 1249 26891 904 6873 5781 34734 63737 27777 63734 13153 61024 61910 36757 56674 14015 36089 22797 54304 8069 57194 4013 45305 33819 55270 42422 58276 21540 22431 4614 22134 33419 17254 15817 9845 18130 36235 16819 36491 38241 29837 22311 61311 55649 8329 12834 44369 4285 13313 20443 20289 49528 16199 40221 24497 13630 28332 45271 52672 6353 11986 9803 24674 46130 42598 62755 8873 56885 51092 5816 27392 17234 59610 28481 28685 19321 49469 59712 42802 31229 46531 37225 58652 48265 39828 50688 14166 62420 37285 29121 63019 57040 16069 28925 52642 12831 37632 14706 42259 28031 3064 31358 45830 15533 60644 55827 1006 45859 7114 19913 37317 5224 42652 18409 24374 28177 26132 14841 17012 44381 23918 33146 45721 42718 22728 16705 64396 49868 39640 53557 43284 17390 12062 48387 22366 44467 34827 18315 47601 38456 30441 25970 1246 30760 64003 47409 30957 22012 4422 34739 46962 3570 56612 2957 14494 55990 41874 13279 43810 44311 19303 1232 51944 61321 20586 34339 60647 27444 62934 18781 41173 31308 63563 45051 34372 5166 49117 24278 29296 38290 23763 59019 29699 63738 44443 47241 39756 3103 51376 40516 31219 38870 47453 7728 25826 7220 18338 10147 37308 47381 56130 44680 36919 20763 28906 51733 19579 62233 31494 43576 10452 25758 7285 6404 42831 9585 13254 10774 55087 59975 60159 45769 13501 6344 19131 13085 53896 46335 28653 3496 35024 40223 50633 59617 7888 18519 35290 4146 7154 36036 35550 29076 7530 10376 54741 15988 38219 39020 26700 12019 3030 63511 42191 60900 19912 44048 57690 3262 28191 2385 48068 40600 628 6410 32786 22119 18797 25693 43668 19874 42103 3814 33170 57614 37414 38222 45878 41195 46168 5402 39359 33004 6579 5200 16010 6136 24794 21872 41616 25534 11518 22112 13424 11240 23143 37185 43043 495 63845 19860 27284 11632 42788 55795 47396 24077 41034 1152 55385 17367 43027 4356 28019 2382 33949 54565 47890 40085 54018 36388 9271 28784 38255 15709 5644 27487 57766 24094 36061 14135 2207 24577 38648 9826 332 59189 61243 1475 39423 54031 16316 29944 29702 43584 41877 8574 60370 9818 55511 48367 12053 54442 20389 16969 64444 20899 24799 55057 64340 19262 60792 42033 34075 49017 60501 24730 5018 32943 21514 39274 48535 19867 54233 47702 35641 61987 51062 14797 16873 18486 5032 58998 2873 40569 63106 13689 62308 45082 49927 21164 44920 34317 26094 56254 23270 39151 58085 33532 13118 19772 30061 45155 46804 55914 27711 19307 15590 38815 15504 28063 13197 9508 53318 20337 62779 1811 8556 62534 57612 15236 7653 48258 1460 21199 18399 28935 19138 41928 15663 5742 7812 63745 6203 10974 25294 26774 23797 6967 29751 45039 48723 34257 16049 61460 53674 62858 4867 33714 32990 44627 40456 15795 57519 14990 34429 42109 61469 42752 60727 30206 34055 22412 17145 41323 50538 13364 5683 1683 56865 27617 16873 23377 8317 447 85 45110 16215 18473 41377 8157 57700 9163 47146 4692 29413 59781 25314 60986 55132 40291 1068 55857 30222 48232 63917 6621 25716 23133 26135 1078 50108 4725 25390 45439 6879 15128 31246 56378 14380 42470 27431 49788 46583 24757 5847 61524 23616 28793 29146 6200 40130 27290 61358 1926 31413 6932 20810 30507 52443 23637 36038 13882 61365 35694 29145 60634 23833 57430 16751 8892 30539 12830 7465 26685 2013 54675 49890 4788 54661 45151 1744 6543 53215 46884 30794 56618 55550 62561 53885 49455 9120 44453 63148 19923 13449 44722 54475 36883 564 3792 1711 26074 37613 50497 22984 39930 43555 18402 3545 1313 15637 13484 41614 24567 60659 58808 60355 48618 59891 35866 24983 37181 55412 22970 30766 35492 30417 7621 60 20692 251 16278 7115 42983 11647 61108 10391 38238 2544 22008 57871 64190 15948 38085 23086 539 9929 5273 60783 20017 11247 62334 58397 28080 8845 508 50342 8301 42498 52288 47283 5095 33275 44851 15433 26522 30366 9405 52723 61800 4810 59569 8266 41447 22539 54263 27516 59894 49200 22480 57455 52030 4501 10100 4678 1634 40175 23497 22074 39656 6920 27085 16856 8007 29707 13432 20150 14201 3035 24780 28787 45924 41736 39177 56846 35912 8108 57736 3512 46484 279 16443 15833 26507 38009 28944 1075 22434 44549 22434 22780 24245 9629 28125 35132 14705 25413 4509 62618 4403 12911 46125 55236 45359 16427 36722 57838 56361 60011 45418 48980 33179 22335 30573 27701 62827 41916 3547 36927 50000 44509 35104 18887 8358 61658 36252 27784 41319 18305 64021 49418 4587 55873 3999 25913 40999 16954 52154 40970 9554 43774 36763 28250 23140 48402 57942 25133 50253 16629 5080 13537 54910 39185 11645 53224 63725 10865 38958 60878 46280 26696 47286 11813 43737 61444 49626 50316 26575 40598 48710 59488 42226 51359 17686 19653 11173 0 3459255301 +1024 35089 26659 42654 34265 10990 1205 51135 50175 44291 41809 27167 16508 54484 16871 49803 7724 8408 17578 12255 35243 7479 64350 24950 62598 51932 17592 54106 62507 17916 44485 18295 2875 20851 12556 57401 5105 35656 3150 13479 23639 6362 19608 10022 49577 13371 21578 5546 7003 56122 46416 64485 16713 51488 40898 15743 9792 64455 52160 11352 1975 44885 36965 48412 30894 25912 23371 9785 57707 53574 48005 26661 63061 48243 41340 60011 5024 15548 40219 44845 48458 48414 28264 62849 48198 23672 14767 6015 42062 7293 9906 60058 54911 28196 8895 8562 41606 6532 31644 52405 59292 52443 61852 43844 61570 30020 14389 52645 3638 60903 60099 48027 62050 62976 57459 2704 30882 25005 25985 6203 55333 46385 29463 13027 8730 58290 22475 36845 18498 47699 56009 33308 35189 4839 1935 51917 26446 55504 59637 26425 22363 6015 28452 51981 7944 12719 62149 58265 36127 11046 55585 30567 41956 20943 3933 15944 31203 35046 18275 17485 53963 11157 13142 13406 58428 49890 43652 23694 27970 8203 47559 22984 27979 30837 52793 58063 50942 42168 20759 33433 21773 18385 5703 47486 10558 16066 50950 41765 16906 16613 27783 52115 56775 19581 62785 5300 53500 28961 30075 47312 23144 33133 3384 21136 34811 21929 9389 17345 57665 4569 700 11062 20388 20174 38707 47700 40726 11527 45324 8228 35482 19756 43871 59841 6146 8819 8316 36599 63476 61153 18745 24631 33458 13202 33370 27727 32888 232 59614 17550 23624 47384 3122 33085 43746 1840 10108 20490 42851 8135 5809 4916 53493 19709 55842 31364 5273 13371 14809 10910 44557 29326 15474 61068 27730 12796 17844 31259 35745 2241 9647 41426 34384 6642 49993 55231 42312 6921 61044 25996 40461 59080 28130 40512 16288 60356 11611 13309 3302 45576 62267 17334 15164 64477 33492 49898 21945 30934 17093 47547 14518 62489 58837 26086 324 32931 1900 39081 12011 19506 54576 47056 49043 49210 53100 13608 15282 49005 43383 42188 54745 36807 10381 1565 23307 23501 30170 46967 4506 49033 18716 14517 59479 60307 57890 18726 3172 5772 19652 4978 35962 15666 62810 38927 27879 21333 46428 10779 60996 52578 13213 26342 44388 27955 15380 26277 8507 19417 60640 51657 237 34133 44591 32811 55727 60075 44118 2337 22690 61877 45329 34142 19277 20550 1612 29121 19319 51363 25235 47186 46430 7830 9836 2513 30906 4435 9235 34027 45389 26407 36289 9806 43662 37548 50193 29319 63399 34073 22125 49825 40798 61475 42610 18725 31444 37562 8245 30933 27938 12312 48783 22231 24426 29028 6819 30082 50586 6709 745 17097 4248 9530 19228 33150 26009 33347 4856 41198 25574 56073 61491 1313 50695 37156 42916 44759 4462 45823 17674 40264 42175 39126 9545 3510 17488 46392 8688 35500 8675 59937 49278 4014 19377 12793 13919 39105 40328 19540 24160 1706 17364 7545 27155 61127 37320 10055 831 48948 42982 34155 21178 41636 26112 14783 30069 45000 6966 3744 988 22231 10975 11968 4988 33659 19459 53954 842 7178 55285 5172 38859 16621 58397 57115 2283 31431 17387 51489 60586 14088 43342 12518 44394 10446 12817 44645 24730 56382 53794 16451 27044 18248 49087 45112 62858 43774 60292 20947 6113 18798 12923 22876 39683 24647 20601 31597 22154 1052 17981 37510 13007 18661 25875 28992 22631 27883 38990 61032 13485 44076 60892 20672 29442 16255 39071 1431 29082 23100 53417 25865 49751 64142 18353 38341 60910 47662 60067 50210 29643 63503 64421 1124 16587 43937 37473 4269 56050 48619 38540 3519 29061 29818 27710 48706 11075 3198 9729 37089 48487 35325 63420 25527 18083 48359 3712 54532 1906 44845 2523 51598 27172 39228 24 25294 47412 64478 17910 32770 42010 174 57692 60552 59545 385 5187 31240 48786 42059 15829 28787 43994 22699 54243 56033 7769 33277 41949 58732 13639 39243 34916 27954 40927 34556 2859 58912 60082 39004 26222 63573 28622 63805 9906 40819 53604 57959 21879 19583 38921 51200 20321 46292 49348 30704 46201 40869 44642 39865 40095 47754 53724 6025 63091 52332 30576 15487 39953 20379 48508 1000 24581 10815 12438 25240 56238 42740 33253 4035 58880 48804 25686 10133 16057 52887 53084 52546 60021 48335 47282 46286 26945 38709 1550 2716 13495 437 39370 44083 19300 35143 40377 54751 17604 10293 58063 46028 9631 33760 51174 61115 8583 63747 58924 37293 45752 25734 4078 18410 60960 41410 10988 33402 15572 22347 9365 53031 19255 23571 4075 29941 24476 59620 55798 13349 8428 1924 52698 62220 50956 52469 48093 5571 43755 26351 64396 37733 40758 20644 1439 20928 1681 58684 8820 16948 26340 24097 13374 15188 3508 23516 48167 54317 24137 54544 9001 23741 55554 27513 24277 54339 51324 11846 17825 27734 43252 16519 3932 59673 29446 1951 54805 48020 20167 62852 27391 12951 49902 36570 40155 35235 54924 58794 21192 40468 24636 25535 33794 49916 63069 35702 44101 58211 47536 6906 4029 61839 47032 14135 36815 29645 49166 38734 33712 38844 17174 3319 28779 12991 51656 9276 49389 30321 46740 24429 56004 388 7116 57760 56139 6239 62229 64210 11178 10122 320 57190 20605 24821 52441 44596 45050 56127 63121 3968 64021 13949 62274 49673 49345 41165 20053 16641 11558 43109 30390 5341 37216 19247 5215 23221 38892 59264 60272 44207 30730 46831 46692 41900 38026 49551 21996 22592 44396 17086 28625 36701 19939 791 31198 2832 4877 29888 21992 55551 58329 54030 58086 16960 39797 25977 17094 55698 15813 33402 28463 16887 55632 8284 48284 58290 62692 37007 42916 36831 51063 2025 18008 11236 54664 54839 29491 20590 33539 13098 7794 45713 45781 53979 52061 10373 4767 9991 14441 14269 43167 62343 31191 38190 60552 40552 36199 1550 15233 2620 257 63625 37480 33692 5559 13846 9347 64110 34316 25917 45559 11957 58033 40248 5519 31498 36766 61807 43505 33942 62811 52285 26196 15221 23296 30748 22500 21522 964 42984 36956 23467 55863 1310 27415 54950 15608 52991 12169 14589 17603 36556 15597 12705 48523 37060 14175 17041 39598 48171 1370 11422 60583 40153 44865 44157 22314 29295 40380 40297 58561 63071 44180 38492 59546 18967 18354 19883 44311 25596 39222 8825 40606 31599 19139 58208 34936 34132 56175 52635 17018 50660 40767 43966 2961 44065 12279 16416 38105 63763 2005 7058 22095 63550 18164 4248 56050 8636 40289 27897 43615 79 62839 30211 17455 5094 4435 12226 10511 52525 21247 26566 30736 2144 31267 1893 59781 18104 59160 64306 28241 59307 29821 42231 20624 47917 48227 18387 33119 8196 64161 9091 41320 51971 55024 35701 38960 46451 24432 42421 50472 7292 50281 33927 38135 49165 10262 61530 55286 51824 7325 41147 52252 34973 24743 15169 42989 3766 11579 58311 29806 47492 18308 58803 45993 30200 38897 38484 19100 51787 13408 3358 31571 41007 34521 18014 15422 32866 64505 58084 16514 52290 45748 6264 51700 14386 5578 33819 47796 20667 10338 34474 51261 22523 15748 9323 53370 44923 33357 22192 46092 62057 52380 51342 19896 9764 48264 7179 55417 41761 26919 8067 16372 50212 29887 64166 10283 42262 50678 1416 3187 59923 51028 43487 25846 16140 6942 5782 19126 3939 10819 56311 21850 59823 47271 27777 36210 50068 1357 8471 41182 3300 40911 13606 16309 55678 17222 22278 37092 49374 7831 31203 56592 43578 36344 39894 45145 14591 23288 45876 54338 34864 52173 5725 5675 9910 10191 6131 55138 60222 56875 44001 13170 9748 37494 25005 51817 5890 23100 45897 8077 703 25029 23443 41909 63972 26758 16423 56407 60762 39353 63082 48398 49799 4016 4741 49457 23574 41872 30046 3815 46496 58995 39135 40776 2104 58078 31407 18538 22913 14915 5958 35928 3769 39630 50502 49683 62877 58092 6860 11994 61970 33756 46239 9747 46418 24052 59578 7017 49074 10236 41518 1547 25369 59573 56499 21588 11046 40230 52575 61264 5125 45304 59442 12493 10970 45769 18710 13259 26679 16551 33341 40123 8164 63068 42479 12999 11692 39776 46286 25270 4287 22776 45460 13290 27294 33575 25553 49290 11953 43965 15199 21765 11478 12317 19994 14746 19237 45664 23746 10924 55249 27376 13360 20817 63089 28469 26560 38673 25126 48563 59090 37712 47362 61297 17159 26236 19558 28402 41931 8492 30737 52259 7930 53572 12509 59946 7647 57979 60278 26882 40717 18138 18205 602 17752 55861 51784 46049 30744 60055 45555 33287 43803 49751 21676 27210 27129 46115 59135 47478 54769 34597 25571 31333 46829 3004 33699 2002 16845 31359 20570 5657 15962 30219 45700 46987 46781 52 24647 27279 58408 35404 8028 44417 57336 11957 46817 50750 25860 20342 29545 51578 56265 774 53846 60372 43721 43638 21816 56341 15639 10367 5279 20470 7881 25751 46578 20806 53332 9077 7680 52955 36649 48835 47175 62351 51339 22980 21686 34483 20964 62084 29231 9380 20980 48569 36982 28593 40502 63247 40675 2667 14072 41281 43567 55402 22035 20021 51310 22950 60957 54632 2336 54516 1675 25478 9711 15709 39654 58340 3750 45391 11373 37589 47518 13727 24959 30602 7081 35342 37312 34581 46320 9662 61209 12922 35139 27171 27756 33239 41929 41479 57307 29106 10423 20982 42905 52703 56681 54401 4266 53964 14311 51056 26792 35962 57807 39868 26653 54097 20162 7393 34013 50058 47128 3054 55620 54210 63761 33461 60279 37877 56106 48543 14056 55395 59068 39309 56820 6026 15275 51693 14954 17996 23461 35382 37385 14152 31521 44837 25507 35704 58748 26308 24471 58873 52458 10283 8276 20709 47355 18135 41028 12686 17432 5404 7391 3981 55037 5166 61446 17823 38789 23626 40367 30476 5833 28549 51058 6387 29435 51680 32814 38077 53923 48137 26363 2178 21023 29926 34964 54463 23294 14859 33928 30542 39585 10916 58799 14350 38632 32783 38584 46950 31031 29244 25007 31275 36989 16136 54316 63312 23025 11767 14878 14256 28128 22425 28098 33581 35354 26018 50666 44519 296 15076 41611 56713 29768 51781 38507 63321 17739 7323 4063 24040 36215 21359 4301 13942 64174 47016 41652 38022 2607 63703 50364 45515 56126 21171 27176 44376 9346 8796 51188 2784 23393 15501 2393 61939 11177 30807 35955 49398 24845 62796 1636 25438 45777 22474 47506 4241 21328 41957 47302 24033 64136 41124 12500 17098 32924 45880 54882 12820 1269 20195 22760 34060 2282 13649 27160 46796 57853 31730 43244 38939 27257 17914 49383 47539 51594 8825 45620 14291 62497 56369 28156 28380 17782 26765 16272 15742 41735 61537 12710 60219 16516 33387 43620 53147 51484 18112 12529 19997 41739 62187 61180 17405 3472 42215 52825 10910 49955 43962 35775 39414 54650 9352 23034 21975 19115 1548 43814 12414 48570 54395 23879 28424 10521 21528 3398 11142 29810 33768 36216 24913 30021 46798 15150 1040 17395 61706 16892 16180 44494 2784 55739 51410 14389 12250 44503 55443 47103 43193 58983 8215 62551 47510 54142 29648 4183 22660 38 54212 47745 14297 24335 63540 43139 9855 43483 52165 37919 29407 7418 56383 58070 55463 22579 53861 26723 62461 22017 27048 51123 60234 53839 50290 17643 1873 8346 45628 41887 21938 1379 36236 59033 52507 20808 19097 38878 22237 10747 42458 35718 25052 2691 3396 36609 10144 21583 2252 64300 34789 15710 25723 5291 23092 7052 22968 21635 6069 21181 12905 46031 15466 54796 37529 5034 19882 26588 60250 20319 18056 15083 62858 29178 2249 59215 52860 53430 15339 51201 57731 580 2534 2311 7984 35315 5162 29510 62184 41381 36561 29812 24367 8151 21790 57512 40401 16291 42802 14652 8810 14070 29430 54670 43519 48757 50643 21785 24988 33795 12393 19897 31466 4176 43569 26080 35741 26157 21553 1667 63348 35523 16518 13368 60498 14969 16188 34856 23791 56656 53811 42849 177 39564 10893 53366 38465 17234 60925 61797 14065 53016 23718 47864 57624 12613 1838 38003 15363 45875 60761 50148 21586 61517 26023 14302 59967 54012 28432 29166 56366 3396 16931 60696 4403 41603 20601 12883 44631 43249 62689 52077 63413 52473 42639 3770 23746 1961 48114 34478 27317 56574 4348 55096 34639 2462 2519 58149 36482 60803 28059 52147 39407 25293 37309 10648 52317 64359 8117 61340 34452 27559 56710 33468 29117 29668 16677 45952 59822 30942 12021 6384 54330 6417 4506 11085 53146 2542 52763 57403 27588 43093 11809 44138 33551 25091 39930 62892 44046 9183 11703 27205 12725 15232 31050 9562 2419 53525 5995 18792 30289 64383 5874 14061 32810 26170 27840 20019 10169 13573 5362 15199 19710 48495 52168 43290 61449 42827 54533 12222 45086 36662 35413 11209 46706 41556 59892 11767 47105 4781 39406 46655 11333 62167 7298 61542 41523 21513 43320 17259 7133 34273 64086 7881 55462 26825 43100 37439 63154 31622 9527 20946 61586 41722 9022 48192 42364 24353 2051 44501 9674 990510763 3485428560 +1024 31061 34259 34109 38336 7963 9849 2068 48081 10736 57183 2002 47518 27751 49108 43958 10727 18742 61381 21952 934 33498 37639 51366 24258 62798 24975 51821 35894 2603 25120 23209 43371 58303 22906 6685 60557 29855 19464 21380 61212 51092 13920 10968 55115 14113 57249 44544 20293 50817 37939 59805 48634 47349 10734 25567 39092 47787 10109 47094 47966 45175 50094 4035 20330 16564 37603 33478 36389 58886 35943 10806 61906 59405 7544 39684 48368 29215 38950 25078 3449 4791 16459 45084 53894 59144 51025 34398 40345 24525 24999 48478 37530 24589 14334 1386 38340 60341 15289 28021 52170 19337 23019 34659 41532 58979 21626 41869 12603 58890 37308 47933 39154 61328 46452 57458 23188 53480 55789 16278 18751 52814 43343 51282 56581 1313 62470 13193 37651 6562 45639 29785 41591 49224 44880 35807 24739 10323 42749 59252 8101 54858 55343 55075 24883 29119 49055 52123 41086 26292 45193 52571 24503 59839 6953 6501 11331 47219 24118 34550 5823 55357 24619 12875 49340 4128 21898 5472 30379 49840 4955 21784 12231 22533 43632 60618 62593 2384 50225 8904 41184 18938 33537 4683 34719 13087 29108 43694 8990 5089 57462 24773 30030 17440 2405 3514 46270 34577 1141 37470 57027 62746 1952 36026 39626 11614 49939 37192 8442 40941 10044 11518 12155 12608 46298 4788 61517 34883 4031 40272 22954 1040 42059 16806 25959 43544 34978 41066 41143 33538 10766 26200 18511 14348 40517 2797 63363 61569 20538 12689 15105 41736 61640 36729 11491 12440 53779 6912 38555 52434 35168 3887 34792 28597 25210 17222 37098 45611 30994 19299 16135 17057 24336 60942 31664 28603 41567 46081 19747 16261 30339 33182 42627 62506 28295 25893 15705 14981 62290 46434 1423 54060 18354 47237 39525 51435 18815 20484 30226 56115 38041 31083 38739 42439 38446 40474 40874 42253 13581 30690 37388 4291 33960 43806 14373 22365 13111 30301 672 38778 61659 33344 53044 7472 23387 12774 34974 33999 10944 24878 62947 54962 3299 39746 40969 44916 58637 5083 25390 5776 31580 40175 20544 38052 64498 42172 28104 61758 38105 34567 2496 29904 27489 12264 54591 18737 48669 2148 51361 36300 50779 40834 26836 43753 25201 20895 22658 56228 49110 34327 14911 14197 13208 10321 3605 25356 28863 45987 370 62769 45224 9965 62671 9930 37778 685 64176 39627 27195 26277 28951 36761 58903 46683 13832 28407 23577 29918 21520 62459 45473 34124 20684 29674 46256 56435 48877 43678 13712 10068 2893 38567 53695 52960 25174 28406 35853 46957 64479 45627 36550 316 21234 19818 34489 19181 2920 22500 43911 34906 46148 34826 53391 52846 36452 49874 3558 38431 34219 58849 38895 62064 45707 33239 59983 30636 64196 38885 36666 21993 21612 26487 55010 12370 51380 847 4736 9083 755 39753 58511 38791 41156 28707 9194 1626 7174 62617 40130 1057 52507 7923 58951 60586 18613 58290 45866 23164 32789 20160 44840 53822 18961 50807 61601 44886 23729 62225 23423 36287 28321 26926 34142 32858 15612 9048 31204 25591 9740 3352 45131 40504 43875 10770 55978 18086 15102 34109 28854 34257 35124 31274 18961 23547 37877 34576 39236 13904 45660 63029 54561 63004 2195 24997 2657 52725 32885 46006 37209 30203 24516 1175 34207 35176 47310 22058 47460 46067 34449 27873 20063 39214 11383 55765 6982 24048 16282 20180 47178 2287 8244 23761 2631 50801 56950 25506 5420 25579 5681 49663 47102 36 48233 36186 340 26615 37665 49482 42639 52469 4617 15282 20142 7936 51192 19120 9748 42553 55737 42971 29485 38364 37432 18921 57474 46265 42711 1120 28213 62590 11893 60306 4579 33990 52411 60354 28436 37399 61711 30389 54912 47760 42454 25713 42918 2843 23591 13387 49533 48729 35511 53613 37693 45643 1844 26099 37003 15464 39627 48130 41037 32930 42610 21476 6774 13202 30560 61522 56475 52979 11827 17828 13743 26008 43895 15591 38215 16490 17909 53969 61026 41929 16921 20723 2839 19230 10485 12107 58993 44976 63136 13828 24670 3291 28126 36211 21201 15499 8948 2276 43455 58382 2275 21410 40943 36034 4338 24518 28579 4860 25971 28662 20161 2415 58560 2409 59984 63808 54072 1819 34308 62610 43511 40776 10826 6003 62240 45862 23193 29190 19790 16274 58432 58028 27918 60738 50824 64217 28843 18168 753 43109 41244 5510 60676 17592 26419 2331 56259 57289 51316 8974 33776 52511 8262 12427 39337 48478 24690 5956 52742 63467 54733 22052 12445 3261 22738 12769 23689 20833 8487 17732 3143 11367 2486 23862 5688 6715 47963 1241 55046 34041 63746 34019 25599 34560 21811 44258 51500 60550 43393 12049 3108 9202 23043 19910 64385 48631 59390 6548 47075 50563 25773 38920 41320 46668 9120 41431 19480 39568 20400 35346 27993 54477 54582 24653 28332 45605 49908 60041 4314 4255 33668 27936 40770 45252 7241 8357 50682 15925 14315 40632 13741 17565 3879 1435 27323 47514 39214 49324 9265 50061 33053 36773 24367 5696 25366 41415 23469 24592 47196 49791 26255 56951 37056 20351 14337 38426 33727 50438 17617 41206 41349 59697 24349 8694 1918 43907 22502 22760 56751 59715 36987 59152 57716 44961 55325 27066 17020 12502 33955 55647 11532 3374 61848 11358 45840 3488 11753 49560 25843 54485 11298 27117 53344 4995 17364 37310 44079 58723 58995 59351 34610 27948 20319 16539 5711 18678 58451 30671 18580 51751 36242 21208 60793 11491 40551 2338 13665 40391 3047 11585 19768 5168 44887 55415 15682 49008 60578 62595 46054 38329 29932 19168 49744 44681 45161 27546 15575 21968 41904 23801 18441 4488 3068 6327 31108 1369 62505 64222 58570 54341 46649 44393 28296 28233 25384 2489 5955 54233 7656 58508 35072 24075 53847 5676 10329 9915 63626 8357 1351 21811 47612 61744 54322 45232 32776 12566 41203 39001 9434 42100 1413 1620 30856 25914 57203 12011 45492 40926 59426 58221 5911 55517 62278 45056 46082 7642 55160 2977 23705 34041 34305 51056 2437 59000 40844 57665 45241 30030 49586 7382 26162 33756 27131 44600 56918 56036 23114 23822 45859 15607 3366 49190 31071 932 58665 60039 60628 35578 2111 990 26747 23195 54007 45191 44848 20434 2109 55114 28444 22826 59263 52024 36183 14338 6911 49816 35232 38637 8465 21993 33819 45725 30940 51383 6820 22221 40810 30292 54068 1086 43157 46481 58849 21938 24251 47922 53801 6108 18160 44276 50518 41873 57900 940 41712 40255 6034 9990 361 21927 63242 35897 3285 15996 12399 54957 51750 22507 48417 32783 62374 24753 12315 42504 14193 16131 7153 12357 29646 28529 38726 13932 53619 4964 34029 51833 45163 62863 122 38475 40293 5610 50594 49194 4180 25337 61030 38459 63279 41738 14175 20159 64332 49727 45753 48867 60001 50261 62947 12637 1787 58541 18004 30364 19732 40897 8502 43148 57253 17706 19143 8082 23679 60676 24919 48632 29877 12362 34125 27390 45281 54277 46301 27644 46388 40520 19648 1726 25894 62164 32884 15814 7136 64042 41304 30060 45234 59881 3522 58143 20930 21541 24416 51222 20222 51218 61698 7772 62013 5556 48849 40554 37298 34261 34822 62525 37667 50145 36920 34920 565 37000 36796 6308 7414 45767 64134 46311 44486 3179 49829 2421 47275 2742 13650 6602 3214 39594 49895 47182 13988 64065 60779 57322 4487 28342 45802 46555 44006 15422 61977 61193 50629 3422 23995 45451 60012 12546 37112 483 61351 53141 30190 46462 18158 52226 31532 43831 13733 48125 175 64199 47682 61249 59693 62054 24174 63437 26137 50688 15246 9141 8694 55601 21665 1954 3092 63709 17885 7949 30980 39804 61185 42002 63655 13843 42228 62509 4308 34560 16720 53938 61893 18170 50668 10752 22566 31639 55219 54787 24396 57491 34339 10516 46971 63899 14316 47729 15455 27236 33739 33467 62310 55478 53556 33761 20731 26911 45358 34216 36940 42667 47286 130 14357 58485 64344 34564 42372 46309 28829 22800 13753 4700 22053 12075 39990 47947 18669 4068 11183 39676 5567 16134 23306 23746 52757 52170 45615 31333 9150 46819 37132 54859 29597 1835 898 63103 49077 25844 37948 51390 50576 36034 61203 6752 62838 25166 9269 19555 54586 8576 43481 42394 5885 27322 53083 41382 52178 8380 48031 57924 61874 45834 7376 60178 40353 31284 53976 33764 58299 42069 27746 59825 35220 60218 42800 52062 36089 46889 35084 44029 44052 37481 18491 25895 22212 56583 35958 10340 52957 55470 4768 58082 53984 60461 9360 46103 60247 10922 29972 15417 60226 45283 37512 11004 33875 31172 14304 29260 39331 22827 57126 62503 56598 46509 52174 35669 30708 16768 18088 34675 44772 31626 2128 53626 163 231 60704 4300 64459 9614 49065 25137 55947 9958 52527 16639 16778 62414 43417 41300 7673 7851 527 20679 13736 41832 3748 22182 1670 3306 8261 28949 3619 30052 21808 46324 35856 11909 26436 62175 46052 27462 61788 57589 11520 46592 7696 5728 26674 20024 36727 56698 576 29696 14317 12895 34072 58649 20571 59546 54309 26214 15109 51786 26718 34615 51513 33058 60840 50562 56636 40590 3380 45249 57504 45389 18547 12232 1073 23383 45607 4172 38965 20135 55869 10180 45508 46260 27868 21335 11386 41097 40541 62117 16880 25894 9789 36866 36201 5316 42684 63419 61312 12092 14774 54943 36423 18364 48026 55622 20005 23316 34162 53593 38832 37746 23515 33208 41419 45202 57314 4593 51323 51730 4468 28008 33641 62094 42101 2568 56600 39439 10139 22153 43226 30853 12834 49492 39785 60338 21605 55645 37099 44270 55469 53671 39851 5704 17287 11864 48163 15552 44975 6300 57834 39847 42312 19190 14716 12991 45693 23695 29947 48946 40117 17346 42795 34286 8014 3468 1998 12810 36615 53584 23410 53467 30122 59669 26157 11178 49338 47572 17138 37140 22520 21848 2742 5442 48275 47380 9810 38743 58842 18295 26283 59105 28196 10426 49443 4925 26254 49495 1167 49221 37841 29500 34104 34151 43856 14324 29928 7719 27354 58113 5456 40756 21900 40454 44931 4919 23486 57638 63281 55565 44034 6354 49233 12151 48747 28639 44072 51254 61995 51780 59742 50161 38850 3696 52190 35095 33706 59522 19248 4367 27788 21141 35281 44055 21315 2132 18817 40434 58550 52360 11472 28627 28698 27785 46486 5507 17656 45353 59074 34128 10540 8680 30949 43762 9129 25543 23989 33963 41061 5759 5246 26076 3267 9415 42360 28607 30685 58127 29600 47978 37734 42302 58239 23779 36728 41492 33800 14831 40782 44547 16612 25989 52913 28229 37872 10238 642 19967 60236 21810 38862 24853 43380 36308 59040 13031 10268 813 51964 63742 29569 53668 19580 27159 30311 42147 28858 39239 46615 59470 24577 24024 12041 59264 13722 36850 44686 61870 46752 17096 45702 46409 11760 51401 4831 48767 7089 4172 56098 150 33211 36402 49046 37680 45182 38702 51136 47592 63002 57692 913 55491 29012 28197 59319 50050 44241 53879 14444 53482 881 3600 61631 55886 3760 3626 11640 25701 7976 47489 4271 9324 2165 12929 34625 45893 45713 29156 57143 45292 7310 16577 41038 22692 50437 38164 35664 46452 43721 12780 12441 16443 13523 57463 30526 39009 61149 36573 47163 60029 1654 63995 53229 63956 53973 52262 895 46243 5094 18032 33435 19539 42159 23981 50576 30807 47834 43916 1697 52270 50321 4586 26711 28442 4964 42856 47466 9238 22893 6070 47251 24116 28440 25592 26588 10669 40789 48561 50109 11565 43781 25568 40828 10691 29830 42632 27790 23952 48823 1811 9215 16832 57873 50376 55055 34358 7038 4623 44829 60498 47999 21881 19084 55215 39449 829 58231 54727 15772 18348 21495 38573 46554 36529 38224 17654 13295 26025 47335 55697 15866 13652 18514 5758 11320 6219 24644 907 47413 38926 40213 5562 16557 47105 50390 26386 5855 15078 18685 45357 19532 3960 50491 17338 17753 55704 7698 37343 23938 46616 34720 39416 40726 23835 59921 1454 4643 59538 48849 28612 15474 57028 32812 48233 2368 54119 41108 30805 9980 37290 55025 28524 55174 5668 34409 52109 15195 17822 7942 51796 43451 30377 11591 6200 13636 27220 31379 47523 15129 12254 7961 64415 17606 5293 54308 20182 36310 7994 4805 3772 6804 12019 59743 60085 30626 51638 17984 37630 37819 2949 33782 33371 45060 61975 12264 38560 16579 11592 59370 57547 50431 28885 37945 46462 19838 8514 29495 55387 8281 14591 22187 43225 60506 57560 4797 46413 30100 50510 64278 11691 42086 37765 1193 60713 35883 24704 41930 20222 38530 63829 10120 59929 16996 30189 55438 16061 20244 18271 6415 26172 14775 54695 20252 50777 13389 59280 53918 53903 29387 28237 1969 22337 19018 34990 28421 33379 4341 59651 51613 24504 47694 49068 5332 2645 17583 23408 56236 34610 10979 41321 28986 12292 22379 11708 6928 3911 20351 25602 59801 6101 934 54163 13550 5808 48108 20521 31081 38829 35010 43427 38761 3269069211 3468893132 +1024 47313 57203 62062 14743 52641 44727 16904 48505 44936 37790 3818 2131 39147 40107 38850 17750 22686 34450 13728 40750 42213 49051 30259 54412 45275 1900 8452 27581 43574 26633 61998 42141 10803 15597 38858 22579 11599 32876 54248 22209 2242 54592 11590 36171 12594 9021 22078 11856 43238 56424 39701 44302 20763 54747 9195 16299 21419 31690 40483 61610 27039 3393 1527 51465 55086 44887 48809 24335 17996 25771 37500 22288 45592 13703 52831 39625 11630 23983 43251 29664 47848 34321 36969 60895 5002 50740 15256 57131 53335 14670 31594 48721 62458 12354 28385 48589 9281 13649 29848 16233 48457 33382 33718 12269 43768 44712 60608 44686 57486 19083 47760 8104 34790 60760 29283 5768 31722 37358 31203 35977 43144 27402 30840 31260 21952 53301 22889 43225 48959 25999 21890 12576 15245 28032 46285 58516 27974 55100 23674 57416 7618 53615 62178 26283 18768 18653 64247 38838 16561 46912 32925 41365 63589 50420 55406 1544 31073 60646 16039 28597 52669 46280 55650 29345 55705 40109 31537 17536 7543 15585 28185 15335 56629 845 48784 467 57339 37589 18189 30760 9681 38212 6188 45667 19043 28267 35252 29526 39417 7829 58520 63727 40778 45295 24162 18676 62620 58441 17465 19216 8550 42821 18436 59111 14834 10429 50297 31266 19593 10030 17487 31288 29301 62860 57774 1487 8524 61935 5550 16814 15861 63836 51536 11735 20012 20784 21661 18126 35981 45273 641 16338 10849 32876 18244 61309 7082 44479 21325 17311 26120 6776 37614 44924 59409 29272 4152 54604 1511 51306 42829 59519 58640 16336 19729 60308 12301 50488 26939 3921 27812 10598 49973 38959 16785 30699 34121 51919 46906 55262 12778 48450 44388 12635 28527 49773 53556 22475 45114 48491 42541 61081 40819 62276 56709 16094 43025 38641 26131 406 42207 28024 52662 13430 31740 54159 57260 26945 31665 28891 20659 35815 24882 29987 4268 8252 37283 48074 58358 42055 29700 40727 19133 52121 34088 42050 14691 15481 39466 42586 36974 21320 63165 55700 40051 45002 46436 21115 58030 42808 19197 44412 11053 5119 18284 1691 33630 20852 37867 21536 4276 19497 8743 34600 20273 2391 12413 5312 14465 36511 45117 40779 40557 13160 3406 36655 19142 7139 28095 19246 58576 53793 51022 23799 9189 34226 53149 26832 54585 63914 26430 47089 51781 63315 63382 40787 36505 56956 33592 28889 15997 5686 25348 20623 6289 4151 30583 4571 2295 17435 13282 32947 26138 7182 44086 9014 20104 61432 55426 14478 7740 11957 11290 60781 29696 43132 20677 12643 33930 46264 50803 35454 46578 21436 58058 60380 36609 42940 47491 37426 61443 21241 12539 31520 39888 61549 386 33135 47167 38314 20126 28330 35288 17376 77 35106 9004 30614 38871 10750 2136 17173 38823 18182 19460 5682 55904 53427 56499 13898 5777 59464 5905 54896 28765 45358 15094 47567 58606 11297 64292 520 43692 26086 26236 8994 19300 21200 8903 49437 14904 63225 20121 17728 24197 36025 40845 16812 20560 15636 12122 26966 50798 50456 59589 64116 49051 50947 56555 36578 44456 38818 17166 28926 27799 51562 44955 41783 61038 36313 52709 26703 14781 29000 43338 52794 57343 14717 23633 35281 53340 24664 39815 47224 47615 60726 5522 14257 42797 50273 8117 60752 56591 35613 63515 59922 9018 38866 45258 40065 28673 42632 51350 24966 34420 3005 24094 17891 4651 16944 42734 547 61896 57939 47581 8354 5310 52820 40557 11441 37900 46210 52156 31717 3982 49055 27076 8694 48717 49599 49131 53795 9854 34982 43708 24254 35747 19996 35294 35762 7899 10097 13977 10192 55051 48820 32790 23378 6362 53477 15159 48377 21062 35213 56124 58293 47341 6136 39387 48941 2722 29050 20880 13354 11251 48680 6918 55937 52542 53319 5778 12905 56479 62481 25275 21991 34372 39843 26357 29710 28748 42143 35045 23270 51651 8418 5353 35036 64253 14545 28199 54230 2941 24808 8571 16869 21052 42966 24801 29998 14491 51690 24890 35092 26951 44179 28790 2734 38493 8110 51175 57280 36136 30309 23697 56769 56944 7310 24510 30791 17077 50925 3190 44640 55392 44233 7298 7425 50374 24738 57502 27872 1139 17074 54123 44568 60591 44810 63870 11750 54998 58822 12382 36596 14173 50295 16692 9850 8191 37318 64097 18946 52721 22959 7527 25429 50010 47045 3090 22689 8536 3723 19074 17881 62054 39633 34599 14682 3161 9131 19003 40278 12400 28208 22652 39620 29980 55198 42481 51183 48504 34040 1637 37666 60234 30223 59103 24970 35967 53484 30245 38725 53533 12447 17945 37384 29906 10525 4775 30390 18145 62066 55865 8247 24197 26607 19736 3378 55327 18730 40191 25657 523 59009 5798 19666 24729 43480 5992 2390 51377 1294 55648 16815 34030 53908 57833 21108 54280 45022 31534 51654 18539 18624 27887 56344 29777 49372 29286 24336 63223 53354 28091 631 50550 61156 63565 12246 46843 15519 64060 2388 49298 44099 54741 21484 715 3222 59009 31638 55322 49134 15923 62516 49735 39724 1791 60804 27008 40553 35666 14147 54858 37393 44790 16265 8653 31486 16859 42107 14652 25260 47475 747 51711 27711 11515 50571 59578 46230 20988 49917 27776 56911 13335 56468 28845 26086 64347 20116 8752 31415 35634 46119 64027 25811 30790 15973 7322 31008 5874 51272 6774 62343 50961 57615 9330 33182 19182 31184 59496 38358 8205 2681 4390 30168 46961 30899 9380 18730 6935 15247 43488 38533 45346 55857 19551 29434 21159 54667 9990 31646 6837 57927 12164 17701 6996 56621 59650 19719 4881 2942 54381 6209 15577 37743 20693 26990 58154 57807 41228 2694 53508 50299 35076 60918 38937 53366 3858 45648 26293 47862 9154 5890 39406 30632 16905 46392 57105 8842 22276 6520 27780 40218 62562 21644 47647 59897 23437 25332 28622 8585 4124 21311 43522 12950 29840 44984 20526 13509 12778 34419 41941 45774 17524 13295 40862 51057 33451 50129 27222 4596 16039 55958 45774 1613 63601 43812 59579 31589 33485 62291 63757 646 8111 22182 57060 46049 59721 36258 12066 50716 51180 4056 13040 58168 62275 46007 36340 31203 12898 9857 46118 14445 27946 63561 38382 37603 5658 21785 19392 25816 31189 398 44576 11732 42480 6124 40374 54548 34348 14169 41826 40383 40775 43266 61173 3468 37585 35622 52678 45151 30465 46371 40528 3396 50357 20758 29431 45475 11296 25979 48757 36232 45875 12960 57742 59769 16054 48001 60139 38834 13826 39995 20721 24984 2090 11781 52759 29136 52630 41245 54551 24381 39638 43715 27196 1339 19647 4551 48488 63996 21117 50980 47329 61746 47458 10534 7452 9064 24738 50250 38222 10634 34394 28602 31577 60122 52859 4857 44788 56112 20652 62014 21937 57583 31489 51222 47242 49307 21665 48246 24635 11004 64421 11801 39404 45853 24533 44289 43814 24014 48298 59292 90 14247 37670 5534 49757 57148 49671 54898 30129 34700 28828 23778 52577 25314 6369 50709 43058 26798 38333 18893 54601 41907 9926 59152 44765 30983 16285 44943 52876 14553 60418 23734 46263 30072 940 54051 8931 18286 44618 25895 16813 3950 50178 43636 57148 43808 45653 41210 24761 24788 8695 43819 64299 35039 12152 36009 57530 23915 31478 32891 14329 30274 22555 11957 7211 56398 42645 1786 49425 25527 47368 24483 24041 49355 53496 4954 39231 61423 16056 50295 52485 43185 32840 63094 3976 46182 2353 5293 3247 14010 60224 33642 53735 21499 56828 59910 45009 13434 57993 30395 63195 13405 46605 21824 26478 51337 46809 59069 30055 41567 54985 42331 23502 34475 37499 41861 34351 38526 18016 53284 45955 16879 9648 11141 2720 34561 15083 4217 42950 33407 39000 5671 64445 51489 42007 57060 3161 50666 21447 53411 59236 14465 51281 52838 1513 6883 4935 45461 61836 63900 36881 1552 15411 63621 8235 41132 25104 26931 63774 16732 34257 39319 60938 14841 33731 27246 36962 62697 2705 15128 47425 8573 15418 56641 51203 30770 39290 36475 57117 14009 13650 59061 11557 23606 25229 17203 50187 54219 28823 6257 63570 21577 2434 45812 38366 61840 39038 46644 23709 12013 5716 47888 47324 60778 394 46944 24602 787 4322 30604 10649 37411 4746 61672 59450 44640 55600 20733 39954 1020 18565 24571 8627 38850 39110 49145 12465 50130 43587 1540 55835 58466 14752 19171 47646 63890 6390 47492 17584 19470 26177 42169 49139 5792 29498 13443 2970 53347 19634 38175 9687 46007 61806 12400 60448 63791 47262 5240 20333 41084 39293 21400 64121 62390 49313 11456 50069 49471 30207 3879 60886 38484 42243 31590 57118 62320 44327 2233 60049 55600 20211 12358 25301 22953 53997 63998 37775 63513 20137 2509 9090 39028 53192 4509 40973 62480 43384 8158 63318 55384 63887 62414 62893 4257 60142 47754 18652 9159 52851 37539 20443 48317 50260 49818 1445 58728 44443 60796 22183 20501 36294 27179 52192 3104 48074 40215 5348 16045 16126 62141 54907 25522 63148 106 48742 18753 24758 37814 27860 43803 58623 12323 61358 494 35755 17731 42672 50160 16654 15422 37426 39850 46410 40172 48571 37430 45992 36830 13355 14230 19915 55683 60668 26479 14116 51446 54197 46623 46517 23569 25970 49626 39263 16692 50155 19254 52641 44168 7460 35753 31185 41269 47085 56005 17873 26333 20940 12389 2210 21009 23803 11176 53010 21497 27472 47960 54306 16415 45904 61346 35606 25581 50859 50588 35585 63550 42269 21830 51215 63917 7048 2143 50523 27545 35941 56512 5978 16302 5547 57429 6858 59804 48639 59370 64064 10727 52133 6644 34529 58270 9926 49499 10747 10948 24946 55323 58708 57359 7265 23331 27345 48339 5481 15587 296 51731 41923 51167 45833 24755 4398 56338 45610 57909 34739 60718 58061 39946 30189 57415 35734 46230 22080 22765 40875 58660 38859 11240 14982 45362 38658 51191 31623 2374 62905 29273 7076 11404 35320 58650 40735 41255 32859 51601 52754 52427 45745 63524 27022 671 39774 13432 33518 11703 25417 48120 6455 19552 15717 1656 25089 17580 40055 63054 18377 15133 45891 39928 20926 2576 5505 36087 53913 2777 3749 47723 39757 26143 49424 45573 28715 19173 39140 8459 11750 13044 50577 38402 58169 38772 38433 7505 53518 37798 36484 46085 55310 50170 19262 39256 50028 31529 3467 62672 39819 24246 16078 29913 12528 2849 61235 12437 62866 36033 46617 49800 9166 27879 36497 3123 19488 62137 9524 1572 2768 13074 61339 13992 1286 43133 2014 50894 6873 37208 23954 57275 36145 23515 15225 37783 5058 14974 12086 9837 10456 37430 34459 48871 38487 62545 2822 48193 38201 10742 23003 4503 53037 55736 1980 45522 45583 56277 5290 17386 6821 11122 36120 36715 21696 26753 9276 13272 46383 15105 18557 44982 51828 34095 24271 16774 30401 24585 8999 57713 28846 21608 63999 8561 10378 60635 46836 27039 33515 57166 6741 43454 28920 12460 44701 52980 38621 2089 55384 21447 56974 2631 7315 36967 13889 30192 1597 7494 27940 41991 21966 36873 22821 1559 18988 45873 62686 18825 8644 7113 14504 28868 27324 34936 23794 6476 33257 5033 4913 17669 18123 12245 58725 42416 45304 24452 57578 15135 7781 17982 6310 60355 45564 37636 5890 11548 27851 43328 44267 15962 43031 12912 62135 43125 2271 9540 33869 50573 37495 21305 18581 33393 35650 55067 12580 19598 8701 62743 53204 8376 24747 56925 42711 48360 51556 60745 45272 20536 61579 25298 62052 61685 29031 43259 39438 28721 52119 52004 216 38035 15733 11862 15227 60331 61077 48568 52967 2598 22597 6986 41089 47410 61030 8207 47012 21321 3439 4294 25744 23172 28058 49163 58116 36907 29726 40995 53732 30582 13243 48990 59479 9053 40123 51899 33876 47030 894 10948 14057 59802 16914 60673 16730 29134 57461 21296 37191 31722 24332 31687 13783 63496 48628 3082 35555 5811 42266 20750 57721 51584 17144 41663 18978 49405 44892 37219 19314 19307 40540 16688 18661 24393 6758 6325 22820 48328 29366 62075 34622 23590 44205 61871 57993 9333 57514 34873 23243 3799 21893 40443 61928 59477 47774 43282 57078 48311 5123 49977 60225 43754 11288 13915 55349 33372 15948 53008 12566 34677 6287 51057 52502 3930 10056 53006 30557 12980 44172 14335 16146 56117 50993 64251 23341 34738 50932 14823 25029 16658 44308 62289 6260 50976 52742 30213 35016 17396 40670 13669 43005 22056 21843 15482 40029 13245 33400 33318 35803 43354 33792 34613 35884 22998 5548 46586 8010 525 41659 27199 26124 15349 39545 48022 7877 12546 21464 34899 43580 39534 27999 6747 35435 27915 43050 50156 47709 60478 25525 53619 4040 17407 41274 12604 46703 39494 15578 39070 18153 58031 59221 53504 13580 9456 28717 63164 47359 42521 41674 45879 26945 61961 57379 41871 18602 48456 27192 38989 40930 25476 6033 60808 31231 23800 48291 60990 58505 25522 62443 51159 54638 7846 53738 36410 53493 48929 34584 17180 9600 36162 4495 10969 3351462535 1315264109 +1024 28319 28027 62744 26084 52089 58613 12844 19381 35116 53333 26850 25698 61032 57103 33981 53043 50221 33947 16660 17089 16447 38648 61339 46414 58262 59383 50656 7621 51111 28645 34290 8256 18351 29293 17940 27203 56640 14318 9178 57474 51110 54047 63838 38650 3698 34863 38190 23365 35171 41609 41463 54703 29513 45951 56246 43304 19124 26904 36404 62133 17041 23483 47446 64449 34365 35979 54873 50318 18370 36293 8244 47755 7381 12875 60637 5522 14520 25476 7640 42868 59037 277 14024 59182 53731 24095 58558 41826 62325 13786 29501 41126 14622 64388 7876 37133 38082 59439 7378 47897 12701 46612 1168 6303 40278 55350 64249 11290 14708 63003 35009 28657 23489 767 6820 34051 30440 45495 18218 55132 21537 54573 11691 31137 53580 61268 30051 35579 26797 7224 34962 42671 29257 58116 56148 60924 49690 41185 57208 49401 17200 44850 61386 31449 18123 31197 48493 36853 20816 23544 11244 2218 21875 25967 61948 2812 22112 26270 41417 60579 15585 52378 46543 11439 18058 12245 11557 53923 18247 24688 36880 12659 36917 12802 10576 49219 37750 24045 30945 57139 52236 16481 27216 2282 40069 56236 36747 46015 41286 18291 23476 24674 49752 6953 47517 59315 1492 33764 27904 45124 34556 44722 44378 316 36185 57178 23407 37395 34661 9063 19867 11376 43767 58738 49335 28065 24024 39514 38192 5582 14033 49542 6106 20494 1548 37563 23153 38296 64002 60699 52885 992 63035 55165 45673 3727 53489 205 7581 32941 46434 13903 33484 31324 5788 58856 2626 37133 11436 57882 53795 55329 29171 28662 11764 57781 50983 12098 1636 8035 32903 2173 30633 21694 14172 572 21527 62666 17096 63728 15154 54684 61992 61593 2681 61703 49659 25790 16279 3642 64434 11019 38590 60585 25310 46830 40765 948 56231 12329 36838 13066 29935 18977 57657 42160 11336 25451 45715 34325 43053 57176 15293 43016 48472 10993 40190 54874 54109 55420 45275 43700 37888 1025 41290 51734 30150 61468 45979 11478 22214 39804 13577 61107 44807 42574 64123 15587 53217 27312 61743 2975 4940 49625 49710 52819 55410 6837 57555 14987 53048 40891 9312 38298 1417 64278 8124 11330 56457 35919 48640 21676 49656 14405 8856 36465 34679 45252 3636 22462 59603 10007 49739 39711 25837 61539 29280 11697 2987 61833 21803 62934 51256 20370 1295 63212 6338 28953 39940 53236 59995 62641 1248 4672 15501 37278 21465 53701 7602 20427 15994 55259 43651 47337 17460 1500 1062 19000 14987 38676 15716 55584 51113 45385 34182 1729 28244 14886 8585 4855 1752 6651 23876 29680 24161 45916 60914 19318 53521 7580 1002 42478 45551 17309 63520 30985 20923 36539 3245 8629 26834 43905 6461 57432 37241 22387 14991 29869 457 28658 57793 22694 2628 19051 40509 1900 5635 12948 34549 49317 52542 37464 43519 12093 39214 31107 57268 36989 4419 18081 9444 59690 57892 7529 41442 49319 38872 4633 15887 8093 28127 21069 38492 8607 52988 38377 63337 15403 416 18573 1474 26408 51621 12366 35811 51712 47127 14314 51023 3058 53941 10802 38696 9249 9536 56387 21393 27315 46389 48448 43951 40814 59563 21973 16229 52437 28968 52685 18434 64425 39287 24063 47992 22712 17582 61199 20197 30551 62588 59421 3484 56671 14175 13379 6252 57990 37541 9959 46001 34221 37575 27190 20878 35148 54364 51125 58207 40956 33611 47809 20737 49991 9614 13383 24529 51696 14487 62432 62095 17555 28377 35862 12785 6573 21049 18087 60204 3573 8005 11405 43168 23642 45129 30187 58393 15914 58729 10960 37189 29334 31003 18900 34239 37293 52759 37782 18157 21693 36724 10706 58724 57240 30746 55849 54401 51948 25390 47458 62093 48157 14454 15781 11400 26611 34762 44668 59995 61148 31552 39015 63681 12419 47910 62074 7538 27541 23055 2213 37120 54478 2954 15155 7763 40706 50986 41153 17661 8048 46716 5609 20303 1926 62374 60439 22127 48471 51131 23275 59148 8892 40855 45196 1520 37199 27772 35775 13460 41005 47951 55949 6015 33409 44832 3033 30366 36405 45938 29769 14511 34951 50555 22610 49468 32983 59565 58036 18462 59470 41867 34994 16302 33894 61637 14819 60955 43457 2879 36078 56313 13575 18500 10134 46752 64131 59854 11992 39380 31577 28584 48349 44909 16371 28295 26597 61290 2051 34159 26295 3016 39403 49692 3800 20184 37069 16181 28405 24256 12390 29750 2710 5681 49479 23405 49530 6520 16157 46163 36890 9588 60132 40393 49176 33448 45424 33680 34585 54769 56514 6326 34394 5223 30469 35044 56429 22800 6515 19135 3929 27203 37863 58336 13076 46181 9364 39455 10919 36001 32972 62860 63319 25075 62400 20206 16673 43940 34829 20543 25407 24331 809 46548 50802 46123 29076 3467 8143 60022 1847 57717 58618 27426 54090 18404 12833 29380 55003 36980 11295 1413 27268 44222 21255 6654 37476 47933 46741 15933 34898 33374 36736 55210 51127 38161 54768 28101 57789 26666 49326 43858 43915 36362 49956 50413 13810 13182 20579 28320 61765 26143 14195 1884 8569 60577 55328 23379 34087 49088 11513 20810 26850 3443 58925 38150 18536 49246 20775 46278 38943 33244 48556 18160 16015 12692 20303 3852 41554 29914 54877 36630 11095 9226 43060 43663 60716 33860 50142 30876 61726 46513 22466 16395 42688 35213 43015 15670 28835 46176 33385 34086 8520 33344 6144 55167 17041 1803 25751 40394 7888 54262 26438 64127 39642 64007 35312 38070 54902 63776 34225 45453 49791 55744 54954 24504 431 45914 9165 36332 17426 45478 22084 41504 3738 17781 52395 2566 8450 59259 10951 33602 9432 20684 43773 49574 28996 42635 33051 38188 33517 50329 42812 9902 33140 58143 747 59998 12575 569 45849 52041 7211 45271 23668 33279 14021 57409 17309 50867 44467 30325 28997 3622 13189 25296 52632 33745 64452 10060 25700 10760 22095 35571 16892 28186 35741 15952 18865 13500 29770 16724 61702 60492 9856 47748 48727 24755 48451 60234 6219 42883 12318 62272 13739 54143 8631 34781 20125 55623 51502 36722 61273 37244 38641 51056 52644 25552 30018 6235 42476 1272 24655 28317 25289 595 59376 21545 42638 40563 13907 56894 40214 35695 40585 40564 34716 46958 33305 40201 4149 59742 56408 37620 21325 35738 38354 47737 40733 57069 11294 7228 31184 26695 33482 41203 62361 40208 55205 6075 10282 12524 54993 3513 47732 57277 56225 61595 17055 56172 1844 61802 62760 8763 6979 42182 21404 3109 12275 22851 46105 64408 17237 16943 63566 61239 41891 57677 7750 27528 28762 58010 35358 6484 20402 62639 301 12568 15902 20717 25818 22735 21030 49962 61647 38001 19081 2838 9959 43651 14883 30113 29155 45657 21092 15032 27553 44341 47029 19638 16529 6896 11280 12073 52612 6285 18119 19134 27040 17171 26359 42629 13516 50716 41734 8331 31267 40980 27624 14424 40153 22364 14284 39972 18023 36644 23301 47231 6619 18819 23102 53366 21007 43765 49822 35897 5294 11117 23654 9580 54354 34438 42468 30127 29621 54047 15756 5525 3537 34952 34725 48244 41115 49085 56173 49267 2917 60133 50225 48255 61646 9640 30107 25986 46282 61408 25682 48469 47765 20704 53161 17748 60532 58790 28676 35335 39005 21130 24737 37865 29282 44667 54425 56280 42802 15988 26894 11390 29130 15590 4357 1893 26759 51292 15974 60525 42452 11349 47682 28095 14833 15702 55221 38605 47135 24818 53702 39778 50833 11566 52759 40531 56242 26398 27351 60004 15436 37507 53572 29022 24802 51011 51310 57385 40596 3427 11540 50296 16665 10010 52340 24316 45391 7224 43023 4007 22181 48398 30990 36727 56302 19544 13198 44076 45311 41471 41722 20282 25641 37176 35893 12060 42039 33907 40536 26891 10692 21479 10507 10570 58405 12396 54441 20853 18107 56296 23292 14819 6518 46105 53511 35087 50818 41791 20352 52446 5221 1742 29150 499 9776 24408 27783 20319 15080 11249 55897 16823 37168 6357 16763 40220 40362 40366 40849 12204 57767 49021 60105 11557 45488 35051 37862 53889 38710 15457 59882 16112 53294 29963 28141 11709 43010 54555 9160 38450 43566 18717 62186 8487 55643 23855 39908 29448 53300 44054 30316 60936 63121 12614 35555 53068 62793 4983 27975 50124 51495 30826 40805 38068 44717 26413 56609 37958 1405 49150 47439 60405 44486 51139 15701 50267 13439 47497 46115 36104 14420 29793 50274 62947 422 64302 52682 58432 9833 60439 14179 47960 33462 26861 46967 48527 45230 27808 48694 38007 2808 57664 15155 47044 27713 2788 34006 39680 47676 25198 10024 27933 500 11674 37606 44878 550 62860 52513 1631 2717 36315 46156 13586 48744 28013 8739 53503 56036 58856 33080 46948 14290 15268 4959 29290 49805 31325 5272 58902 40782 59953 33904 7997 64055 51070 25473 11223 27414 12579 45724 54244 25693 37544 56590 42861 31017 17567 8825 55098 1456 47234 51514 50211 38090 56812 44954 27458 51433 63625 41005 47906 37092 34747 44920 35535 19908 51294 59835 43728 12599 15350 59530 33359 54093 39201 6744 20571 16181 63312 38636 52103 20660 24976 61587 7090 52467 15554 25636 10572 49385 12935 46797 62781 34206 3508 57625 31657 5302 16001 43891 60362 50725 31068 47739 40657 30093 25978 63337 60948 43273 35375 54878 4803 23977 18477 34850 40306 61645 11246 19022 2985 12528 26432 39015 19091 63772 49266 33338 5094 24672 57110 41599 42274 60233 9626 40146 37224 26075 23514 48036 48371 23796 27308 23438 34306 16973 33128 22809 60837 21990 41159 20378 49191 2140 1121 26090 20313 25336 46068 1399 9993 49650 24635 63143 3742 13419 60192 4597 20368 57342 34702 11200 46391 63242 13613 21066 39996 22038 59482 17866 8660 4308 58237 29239 25303 57786 49442 61853 11344 64088 35908 47763 9060 58659 57729 20536 22984 56504 30915 46077 6598 28747 367 36900 45501 50901 64326 45181 8020 64357 47082 4261 29137 17762 12009 2411 265 56682 49909 58088 39845 27109 29161 29540 1940 45270 63694 30004 9132 38888 40000 61192 15207 59046 26360 2285 6194 45259 32792 18134 10145 42490 5025 20714 11567 55694 43943 47877 52171 34971 29917 37886 59901 35262 43217 54509 22824 26289 24047 30889 39385 6263 832 56798 47791 58103 41681 53966 49424 7199 59374 55651 39853 19614 40164 7557 14966 52015 36126 40038 26835 62830 30592 36777 58977 12313 46204 16773 30491 41494 30093 16742 41473 46175 13092 58136 35196 15569 3203 15555 4879 63932 20671 28142 60442 51349 18901 52347 63568 41575 45044 3251 28989 25048 27142 11555 45850 705 9885 49090 42615 51921 21503 11804 62327 18866 56678 24234 57909 27981 22536 22773 45079 17232 19553 56491 45433 63531 61519 43800 44563 20754 50726 41338 20816 4509 51749 19630 10963 43575 5447 58593 27656 13229 49145 29699 51818 10446 28809 46652 44992 15809 46377 44489 61295 21032 312 28891 29588 51492 41658 31493 14996 52532 58609 2542 13793 15344 51472 5590 25098 27894 4413 44759 34461 7599 15340 14394 41275 18772 58314 50294 61441 52468 2516 61964 42233 54690 29293 40496 14553 53046 16767 30007 19100 6410 19756 40410 47329 39407 53004 61027 5654 46232 24694 30392 37892 353 41403 28900 5256 2853 35782 3426 26377 13795 60609 26168 2429 42657 9473 3151 27691 33952 16491 11154 40474 33981 37526 37827 30095 1613 36918 54408 8929 36578 20869 36759 12281 61618 18208 33475 35710 41994 38089 62941 195 29126 2751 7866 23044 49093 46705 53189 37078 12187 12885 42346 39886 29934 58435 27358 46614 10117 57931 42790 10423 50428 22961 54803 25768 9493 54755 62228 59848 33794 46974 51206 6377 62516 45495 54503 45826 37509 3135 61090 57344 63691 55442 29427 25239 19809 28739 43815 6106 9926 21197 7994 8569 62747 12207 56409 2889 21035 12763 5415 47659 27862 43509 54501 30925 58595 14138 43110 22689 55226 59606 38334 1194 48951 57475 630 42754 16323 1203 42933 11329 57475 44740 568 34691 46521 8402 18192 25425 8791 60680 56398 33759 18163 27257 39391 14765 454 60104 26252 29622 62522 46204 56661 56880 10153 46997 54808 61201 26555 45000 35762 58900 15110 10345 33047 43342 33246 35350 29391 1466 22491 52334 16347 49630 5635 4943 19247 9893 55031 3606 48740 24195 6544 7453 3398 54478 35176 44362 30389 10065 57932 35833 34558 22822 468 42257 44894 58380 27367 15849 15943 53161 922 43153 39602 5148 15683 5490 34532 28680 34749 27918 12169 14660 33060 60792 30007 47502 636 13610 24866 37101 48970 51562 8242 21962 51586 56691 39791 31038 21809 61724 18490 3231 46261 60616 842 28944 26651 24711 49046 10226 36577 38990 19246 17147 5197 43720 57887 51876 33408 37618 38672 63969 59865 57210 38004 796 13402 56690 45614 48693 21165 29871 37439 52135 25885 59141 16101 12399 27419 59746 63953 26511 45951 7069 48961 38542 19198 38787 2418 54289 15497 46968 27577 27642 16035 3181137471 3488966333 +1024 23424 63634 42512 11614 30375 44234 41325 20102 35814 34376 51343 44916 6420 45400 48518 60628 49625 42173 61521 27506 54947 21264 6423 3962 61226 36010 26246 28192 42425 33542 48535 109 44327 45820 60735 7399 50068 28973 11699 2031 49786 38678 29392 54011 30747 35493 46113 34828 43977 28025 34014 37818 4670 1209 7550 48877 465 37836 17468 55809 52100 2475 31122 49822 6608 38405 18603 33509 35400 61359 11930 24545 6327 56805 63144 62390 19970 31101 24198 6875 39390 29326 47996 43884 3077 8509 36263 63168 45404 57729 25911 63796 21235 36144 23033 1833 33392 8216 45490 39536 36623 23083 49553 30277 19662 40686 54964 18966 24346 5500 265 40144 58814 22952 20249 47725 41062 35422 19182 43448 42292 57855 41582 35921 60356 26371 21123 50765 45581 54749 64157 10363 2371 15198 21358 16608 22470 63010 24215 30426 48737 8892 37218 51781 30424 7260 63715 672 22396 62214 36118 36095 63283 29214 22089 34550 37235 40791 24289 26422 18857 39607 22947 50448 37260 43957 3781 37579 51067 41098 38313 52445 40123 29378 43644 29352 49479 13980 5481 2008 34503 9783 54133 24677 30086 60571 46409 29446 50773 28091 12516 40310 37207 60591 5499 41005 5186 4963 40289 23111 24351 33375 20803 22200 11727 45361 48390 57188 55231 21396 60579 47880 28594 23253 13697 44386 36176 36364 2487 3731 64177 15213 36378 41558 14127 10385 29346 47901 48860 10499 57774 194 57990 57057 36641 54240 44237 61844 38313 7058 38870 21158 12239 56223 13579 28752 20283 1019 53792 56786 4955 42848 49603 33489 55968 31616 40742 42950 29219 31069 44272 22940 34497 62954 41013 54030 1748 28157 16705 24781 51558 54935 54741 43385 61882 1536 11508 21047 48852 22672 53702 56030 14960 52263 55276 55421 26751 20502 53521 35944 61439 21622 22725 18743 15207 26314 45986 19984 46512 394 51832 40742 60092 50649 40813 44296 4427 14680 34093 24103 27348 1518 51812 48638 32923 22595 52117 6325 62533 11203 33034 54666 27817 35036 21153 23531 17951 26863 39909 56693 9134 1728 47167 53035 47759 63920 56111 657 39131 29855 4278 47065 41743 4492 6337 23214 62180 8986 4843 486 13946 25384 1927 8000 85 36306 57092 24934 33484 14941 50861 58564 3052 14121 54019 1802 55306 22284 57973 55316 10529 23813 29765 46999 52493 64242 16119 4378 31428 46855 44754 21264 42066 57907 57145 38800 64130 29181 14441 57675 23261 23360 31667 27007 23612 11039 47581 22406 40726 52289 61602 3821 28621 4217 44061 19033 63262 44535 1387 23178 261 55805 47725 3664 33283 48564 52283 63134 9884 1699 10594 14426 29354 21922 63205 7277 50272 4975 38993 21156 14656 9534 57420 45340 8677 6570 1786 1581 4929 18523 51077 49061 60134 25491 55339 40430 41002 36290 14143 3159 53818 28289 4226 61050 29386 5558 16257 21641 16552 35821 26566 60799 33495 5875 54907 35680 9813 44567 7050 12623 54854 23014 55751 16845 4873 45306 51526 12206 52671 58720 17097 17155 61891 519 55997 41561 56837 27674 24503 49625 49080 16730 27471 27941 22335 11305 58260 33199 12669 23129 38774 35976 28884 40069 19993 62440 12786 51378 49033 9226 12272 6976 34919 5463 40597 64202 15642 41643 2155 962 126 53768 7788 10945 13679 32854 11391 20923 59704 9818 43807 28869 23625 52146 61346 8150 14870 40965 8560 42951 7334 23344 61288 59852 41370 61550 42479 62681 38620 5092 27015 63006 31413 53987 21622 46438 7254 19904 46606 64100 50335 34640 62504 21639 35465 26321 37550 58234 49004 11441 49269 11245 39143 15382 22154 57800 23978 19858 10102 60695 56284 42558 56558 25555 55046 3129 16694 29492 28193 61118 39255 257 36719 57247 14794 49432 8084 57996 18873 60998 9849 34531 63114 63125 7117 2167 29831 61371 9570 45992 3958 3985 5557 49160 43227 12899 33028 11742 8676 2669 52875 9216 5018 4724 22846 4919 24463 26632 2382 55895 42445 50391 14203 24236 59954 6117 26648 46418 53624 10949 41264 30309 8042 27576 16981 42275 60568 5979 15818 13696 19198 34168 55935 39946 7316 8087 19034 22118 40083 61041 50427 60188 19173 6139 21434 42923 5501 27720 56393 18983 14885 52399 12225 44017 41109 13444 30796 57461 34462 13592 11076 38702 52089 60288 8099 44051 42053 13413 64226 30883 57595 50585 36781 36479 42184 63052 23477 2446 62304 39416 56195 13997 43051 25206 19758 20496 42122 52623 28882 37926 37817 42329 19078 44140 45992 62967 6984 11059 22865 63927 41006 5213 58689 61015 43096 16040 2299 53262 12330 46855 586 29094 11132 27012 43923 46376 64500 23037 25041 4918 51935 53120 51933 45402 4423 51246 60706 55698 41890 33904 36503 54239 56697 2407 2241 36051 17591 37719 18952 55420 54661 31366 42997 48623 44949 13964 32788 44367 49950 30951 9131 51113 62696 45110 15267 1762 58967 29760 52694 16967 27490 31490 26764 3421 31652 41236 23253 57632 42735 14137 61009 61541 53550 63590 1095 39945 21436 56326 56072 15170 34412 58193 44776 13449 51909 11300 16032 8108 30552 48463 24148 17884 5882 15646 50225 26780 39264 34334 12784 28250 21970 46845 20225 37330 45021 42676 18521 23475 18228 30441 14239 28965 8003 47936 18667 61138 46221 57067 34856 21316 18761 33200 58122 39643 27424 50866 63953 62331 62793 1059 31555 14975 63309 60031 43813 49918 39435 42165 770 37992 61291 7946 45756 61652 13904 19493 3075 45253 37910 26117 50975 1056 21883 42427 19862 26676 36517 64019 12293 44516 11727 12193 20908 23131 49260 13722 36804 43204 6075 9291 47607 4088 60023 29307 8621 40020 17899 26861 56820 8051 46068 25512 11334 17298 62635 17318 17235 38685 54104 10708 27124 3338 34370 36888 7662 13036 7392 54873 63927 23901 327 2567 38938 60888 13132 4819 56198 15861 48694 34839 16750 5386 42923 41893 31111 45530 42094 57454 22261 23564 44726 49688 59077 17666 1779 47990 55528 58809 17325 23468 59575 37548 24324 45688 52630 48104 42744 58608 53423 53752 31535 62698 46051 24892 10580 58824 31688 5168 46879 49202 33007 16030 64107 41304 46032 32870 37036 63707 63254 13646 12811 10628 31220 27579 9889 34236 63365 56610 48335 22156 60733 45841 64272 53930 33069 39771 14629 1609 37048 53634 62602 41210 15277 19104 16450 39684 3710 37446 64094 7748 42903 26542 30254 10600 59552 46530 38721 15069 56996 35750 25411 42155 4020 2181 27206 30244 26795 862 50233 37416 20598 42907 52858 51017 39111 3853 28356 17403 15641 22229 5587 35006 60179 31157 13421 13563 22753 1097 48598 43380 43116 30632 60246 44411 59576 20820 5956 17871 30391 49329 34175 10775 57213 23057 57046 12058 52381 2153 55655 63837 46915 61586 38480 25742 57129 7775 24263 2418 54948 47690 53417 2052 10177 61041 26593 10558 33317 60639 53970 12850 42134 52279 49417 52559 13012 13870 36653 34052 51247 52773 21464 22070 41789 20716 1523 30965 50131 40834 29344 63648 32863 41257 29484 46387 44689 58776 36921 49176 25668 31204 9927 38644 16854 59425 57467 46772 5993 7315 26237 62978 33570 58451 58307 50332 31603 56693 3441 27820 37289 15108 8970 15656 30859 8866 11789 52294 48944 62516 58684 16219 6744 58546 59605 59904 37072 37239 63841 10083 36974 64356 59507 53678 33027 55354 14595 58801 16067 51573 47459 36419 63760 18422 5940 26384 37408 45508 50030 50260 51819 40238 55529 11964 13001 9293 38339 29001 51005 9410 24347 57090 33003 49733 25034 40120 52648 7055 34398 52580 4882 585 7589 8611 61100 26340 40616 26802 60046 8164 53081 55455 38010 57312 17105 16326 35126 16541 42944 40840 12753 62585 44188 40863 42078 22545 53087 20564 61683 61896 43739 50635 49261 9356 13023 57113 15659 7067 38088 18786 35173 39693 50192 27703 49741 7290 58675 10291 61052 45319 49667 58359 117 31023 38249 37883 44021 37378 14308 19930 3123 22760 37574 41979 11713 8613 47985 43638 33169 27226 60321 63641 12227 61530 23145 41855 16761 26994 37312 57040 27941 47334 30019 27805 8862 34651 8760 56898 25801 63620 64131 63166 7348 17020 23234 31137 33182 20221 11090 19183 8520 19263 38086 58306 33154 6679 42008 5380 53682 9486 52326 34650 37582 27358 59680 26576 18188 37944 59563 60737 47745 37142 18540 42085 14460 51188 24599 62045 11230 5879 16580 27105 33875 51148 28799 13192 42472 53336 45353 34538 61595 35838 15851 3789 23122 62063 40382 5257 21219 7298 11483 2330 57101 35031 44087 51524 61409 22096 7033 2469 33136 5308 55509 29176 13635 43931 4854 51154 28301 47222 28678 26237 5459 59508 12829 24524 1892 429 5670 51709 61401 12883 12634 49198 29559 17577 17945 21840 35717 15705 28559 39562 17909 24616 14797 8819 27234 4169 43232 3137 54631 51995 55557 55599 25826 27451 14870 46620 60617 53494 25683 14245 51745 23445 57519 10926 7492 64411 5486 63700 15856 9080 63893 56215 26143 13500 24292 3300 18514 61199 37338 52516 22426 20314 36229 26703 48853 36952 18033 26285 14857 23492 52301 33369 4153 35748 371 57695 3863 33670 9903 64220 36510 6148 27990 50963 21601 49045 26520 61769 59602 48004 61938 1475 39868 36106 7891 45284 11306 31513 2308 62865 30449 48183 50263 52983 3279 3521 31557 28896 26500 51499 29907 22796 4805 3973 33823 23101 45483 47146 15032 51653 1593 40005 52960 33540 17905 63734 63085 44451 23991 48755 3743 15453 19797 41326 49088 54382 29116 55821 27435 53948 9501 36109 15217 29354 36751 37532 23237 49168 27213 2028 35938 19551 43711 63619 49223 34837 44224 46039 42938 14133 26473 12508 51372 40818 2440 51401 5932 44117 6339 717 63651 18181 58178 26088 14158 2671 56509 14031 20098 37592 37859 38679 17652 45184 61773 22393 21750 26077 2947 56661 40417 59660 18533 7761 2391 62390 32852 47820 62209 52095 57935 7899 10436 47460 11050 310 10937 25003 24718 46986 55787 57276 17808 7564 47193 20516 43504 61477 52234 35310 27689 1304 33091 64402 58400 45142 23432 10187 57894 10870 46801 10123 19329 275 61546 2912 39234 45818 59687 6229 5846 29219 15439 20699 13614 23908 23750 6465 17415 16007 34547 55040 23618 15062 33527 2859 19071 39324 39731 2512 14663 48113 20186 44110 53173 11784 56546 46411 36584 31431 13739 50903 6065 16475 62354 52297 6446 39813 8006 54142 43752 23663 52193 36779 40824 57802 38462 39487 55002 48652 48149 8299 48167 42166 30875 16457 34708 58472 8333 30384 61625 52595 38474 3847 26229 44119 11652 12505 18245 3931 19934 15912 57164 33075 15409 27711 19940 24274 42860 47652 5975 52755 24249 47491 43959 37715 29213 25115 55128 40796 60028 46173 5800 38913 10166 45582 60760 53481 25299 25272 46225 56188 25042 63914 14440 10605 52803 27324 38827 18153 16594 29238 19247 12841 53320 45846 53968 4965 51314 58105 28528 20711 49475 23211 34293 45496 19042 2290 11853 11257 61444 15034 24711 20239 18716 20797 22408 2360 10923 17161 56805 28832 43148 20648 31174 9415 63562 26752 53602 7711 15890 44101 18623 48492 2992 43353 63559 13213 3437 18062 20787 21863 383 50346 9709 6004 41051 60248 43321 23103 47802 61944 37377 20485 10371 47016 42972 60921 48053 692 3132 24622 14146 6509 37729 10174 51167 60089 33862 11635 38093 1874 24924 41058 23872 6056 16978 89 24812 47911 53274 54596 54878 40825 19042 18254 46711 11807 51037 27538 2589 55246 525 48371 22513 9301 11944 355 39578 42433 9947 819 41156 16890 45355 12035 55413 6492 41777 61270 59611 20219 39757 8744 24145 11363 4897 19432 56603 1524 59483 17054 57255 53245 60597 11011 50314 45860 37666 29933 41798 7663 8473 39090 55275 47765 38079 35038 12271 8155 60779 28598 3924 22912 27074 37307 51560 3182 55528 8825 61041 23388 6383 23048 56790 54085 35580 53974 34582 15580 34026 3099 5222 46057 46000 28007 47945 33721 9836 55127 30271 43202 11129 53860 2841 23012 37078 30826 34283 56388 16026 51573 8432 53933 40379 3138 34219 58461 52717 59599 42515 54068 50897 989 8000 53823 211 31426 42269 42725 64191 20286 35353 41069 46364 34147 28841 56834 51883 33825 57602 30298 60742 53600 31124 27142 14847 16888 48542 23903 30102 58141 26689 43768 9109 47201 37934 19517 61868 52680 50073 55247 19602 40950 28824 12929 41418 9330 10795 23135 11005 45415 23394 59416 10128 47991 42099 50665 55053 64260 1341 31134 34382 39165 6325 33672 46264 63701 51661 11038 20903 2973 9387 18299 46740 33490 45023 7368 47276 12960 55815 15395 26973 48903 62401 19840 43562 32804 13850 24357 45023 43437 45481 12039 37701 15939 60047 42131 63171 17237 59033 34445 17055 342 21291 36117 20641 49391 46552 2859 15240 10451 48421 20617 54048 55117 14237 16798 26714 25826 41934 46630 15923 19485 60855 3122 7281 25451 0 1299443705 +1024 8494 53443 47771 54137 25442 28876 4878 60901 19514 26511 7494 21776 26884 25019 64040 30277 51257 24634 26646 40045 52730 46841 7820 18496 60259 9717 42791 6972 36629 56028 23387 52774 42678 49211 14121 42298 31721 2714 17291 28918 17376 45215 23369 61571 38769 33551 55121 38432 24603 26424 43376 6668 29167 41753 14462 15188 34167 8834 41504 1868 6230 34252 31264 21692 14482 41500 61832 11036 29754 5183 10496 54268 21026 50372 22204 29176 15049 11877 29498 47826 20304 7833 3259 53646 21822 43056 38174 24350 55124 48369 54359 55192 759 35756 37594 12020 31045 21819 37577 55918 31522 34124 49193 33649 2061 14326 51923 40060 63074 50252 47743 40271 50292 2196 20843 40588 16410 59661 50072 526 52726 50652 39589 14943 54704 35718 36111 58973 11058 43617 20683 9372 34871 51059 41374 12297 50630 53760 20450 44631 57544 51556 38072 48486 20823 40593 8976 25880 30838 36300 59013 4583 50035 398 42706 28417 2498 13088 34400 34096 40148 829 54713 63848 22270 22057 10844 57433 63857 18193 61903 61398 23746 49085 47204 46716 26197 21160 8896 19716 15829 9538 24234 26077 50176 39314 14485 7972 309 21813 3855 7576 8989 9421 26399 50746 23715 34938 37640 27012 23699 23227 17831 12232 35443 35812 49530 48916 34066 28604 30353 2699 42686 64159 33506 46865 26754 26838 35012 42563 33723 26259 55907 39901 632 58113 1767 707 27695 19517 59842 2389 23214 6678 23227 3564 49310 26831 8723 60292 22276 606 54724 25616 58964 23275 63475 51527 16489 20151 44653 35818 60911 8345 62154 38680 44685 48828 37780 15341 36702 4843 55212 40567 23605 47599 42658 28277 18660 53333 45791 46952 62426 34932 47662 43702 48270 56497 39389 29902 30268 7084 2297 13714 37327 16244 39861 13011 39086 51652 15423 41431 48804 54440 58265 37267 9347 34732 18688 62185 31039 52554 6977 60128 23480 55629 56372 57275 27092 38194 21224 14716 30839 53095 53014 35759 3096 39887 50373 40214 49415 36478 26095 46023 24220 58683 39697 52960 40172 31689 30948 47310 27349 60412 52472 21769 3381 1631 41658 18725 52995 57979 11107 14407 39497 57064 1610 51239 56409 18727 33880 57918 45103 33026 28720 48613 20880 2086 7004 53890 36673 8691 34759 9409 48066 24626 16471 39123 53206 52332 10697 46562 34964 5913 50157 28079 17535 7506 55194 19120 28521 4738 37356 18563 3961 4365 61154 39682 6866 33474 37000 43549 52767 36477 45443 19748 5225 18471 14712 21459 44670 58361 20679 43047 58559 42868 15174 41351 41420 16094 45382 15865 9401 29535 44837 37696 3155 62155 30149 42699 53896 43356 6211 11768 30739 6755 47172 62912 14156 26150 3134 1633 13982 33142 54624 18328 24230 9042 27594 3233 52239 55972 6372 36696 20070 55536 52502 1175 47246 49668 6888 47424 18612 30540 50045 39633 10339 50334 61310 27153 54702 52450 51808 41910 23482 26107 56137 55108 58104 3620 18968 9887 55284 58184 56749 85 18997 27719 36166 10908 3099 61767 37744 24444 10315 38 2625 22078 40310 61896 62351 47223 41514 3616 47754 37532 22885 28673 61109 31429 23167 16107 11567 29016 62989 15154 22111 19120 30024 17134 17457 46544 15777 57006 127 35260 3194 38215 53353 29369 23575 56712 23470 27343 55928 39532 28858 58061 8144 44542 7721 7236 15204 48232 15480 63365 25104 19438 59983 59516 43192 18621 61867 32989 57393 911 18530 9228 50394 32879 39387 52278 37280 42164 37116 58872 42160 8497 9299 49822 61111 42474 29011 56295 29299 589 58041 42916 35492 36808 52399 62886 29000 43727 30785 20618 56460 3112 63339 34207 23853 15496 54836 59786 17699 58957 37246 17105 34664 55037 57650 37645 41080 45676 44945 53701 1615 4863 2895 31151 63360 31041 21670 1262 60270 51657 53286 44419 45203 61012 28598 7481 5506 33795 45893 23775 8548 25507 30615 62475 38938 7661 17932 17443 6089 54774 11004 1988 62669 19373 6106 41887 13289 50647 52168 36826 23985 27848 49923 5787 33956 24062 30410 17174 26704 62386 61238 5086 17772 18151 5895 62226 18589 19020 43453 56207 50750 60763 43600 28316 14335 24648 25284 58850 62037 57140 4459 50942 6697 4343 64359 12271 36881 6398 17667 23056 46046 61213 50951 1724 44321 61407 4720 39385 57570 28038 62552 28016 29921 52438 5560 41726 43272 55095 38052 1658 30535 41867 48783 30516 10634 42380 18380 17783 8589 52034 16788 41421 20835 22867 62615 50535 36904 48059 11443 8340 16507 49930 37427 24423 64274 44739 10012 61435 39196 21536 8771 45641 55722 52405 38968 61802 31230 10059 38453 25630 7650 56534 30989 42436 59323 47815 12499 16439 59306 3843 60853 46139 55857 55049 34372 3955 38333 25883 50154 35581 40581 18706 49344 12789 1952 7268 41407 28022 60406 19404 58050 48941 5787 53598 57428 13652 39221 645 59379 34562 51153 19322 18799 39840 41373 5247 44118 57896 64233 6156 39218 39601 45317 15009 26344 44946 50114 43671 55109 19800 56928 27317 9820 46337 6092 18295 41990 25650 50483 63725 352 45219 15856 25914 715 54193 28241 63002 57635 25139 24763 472 40266 41154 6191 33114 528 18954 3399 9714 63181 10651 2569 48853 25892 8001 52084 47365 37905 5348 16125 27764 18085 42509 6631 55569 28985 37937 53564 61554 21043 63023 53183 48661 46967 14834 19501 5812 63453 16581 18831 61612 56877 36544 13291 7225 50028 62966 10702 31099 2996 33994 18224 55139 49299 60346 4568 48286 22088 40540 30347 53148 41571 22144 22146 8584 27688 7413 45937 47598 64397 1367 16521 18102 36450 17463 17789 64176 36467 60652 20308 49283 26729 58756 34579 6686 41213 55206 61202 41186 4896 685 47307 7507 60084 44624 17925 16564 7015 40385 41963 44204 26027 49901 2344 23024 36155 14225 10462 62613 43303 2119 41292 46189 59461 35996 52208 39879 33098 25514 52291 8449 21521 52461 22966 54853 34703 16989 5719 8720 53182 21204 17497 40939 18017 42436 59155 33950 24610 50734 45902 50614 30099 38032 8920 44709 21671 10575 34244 43807 49234 30483 7954 16747 23872 9194 9187 7533 43446 16928 61002 43321 36502 29371 21136 56036 14659 60661 42578 16715 42671 44164 2976 454 56684 16930 51568 3833 43749 13372 50362 24693 36018 10173 29500 19438 12594 34708 9167 52169 12961 19605 22871 42019 21090 49003 20029 28019 56755 8168 43138 58431 24670 56554 59114 50444 63373 54983 40633 7739 46630 43440 22133 1460 8392 24400 14311 56070 30078 55518 33237 24835 41425 24690 9422 16676 3445 48669 47401 56078 6850 43990 35299 60537 6272 52035 54424 23521 620 34603 49513 48117 36701 15749 58370 49963 50927 22202 52154 62182 12713 36714 5397 16363 24494 25222 50827 44785 36611 33573 36375 41973 49904 10100 45782 1427 7348 43097 53493 24056 1054 22984 21331 17937 22752 26155 55096 29664 4874 60594 57939 40774 7857 12413 23406 24011 55083 2921 14239 56768 37081 29262 16037 29338 36781 45011 64085 3946 11467 42115 56941 30456 13802 52958 58292 40271 37742 3466 9813 3565 22260 61842 54369 61614 63381 5941 19718 46509 17317 33249 23573 40266 56517 56220 13991 64188 31538 37880 20201 31697 30464 15180 5071 46214 52946 46210 39230 60095 57576 47356 29556 51867 22116 35940 51059 39938 36056 50377 48010 47954 62544 5008 14046 44656 34807 28159 53114 10199 23123 15739 15848 11355 730 62585 10006 24117 22240 15103 27456 30321 44021 58051 40364 57436 46449 9986 25013 7324 37343 55203 26059 24063 7869 47352 63705 28012 35869 17208 22741 18824 21120 28551 63216 28435 30107 21736 26951 60963 42103 11483 56778 40184 18226 23965 50117 10094 37244 38310 63556 62761 37891 62346 39628 57229 43709 26337 2669 27536 10714 2354 43993 55856 3639 24402 16046 59423 29088 51241 22754 6092 42040 9708 24944 2467 30512 51438 50065 11707 2498 50260 36110 31280 47957 47417 34820 40653 43114 33391 3230 20158 13615 34096 34499 53850 26830 60056 61655 32798 46338 26148 21362 37543 47140 55095 29312 18682 29757 18117 38028 12638 9602 916 7775 54774 57434 2352 59215 5332 60628 51789 33398 51246 54778 7068 38118 36416 13348 43681 34491 13860 61381 64293 28530 997 11457 44241 28471 22724 28290 49471 10273 49690 58617 60595 20828 8717 63593 28560 60525 44652 3158 36989 5047 14388 54282 46233 53050 47708 22316 14311 52665 744 58861 1977 30502 24860 30259 45867 35067 16892 37519 14105 53978 21208 42484 14507 17859 40772 49067 60232 176 14488 59452 10592 56273 21737 20506 21628 22413 19395 40395 25341 45627 4048 46332 13337 18020 244 48581 23863 21316 47280 12714 2019 25696 5194 35963 54188 3025 5123 45261 21541 58630 44654 11109 2362 15061 51201 7703 28680 62801 10331 9394 56591 2797 19576 40954 26228 48752 24579 18050 53040 47861 19985 47105 31503 49730 53220 25475 41115 48138 47475 38392 62101 29845 27645 19650 50437 15691 1628 27837 3532 36926 31646 53907 17176 27818 16364 247 38621 15439 61974 23505 15645 28978 47272 1880 54002 23112 37097 20438 4837 62811 52140 45099 14085 50319 34233 6085 48355 64224 57418 10465 9827 56197 50385 18344 25862 24372 20244 2972 7565 13275 60548 28051 11266 45676 33519 51029 43296 16351 59402 57101 4926 9939 63153 3907 15853 4293 58594 34029 41413 64297 29304 22013 1862 30110 51964 38842 49603 34112 53443 42063 46016 57132 30029 60080 10810 55090 24526 5668 33703 6225 15088 39055 60877 3254 16621 46651 49196 28982 44401 57717 43977 10671 63902 2450 35163 1385 46111 22287 18689 38350 47390 8407 36111 34723 33286 20360 14615 14830 34503 37462 31262 29253 17213 9411 48659 47346 49071 7803 15832 30080 24084 47550 3337 9171 7368 46210 5266 34300 7889 7887 64240 2958 3085 4239 45712 362 22646 26824 45244 39692 50375 61855 57998 48285 48670 15442 16482 41722 11138 38880 40513 22512 45981 8064 44496 33928 57486 62511 52996 11872 1729 5568 38578 15408 11951 27039 46650 27281 42408 59041 57410 21965 35763 1016 4453 24168 3834 27867 54293 8748 59726 34292 49400 22074 15393 64425 64108 25354 31413 598 10117 63265 44699 26473 57405 50380 21037 17928 33750 37293 2498 24383 22770 8733 6795 39958 21113 40650 40303 45168 49956 31191 26810 11968 764 34296 108 24657 38699 32855 558 14877 3613 5658 9094 28319 8263 36047 52672 6761 42248 34766 33784 15180 22828 15720 15537 34457 11985 2321 1372 479 51765 47018 15806 9637 39603 1797 61132 7277 16250 6286 23180 52115 60267 35494 37099 47464 10393 59851 60233 6540 27409 43062 56667 20178 35988 43145 44383 28554 12305 61989 42327 6150 54597 10290 22254 42300 29947 57325 30239 16986 47915 4980 37727 33595 63463 62178 62066 22777 54553 20727 48069 34891 62165 21445 53937 26454 488 25411 47882 17085 12827 40758 46185 12451 6134 45723 40206 26223 8164 6183 43619 61886 62519 28615 46991 63152 52604 37524 47191 43576 3452 11896 26228 38762 13459 55452 42534 16057 36077 57140 32931 26734 43703 44280 35619 17771 12850 39765 28645 59588 4677 11415 59380 34835 49785 20869 33877 40020 47345 24276 33791 17898 4659 62088 17094 18155 61094 10807 46052 36478 3120 19991 58526 19525 4230 38340 45802 25997 28712 48771 26849 21335 43944 23778 55821 43653 45058 46787 39165 25650 16249 35622 55310 42740 572 56836 56764 19593 47650 51939 24885 62700 41357 38522 37397 22771 50235 13932 58587 63471 44217 34625 46609 7156 39454 17609 3074 63387 52109 21372 46209 61111 10259 17415 47295 64433 62639 55238 27890 52380 34393 20189 55285 24601 55953 46472 35639 59991 4887 52855 39357 50980 3755 30608 52577 6138 47641 2904 58063 59755 52033 51044 56135 3025 25561 33003 40312 9472 24992 56548 48759 4455 63090 14140 15511 50454 8829 57351 42821 19083 58191 56090 25918 61605 29910 10040 47949 64360 55504 25967 9889 57484 12833 29128 37657 14053 15775 5216 63999 7079 47705 30335 42578 16432 45867 31171 20501 57950 10515 38063 3343 278 28708 54493 35474 6313 14837 14168 6492 19533 31196 33943 4180 7538 23157 51228 16018 56322 16126 60524 604 46177 813 30098 37508 31026 55477 21030 20185 11484 44015 3864 1886 46242 8838 32820 379 49597 12577 29859 23143 30403 6082 45632 28760 15166 55364 62364 54711 33443 26837 49658 45905 41801 46767 33317 56042 39688 35648 6862 25737 52518 7852 33307 48335 4632 7593 30786 19163 5289 17407 3631 4906 29498 57748 23168 50426 24311 14371 42913 21421 53368 46785 13799 8483 29996 19559 39011 56472 10785 40565 17842 9281 8071 1998 20755 58355 58786 61161 28130 43772 1785 37596 57637 47102 17969 49937 45475 28441 46402 33107 22927 44579 27958 35639 28741 21372 12726 28991 22167 37961 63754 55418 3100 59767 14401 61169 0 3461970221 +1024 34456 27737 16362 18337 24088 57209 55246 31050 40880 42185 2154 34256 18663 25665 59955 16061 59041 29248 37617 6457 20727 23827 57042 35258 3007 58800 47689 27613 17257 58919 25266 46836 21775 50381 57245 45768 27006 4207 46722 33310 14416 10341 52262 18581 60966 60750 51176 47246 53946 58056 56976 21444 22641 54324 31695 44257 13738 9575 25972 16666 46313 47375 21609 34677 30651 60439 54173 4569 15959 51938 12396 57045 43008 61367 2803 62316 28660 46423 49528 5998 1967 35899 35774 62398 35173 44598 50741 8755 15185 11171 2941 46314 52794 42131 58768 45384 1721 63770 23349 13988 29723 4736 29780 26302 15674 41316 14463 9240 31356 37426 59231 1728 22154 11222 51493 62471 44388 43401 19336 23763 45602 9266 6983 25172 34244 40036 62857 98 41328 27157 38566 11113 51464 27148 42666 42487 4961 22048 26683 13854 22617 2125 19488 26110 17972 56381 15951 8004 16173 9292 24969 36259 6832 7611 39324 41008 34683 36986 30734 64465 17279 41152 39788 29528 48402 14692 57359 55657 49343 43024 51332 35956 41187 25581 13122 28667 35148 64259 13182 47743 8778 3234 25306 7246 46141 2788 39690 47789 30624 369 55052 14096 4698 19756 61745 47801 13667 10596 24485 24925 26513 17433 35864 1352 16976 38676 47621 41738 53867 57413 10129 50984 27294 64178 29077 18686 1122 44072 16067 39124 48218 1929 2224 39537 57001 27262 44098 39705 24087 22 55311 54226 35047 16005 57565 29097 52751 50973 35891 39045 29933 48587 6409 6456 47937 48807 33737 9420 23231 30245 57951 13759 42222 53079 10105 21577 18476 25939 4317 19205 57859 35628 56574 41238 50330 2862 51227 26201 7416 4611 63000 21832 57776 30608 2134 7532 10639 4008 8077 23773 30403 22757 49196 11099 55499 60521 27461 963 11278 53194 63854 34108 50586 50712 23561 5176 32776 25795 11747 42224 62883 63160 230 58373 10340 58383 15294 33124 46123 14554 28104 22333 14293 6664 39253 28159 13615 58642 40593 8976 34862 11852 4486 42077 52940 22842 15696 50319 61667 48008 25996 36290 43814 35410 57077 40832 42403 12745 26933 45693 55063 24664 55266 57579 46294 26938 64443 8428 18859 27783 48227 35482 40665 9786 2045 28978 45056 38661 57262 11672 6520 22615 58122 44458 51144 12847 469 1162 50468 1392 10251 15033 20932 5476 23296 20090 998 5323 11232 15732 19417 44810 38989 61213 37378 415 16369 15801 45155 50554 9903 53670 27796 4825 19239 24604 11061 33371 49478 41366 44119 26074 14607 9682 40834 17565 37958 49032 774 33402 40454 35475 8366 5762 61142 61011 11277 34186 19247 60832 20701 24274 62368 49547 52146 10574 62174 8765 4667 21720 36147 27872 16600 9029 36757 17762 54311 2002 46306 13793 43993 44759 49110 712 28356 57965 25876 12496 13262 15541 25750 5233 29140 16817 22198 15886 62331 60385 62721 51742 5976 56065 18681 40680 58652 11557 59022 3295 50072 31675 49580 20094 63933 8342 2177 57124 30616 15248 31617 33902 16519 43165 23723 14237 16771 3471 1158 33862 18836 47995 15680 23275 35550 58742 20051 16365 34829 46403 5661 50203 53772 26492 7048 5049 23306 30760 52145 11543 39257 14225 61721 29571 39268 29968 59448 53499 483 63507 30995 58226 23441 55423 6654 4287 7901 29091 8932 1426 20944 23080 47411 17324 37023 1690 47547 21267 10926 56645 16374 28080 26732 13539 40488 14333 58215 44973 9545 10220 41574 63753 50724 56022 39319 63423 13136 13116 19849 36849 44319 46441 60512 8583 33880 31147 27953 54929 7070 20833 41368 37825 21234 20323 61692 59339 31358 59390 54109 1344 17561 57435 45630 6606 30025 30050 43821 37608 12872 605 50728 12032 33496 33775 39507 54534 38889 48518 39366 50699 18675 25027 2676 22357 42128 26469 36158 64459 13607 58382 19364 14360 51308 64145 13087 30969 21771 12046 56112 16126 7372 18458 56625 45079 34806 31548 4172 25467 30483 38488 40913 64499 22724 42130 50302 26860 46228 25449 5945 44183 52373 23099 8558 57786 6273 41709 52520 29188 9662 6246 41760 16332 64023 52590 7160 26174 22476 53903 12869 25490 42005 25723 16011 3252 3488 27130 28095 6766 54079 16661 40364 3866 24621 18764 48038 60398 52493 27580 14861 46089 5257 28320 14801 7035 3042 34475 38517 41517 43153 63610 63005 18282 54242 10819 38531 56759 22055 37663 6084 53243 45064 19201 26428 4210 2855 18360 12056 57334 9772 28376 17274 13125 10936 11538 39487 37253 4482 29697 16534 63910 26150 29387 6362 23218 25864 35812 30629 2654 26046 28779 4290 9362 52174 33605 36638 27313 2899 36568 62957 30078 12297 28134 21740 28798 20604 25771 40050 51162 28304 11966 33239 6197 7838 20606 53414 62550 35292 20650 5036 40553 14571 47292 27209 41626 37327 37735 37523 45024 57846 25912 29235 53026 31516 1761 4777 48893 40631 55977 59976 31518 33467 37220 61370 34405 45724 61349 16606 36721 38071 25344 63972 53644 23475 24162 2863 342 13447 56864 45869 23446 34072 63707 21318 39456 59146 45052 52993 1933 13705 34517 8088 8316 47881 29984 24142 19532 58270 35709 1801 14783 28920 15073 51897 13024 24499 48556 18320 56638 28584 51900 18579 21600 61257 1178 49679 54867 42774 41063 16891 22107 23740 27210 49489 24688 49420 57073 4555 21846 37995 44563 51714 16947 44560 16409 26976 7708 14031 41848 63670 27731 38051 40503 15656 64026 54374 14024 25221 6088 62317 16168 51625 6685 25770 27476 61522 58705 56918 18845 49541 6885 50376 61011 1441 15945 43742 7840 21911 23002 25304 10914 35369 26252 37092 27814 45573 27647 18709 28103 16558 2595 18560 523 4005 48110 56144 18771 44555 28735 14174 58044 3455 58159 12097 15256 33868 45516 26950 54046 57668 23505 61384 59386 42506 28804 27241 19274 59580 52608 27715 29169 28640 6410 43631 57531 39051 17938 7822 48187 40820 29995 58726 43961 40325 46114 20356 18824 55900 53926 47212 5074 16094 54789 2815 57703 29504 43836 12631 2843 37621 64328 792 61851 41831 46335 28195 5573 36510 13907 21095 47850 26232 21071 11795 51684 8723 22659 43563 6336 3202 9705 64464 33121 6960 51857 24410 56700 63412 9048 55702 53012 62178 53610 36456 30186 41855 22123 14805 5284 7120 26311 1320 58452 10064 8711 5294 23159 26112 51763 10492 12524 52913 16191 27649 50026 20523 24337 6019 26515 48085 25702 14571 35664 38352 23439 6119 36371 57100 30799 62299 42486 64029 60254 62566 9811 48324 4383 46971 57164 759 25161 15659 18392 40563 51725 43225 63053 43472 18977 49645 16027 37479 30673 57719 58192 19534 32861 26153 63172 55572 12636 40237 4207 26541 6123 52815 51010 18466 36949 2399 49551 9495 51913 38322 64186 36925 26596 63306 8710 54636 34276 15320 40186 15582 44900 59966 50313 14125 45584 39951 15801 61128 17879 45875 48806 30898 40385 50806 46610 31078 16998 55692 39043 33914 49759 11464 38819 47384 6164 34367 40053 14479 37159 20256 42183 62794 28345 52539 2496 54783 48490 62739 11947 1332 22965 48739 47802 4249 59596 34024 44798 50917 8909 11251 48788 29914 12561 4272 10903 49240 4527 29279 58699 58728 47430 37612 11720 41126 55417 15876 59578 27489 21911 60252 54378 18652 26603 13918 34543 15150 2408 13712 55649 36782 54267 61465 23032 48091 17675 809 13348 13125 6731 45371 33166 47923 50688 57879 56077 33633 35546 24921 47486 34288 48612 34374 61614 49418 25757 48061 17279 58775 30055 37993 288 50458 30425 28046 2375 6133 13246 33015 41994 53312 23882 4713 45049 60084 51015 40211 41030 51446 7902 26939 54653 53080 5781 54614 33001 14523 55685 57845 24672 9040 11763 48885 30932 20400 18746 4243 22869 529 32852 39952 16274 44931 12307 13052 28117 38881 23385 60901 10033 36248 24356 19817 66 46760 42047 15914 2825 48261 14860 26742 2347 1550 36347 64435 15070 13835 31042 58357 42710 13173 55032 18109 35965 7612 54633 38008 59853 29305 31493 41854 21095 16063 19181 12399 40523 46250 11574 28702 30712 8678 54206 11726 17687 4544 52216 326 8096 4582 2024 21122 14904 47467 18208 38458 43613 31298 28037 40989 6854 3198 50283 61971 34502 49958 24814 40874 28116 25268 63664 45301 19535 10469 4016 50949 15361 42530 2149 1055 59584 55544 11377 50299 63265 5322 8469 3415 54453 12379 3787 58285 24952 30105 42229 51602 35701 14607 36647 14121 61263 40256 20267 49768 49435 41130 61645 54925 18057 46956 23370 35849 15854 13032 53550 5200 35155 64050 54054 25297 21656 18680 56358 49387 2507 53909 61036 36356 47591 31318 57907 61135 20457 20100 30361 58436 38086 10017 30481 52717 26915 774 33335 6355 2680 48225 16543 23448 64089 50178 41273 43476 20490 12672 23644 50449 53325 26736 64182 58463 58870 14358 45009 41876 62187 58467 44913 7558 26368 28713 29230 60614 21966 62817 46495 59 21764 10701 21128 3214 26647 9793 37415 25237 47890 27732 49536 14233 18708 63473 36514 14397 29050 32793 22108 28057 59937 46598 18984 2509 41248 17134 9235 51464 17887 43777 6359 30805 46419 2593 42378 19488 17379 12746 30502 53993 48238 31288 10390 52962 825 40675 857 19189 15755 64125 48307 58561 35063 27299 42693 19917 8431 19626 27161 34033 3095 50396 30294 55889 23542 841 49758 60976 18837 43001 33583 14237 63926 6690 54395 2832 50478 64045 44397 44262 5788 59410 44436 31007 36593 47562 13729 50361 24120 13244 38747 47147 34078 46172 27759 63372 56349 5468 49948 19644 27365 38048 44009 53407 64345 59236 15902 64158 41466 36355 4338 29939 728 54467 43147 47935 27180 22884 32804 61110 22094 6773 13837 37248 8264 44745 33725 52319 16650 41638 33391 2049 7862 57181 25565 53717 2168 63769 39829 33955 62304 10461 60281 33319 31516 15921 1675 16284 13825 14174 25079 14284 7760 27442 48724 60774 16268 62485 40517 14383 28 47578 8067 35226 61677 49302 62103 45290 43931 9504 9307 49409 9510 29638 55930 35155 50294 12133 26400 9733 61993 59371 165 22885 21071 34933 39839 919 60901 40071 40559 36808 46958 18849 39558 22004 44613 60411 42606 36427 20017 44091 37620 16197 34075 58775 46938 42210 25932 21931 17569 45360 39211 57055 23648 51865 43621 40035 15396 45928 9196 16982 21498 8093 55684 56042 21713 54277 52807 61586 15538 63772 46261 8205 36892 51973 31498 148 63640 46323 4509 52107 48831 3571 38320 39888 31727 37039 14760 63574 40163 45749 5633 56726 44893 36050 44731 3391 46034 48133 53427 12408 996 48829 35989 61621 47554 57562 53409 59918 23502 40919 23091 456 47138 52542 2556 8558 47675 59343 30471 13466 52508 18407 10987 42805 48359 40129 15944 43953 35391 33807 57840 41128 889 59169 3387 47812 20494 33096 45659 3650 6050 30673 61935 47246 28400 36881 12081 54459 11571 59614 53972 64317 48779 22466 33749 24450 61676 27683 26127 63089 21335 38478 17322 62094 36715 42773 61958 57075 22344 62919 46957 42643 430 27565 50584 20362 33602 14065 37477 37456 8788 4029 28589 15372 14085 35954 40218 24036 9626 958 41219 41584 4012 43115 17925 57141 17464 33701 30418 33618 39361 13191 55148 53253 35280 63374 33156 25311 44713 20447 36586 57130 860 506 37182 51840 56494 9894 35278 15235 38630 30052 30984 27649 41255 24199 13549 19747 61613 23625 39388 35290 60465 842 10048 12033 26157 20727 33709 48980 59407 43568 62421 30109 24965 23576 1886 46181 10799 46692 4598 44900 47449 46112 46235 17392 4691 18738 41309 60941 15171 39496 36640 43932 64121 45756 19266 59648 52791 20338 45652 31383 39262 52508 24414 23626 52718 48236 15576 14388 4827 31558 13251 22836 37462 44954 43158 62509 19798 38005 25499 16927 47590 60361 16797 17005 54619 1734 38464 2901 60271 29581 2601 56930 20820 17340 5106 33796 29397 39787 46707 9797 25820 12818 53489 64003 45934 10182 3726 41727 22856 32971 19318 34145 26292 34185 52183 3739 3715 62696 6552 2739 28525 54494 32944 52683 39387 28398 41720 22105 25976 21820 4710 38105 3801 43499 53792 20961 20469 16042 24390 51595 24223 34294 14158 19089 37484 46140 34929 24369 7059 15071 19337 51806 40239 51274 9957 42603 56585 10347 36270 13548 58314 58459 24114 46038 18957 23364 59772 47380 34058 4803 37709 13872 7679 21558 60310 20586 59592 39650 29927 52444 47507 54793 50652 45194 48128 4347 41459 26546 43054 10871 23743 9057 20039 64128 63770 4671 37831 37533 20150 18246 25053 9024 17607 64340 49337 156 35680 62904 60026 11079 37515 58756 2242 16158 47575 35328 15409 1875 49221 1208 15315 1456 7600 17347 54521 17841 48767 42578 39957 44769 10131 33146 42251 8579 58042 43928 41008 20869 63303 41784 64460 60437 7053 22774 51877 48715 35255 12821 61273 47567 19155 37502 40435 27185 53996 61505 60165 54875 23193 0 1333820791 +1024 34614 62608 47855 39177 22097 917 39696 19370 61152 59631 4956 60756 25132 38351 47272 58245 24610 51045 13218 57688 21665 40678 16328 53640 35501 27031 813 36888 54736 42416 29595 61300 11352 46006 27440 15563 54847 2212 51467 1716 5684 38336 42370 59722 8428 7287 38607 33349 51891 25113 47580 7457 48766 51906 46972 10234 58099 31669 22059 11079 13021 36967 58122 20770 61158 14877 58037 63951 24512 5983 48602 34421 45263 43127 52691 11562 15832 19775 35464 29678 60073 49426 46499 18404 24291 21431 55290 47006 57174 33233 48638 53058 23189 2518 4722 29163 40913 28448 61134 54404 33913 11782 7013 3472 43374 37920 15303 46008 22427 5394 25050 50893 44036 44301 45933 5065 17864 19918 28961 64257 50196 60434 7018 56614 58373 51852 1913 12404 9461 22044 30595 34673 34972 36233 35070 31565 34718 42822 39761 30596 41535 43399 61899 40561 57016 8406 59674 31642 5140 5067 30212 61295 33370 16868 49375 30503 37706 24562 29409 6523 53416 47872 5734 9746 29276 31528 31600 16095 41040 58408 10366 21660 63426 12054 18889 41205 41575 4589 61575 37700 12533 45780 18852 12855 4365 43215 23793 49510 33913 61783 62699 29626 28120 21485 26381 49396 38821 19402 13966 643 26381 46909 28656 30671 35165 50970 60017 30982 13464 44466 41528 62198 34652 27345 23554 46610 36231 64189 11615 34528 61232 25922 3173 10007 5027 25063 18886 10148 16198 34149 45653 54851 55778 3117 63747 42794 12787 28270 11964 15635 44871 63462 45483 15097 51258 47720 23203 1179 17824 63661 4879 38727 27475 52221 21536 58338 23498 39638 17158 27959 11332 38322 23024 50779 33367 59405 12408 4547 28670 8784 33244 21576 36414 42884 37785 18370 60255 29857 53841 61041 30404 28578 51729 63788 32810 12423 59827 51605 12000 18207 63171 41178 29099 12672 36343 5985 46548 40111 30084 51385 61443 10933 54937 59202 10201 25590 20894 50175 28908 19390 52597 19675 9314 12045 38697 18571 35912 18023 8743 54267 43746 54578 5509 33876 41973 15170 39494 53315 30089 61856 13140 9413 51736 48134 10747 23570 205 64085 21332 42737 45653 31513 27219 45701 45073 11867 13667 11229 39736 61920 24992 16912 17765 23357 55136 33559 50391 18790 45346 47304 12412 12577 11884 21067 6964 3923 13792 44461 33842 51298 7793 17717 30667 20035 9311 23514 40585 18474 52554 38009 37180 62627 21956 36767 26797 26485 3116 16174 52834 44808 26032 5659 18635 39852 9078 18612 29332 24793 38262 26607 16504 44279 17456 49475 5271 64099 23688 15910 58148 15489 20129 33790 21335 13442 17395 34181 23130 7423 58146 15494 5845 16040 57708 5986 60757 23989 38848 35234 11344 13604 31495 7013 4483 27406 33891 33544 26583 62395 48934 54950 49197 55222 61958 45211 27590 62651 10373 34012 46466 4778 16631 6927 2087 12901 2602 33842 28147 63549 892 52626 769 57143 41098 34591 1544 14270 33328 954 58183 60871 38399 6250 15371 22820 30264 23836 10586 47721 30814 31316 29209 56334 48133 47170 57605 16586 6290 62377 30830 41475 30408 4835 21745 9502 43245 57453 36350 12622 11465 62707 56483 16134 3257 62448 13612 4643 29037 61883 7363 35896 33110 6922 21419 46688 36212 43953 48294 63446 44452 6500 55810 35514 61398 1112 14753 39197 34244 18271 30933 43097 60548 40543 6439 18195 19313 28590 1268 33955 16743 24070 55764 42731 29467 61462 45296 19654 15313 21494 30904 62825 54548 35672 11083 24278 51141 61222 43630 743 51282 4657 40246 52872 43394 45940 49247 28966 49187 9701 35567 46354 49482 21308 37813 18471 16083 10549 21333 6733 50926 42628 40 51820 21134 61437 6721 23259 53246 10288 53588 52147 12218 27235 13198 41995 9227 29683 59060 58649 17645 23650 54747 59374 59279 47948 32901 17557 30664 11463 46698 16814 35420 14837 5676 43090 49615 33501 33771 62720 19960 58831 3957 54140 9821 56202 25002 24569 22247 4026 3980 55683 59057 44064 29278 38388 28042 13208 61847 44496 2454 19090 58505 5821 46775 56540 63480 63047 19074 9961 26159 19382 1702 14697 42927 58137 19941 30126 13253 8603 21469 37936 62163 41294 61283 25478 20852 61726 59944 58564 40306 5614 58234 19248 57972 58420 60252 33740 14028 14111 63235 35218 24935 61770 41320 59361 59360 18121 51409 23100 48015 31495 15669 18155 52704 56932 47279 56022 51866 30005 23159 61635 35066 53159 28982 9640 42490 62447 46929 25559 61058 59386 43985 6160 3772 38570 51748 37269 46384 23934 60212 12364 22269 17658 42795 45793 27192 27187 53301 12563 36925 1141 54375 26840 35860 40220 64080 42370 45150 19064 52757 27987 43937 63240 9405 49212 26038 49225 2610 64343 17232 53112 34998 32904 31565 34859 1537 4457 44329 5761 64064 63026 15121 7410 51752 44996 20525 29598 28958 19571 22255 51449 33262 40048 39426 37893 5595 14610 51549 59325 28000 5740 54596 20961 41421 52596 50173 34170 57402 8567 22301 21103 44504 49991 53045 44323 12985 16468 54256 2251 30569 28529 33563 42553 27918 24891 39550 17423 39771 50901 16105 28206 63057 4977 52413 25606 49191 12875 55140 35617 54102 63621 21958 31183 36479 51954 58656 43120 48294 44436 18642 5376 21595 2594 11833 59026 52416 38938 39975 7357 60968 8450 1496 62685 48470 18132 11550 61359 48710 24884 43521 22040 37000 21924 40555 63216 22828 58043 6832 53623 43834 46235 33872 45647 20750 7121 49497 5230 9637 34486 50167 48450 38230 55939 4710 18077 1016 15053 6742 33287 46216 59910 18848 5633 13381 10178 1696 41077 25141 8480 37549 9956 26517 38751 43529 55460 34216 59433 61867 4059 46990 56535 7446 53831 3735 61109 39144 3063 57402 8328 52222 57394 18327 61085 52230 19935 24046 63894 4034 12999 22166 11477 41812 25592 40050 42664 56595 10140 58006 31246 57496 33659 51725 24152 43767 60961 2684 43754 28159 26811 39286 9747 44807 9030 22149 51112 724 9865 58913 470 9192 22646 50003 51849 41242 7782 50707 8162 63160 56552 22230 53587 46647 26838 847 20284 20668 13323 37610 56315 50616 35156 19597 5042 48882 25044 58256 19489 58491 49525 33072 4678 14453 38520 61682 49779 8936 36174 62670 34644 62173 30993 59559 46058 1289 41026 37891 31052 11053 44886 17403 8094 44405 45568 10306 36960 11386 52384 11635 45897 24883 51636 19698 17217 41171 20394 52195 29375 55777 4381 38248 19047 16192 18826 32990 29240 17600 8385 60765 47007 6095 54729 29441 5881 17367 22899 54621 22824 28574 3353 810 48456 36093 38639 38043 18029 44266 56453 8748 12432 2230 11779 15323 42366 28141 17662 53335 4586 41696 37066 6833 47166 31701 49371 56687 5688 36243 50004 10439 45772 6510 17056 38271 30706 8406 18670 9807 26009 46126 44707 10429 13376 54921 773 8469 32895 58367 56984 20006 8231 53913 33213 29283 41027 62375 22459 40764 7172 52298 39533 53117 46063 28521 22483 20067 39944 15821 51942 18764 37913 37895 4909 17994 33424 40143 38528 24185 18126 6606 36461 29621 4286 56801 64343 21134 34609 6559 51543 2467 10975 24277 3375 28835 48885 46856 37494 14674 24597 19667 21424 18301 20 53240 36958 57283 41194 23394 63261 38103 35014 55665 40679 53131 35689 25137 9877 21110 24515 31670 3918 5397 24269 38254 39695 45196 12743 30525 17960 6460 14576 52942 54277 56717 35945 51156 46096 61314 64313 31265 60112 23833 10708 59494 19263 52931 40102 52403 46862 11271 44613 1162 24339 36070 29628 40078 59195 10160 6997 44821 5736 56630 12465 47211 49866 57724 55063 46831 63993 35662 40794 37698 17451 7899 17906 47541 13437 14569 42825 27432 22420 9437 18349 24916 38160 40133 6380 33240 49683 18544 60938 19805 432 1800 56837 4970 12145 57615 32991 63547 36824 37553 29328 61226 6994 13162 49001 49632 5496 1611 1584 55068 59064 38558 19731 17370 11370 24466 19904 33441 47586 9631 23940 58978 58121 2279 49110 9967 25149 57422 23412 35016 57744 51455 14263 3637 51996 28664 37191 59656 6189 17714 30895 40865 35300 36792 22745 42221 29777 28730 62671 20122 45246 1707 4768 47423 54183 2415 48848 35705 17172 36856 43608 5408 48504 35705 45276 18762 4208 37074 6196 23338 14718 20553 44654 31120 39735 41492 60369 38972 54232 29361 43827 5594 3709 16198 41448 58625 54071 4166 61887 50184 14929 60120 43457 34371 17441 7220 21087 45164 5900 25687 43715 29858 35893 54593 36786 44416 13289 61425 20067 45438 52597 38175 56900 61792 10514 23171 46160 18327 4528 47713 46933 12076 9539 37806 23557 49029 38392 7625 22063 31040 16479 50376 61888 45267 34961 28541 24632 25291 46189 5054 27515 53542 38856 10451 28259 25306 52949 7766 39639 11995 9399 53008 28266 26374 35963 26067 33593 5478 61914 18432 51404 39721 39930 8575 61024 1305 39365 38559 19096 49961 5372 20329 10363 52441 53969 18953 37616 9282 60414 20555 26574 46681 24866 38704 34998 17104 46618 15591 34920 7237 53603 734 22815 46586 59040 27707 57311 35387 17837 55472 42908 59047 50850 57523 40158 48084 12417 40621 21774 59008 38844 37954 45328 58702 25383 39215 19034 39463 7692 41996 42397 192 2134 39545 6644 35066 12687 45950 8049 3081 46459 57325 7151 18052 32990 7343 51603 62824 45487 24389 33479 35529 6438 33199 588 16968 26674 23659 2042 49233 19033 30392 50159 437 30667 27138 45041 63461 25328 62505 36558 36682 64301 56632 29486 48402 13887 28531 44220 974 40678 56470 6492 765 40368 13345 51031 54648 13407 36190 8106 18709 59045 35960 879 11469 44691 14776 24556 57348 35060 33533 8475 47276 27363 38089 4884 58329 29464 9658 8200 9456 48790 6950 38965 28967 52365 21842 27045 35125 7726 20266 27160 39873 9763 62683 44356 42056 34532 14128 18021 55541 47691 10339 8842 1471 24539 64101 34886 47968 21568 21414 59100 50763 20517 61929 55076 11040 58557 50995 4924 47473 9458 51075 44106 39379 8981 1071 19330 61861 5353 21708 47966 4160 43079 32948 5869 61937 576 41284 56001 26180 35687 9537 11221 55861 40504 18598 16949 54403 44713 6817 29623 33555 3612 7437 43566 3244 50619 54407 23940 16611 13731 30899 20042 15367 9036 17644 26915 20765 45282 17086 27252 21621 41937 34781 56512 19366 9921 43233 8954 55124 60349 62984 44881 23093 1654 47736 56027 9728 57368 22812 10753 54377 58546 18932 22786 63359 29288 49991 20920 15052 21053 62849 58218 31473 4091 22797 29234 26873 61032 53434 49476 59173 25936 26742 24846 21985 42246 50965 36260 11777 18947 63908 23010 27281 6239 47264 3619 14966 49444 51594 54477 19770 64432 11331 21646 59320 63359 18752 34449 61979 60719 47995 62329 58012 2229 31190 63836 14855 3385 45372 40870 54390 23660 27711 39484 43926 40547 47984 2376 12552 8147 10998 16447 30144 4614 18149 9982 7072 34893 24447 44089 15974 19694 57138 16165 59184 20409 42218 38050 7812 12422 2710 11144 49581 55107 57615 17165 42433 41051 47738 20524 6091 42838 38791 13024 31415 55447 48900 7828 51532 16202 22803 23947 56662 33517 19995 49279 49215 50509 53008 3449 8852 52880 12104 60294 28577 14125 57897 40859 56208 10610 48032 5883 64375 48597 2138 7136 22457 9258 672 44281 39824 23216 40575 51254 39867 13246 63557 34000 44041 37876 51071 43837 20753 15766 57777 36591 27929 42757 3092 45374 29254 46148 38623 18281 5072 44913 14206 13372 20005 2718 30171 12524 13431 55594 22429 53952 54394 36766 57616 19621 21845 45203 50464 9405 54154 58337 1896 10451 49639 12551 18351 23766 36809 61672 57927 26571 20007 60115 13922 50711 19585 16011 20388 3062 62519 10562 48029 22514 52141 22667 53102 9560 18429 8385 7626 53095 14126 21189 53533 30259 59495 26875 51931 47484 18904 51462 40304 1397 10514 62033 33994 45517 54623 56789 51599 37845 10700 35961 32903 45029 41290 23294 17536 49113 41158 56280 26038 64425 19350 62873 62657 37452 36977 25504 19390 14150 25141 24039 20654 59504 40810 55378 33403 35060 17889 15984 51385 49513 29367 47088 52973 63203 39746 17477 49094 9857 13778 25754 40526 41745 40613 43978 9279 10939 41389 1007 51904 56963 1557 51658 19297 41899 43139 48017 61488 55552 23041 35794 36638 25611 37092 28377 3753 38174 59241 31329 48321 30970 13331 54462 55996 56429 20742 4758 34373 17503 17466 16304 5393 27811 21515 19669 7084 15913 39284 18246 17680 36235 2041 16459 43456 39843 42186 57875 64398 50853 50292 61069 43145 49829 51049 58888 4178 15618 55863 33722 20609 56660 40610 12773 11438 1092 8407 53540 10506 58769 55064 19757 33798 55155 53602 56170 58696 28446 7648 3697 24836 8521 55306 47855 58071 35527 34249 62514 21864 58219 43238 50324 26417 22880 9024 35354 42811 6078 59651 59823 48725 20576 4580 36378 53697 31600 28803 51266 59432 24362 1044835989 3462402859 +1024 19830 24096 44582 21047 63682 2969 14844 60864 15013 44781 16933 52066 27241 44592 1317 42499 15824 45041 61481 12531 2120 11353 21441 19102 27660 43766 63191 24886 31399 33418 51577 21585 53702 10241 30974 22674 55058 31293 63850 55401 12169 27918 48880 16396 53392 47441 39521 23139 23210 30467 60411 24663 56910 45335 63981 42595 55794 25885 8722 11629 43382 61133 38892 19384 59691 16307 30396 22754 12304 31380 27545 61792 29093 25826 4323 50379 22851 15105 6796 49160 51476 48149 6282 59372 49274 5624 3820 57463 38016 43367 46979 37880 42651 53856 22736 39746 6970 28267 35452 13689 39996 62674 26464 43967 4410 49179 15407 62707 16787 63579 36597 58034 52613 15119 54949 20481 37335 56711 49885 14262 23025 63661 10260 31692 59492 10324 47004 59964 28344 16530 3137 27897 47694 58257 18056 16876 49817 39532 4836 36141 5383 4662 473 21510 4258 31387 25165 39461 30817 56847 55421 3227 987 8277 11861 53919 28801 11705 17835 61802 58796 31481 23493 43526 13818 30854 16093 59614 46905 576 62763 52269 49930 7553 19109 11293 64356 55525 23283 36227 50371 19206 57911 22412 26002 28954 44020 17591 39092 15986 44192 37525 56353 4911 62281 17341 39730 15579 56473 24135 29113 29208 15856 14079 3318 23621 35815 37319 21481 54143 54118 47669 63611 7307 52441 12756 21921 33082 4119 30584 10359 59205 12319 23664 41837 45965 11180 28748 3051 59179 64012 49701 56650 3075 5795 10709 13709 54678 60669 55540 51276 38924 13553 10990 13721 5145 39104 8001 49816 21366 23195 26030 16229 55725 3044 47483 35989 53063 14690 12823 55192 19926 58388 48600 7219 457 15081 55618 43634 41036 11884 36154 48373 23538 58141 16001 57792 54198 29670 49856 43680 22327 63035 16851 55133 16343 28910 1203 25265 17371 60347 10318 64164 22144 17025 55680 19543 55664 37096 4696 28640 60440 3045 28690 9847 34387 55281 59469 26432 15291 16128 36681 46717 28185 52109 57474 5498 47605 28418 1404 35300 8879 28744 3971 21025 6286 22102 4917 5592 3767 9301 19877 30989 14425 14917 42924 9597 29513 46571 17209 24154 43357 27463 57226 28697 49072 37449 57179 1132 11362 53048 58755 642 18886 4503 5343 46603 24095 41586 3767 24221 1014 11436 29205 42064 3503 34142 6274 60847 54727 15015 25541 58503 4681 64233 33722 5006 47854 16459 49329 59921 11951 61415 25104 8452 48976 54591 11309 61554 52051 34055 16253 46703 61457 52137 3597 41851 11617 43380 4249 5004 59847 57638 52065 3982 62653 30389 40699 54034 7119 38678 50792 31052 25574 29269 23515 8517 43798 15574 2898 22213 43543 24676 12678 24657 21935 8956 36473 16308 31237 63856 40726 44681 20299 30057 49578 58137 30921 1657 6190 2185 36727 13975 35082 12108 59250 39266 62163 42176 14411 39424 46869 60547 41680 22446 11042 2401 64396 44603 56075 12634 4872 36249 42681 26100 54548 14285 43249 63882 19139 36572 50302 41661 27309 41753 25134 15715 7549 9425 33523 19570 56665 17825 44344 29887 4305 12453 64276 49842 7141 36722 62855 37648 58073 10482 54330 26576 14038 1966 45846 29227 50324 56346 14814 6970 58206 7996 9583 47229 47001 5577 50213 33501 40816 30977 40353 27653 24783 12118 4879 42831 2153 63136 20591 7102 41312 26195 62823 6488 49261 6377 40292 7752 3037 55659 13629 37123 16188 44012 44302 9613 58033 44238 10409 44295 58427 19740 13268 62313 50544 60745 11560 2064 39119 14836 55720 28556 1860 21781 15310 4486 10571 30744 20624 16582 45278 5922 25277 8456 7778 11948 33762 22495 13009 54765 23333 37248 52537 60772 51365 384 57777 17540 20107 50800 25305 26708 50608 29931 2167 21790 56159 35413 30243 64021 48598 26780 28761 54877 46714 62226 50699 48785 234 33176 21368 33029 18347 45380 61314 22970 26404 55802 5981 48503 40042 778 1099 63981 30392 12153 29141 51068 31370 21484 586 25931 19746 5693 313 8816 24586 1393 55899 35587 54937 62955 47536 61438 31577 16295 20377 53087 21546 11524 18283 2173 33918 2048 50045 41690 25031 33383 53757 208 35815 22682 56980 15233 44849 64425 29244 29189 49187 58785 26262 62659 23723 23882 46047 24853 5444 52372 52369 51433 59554 9656 44051 54541 30309 26850 2526 50221 40 2966 52454 4740 21835 2848 40866 60531 16938 42646 50632 51461 6121 34377 34943 42702 8707 59884 15040 17883 29835 39164 39656 617 3962 3318 3260 54941 57700 6521 44855 49099 31087 33487 43528 2513 3599 60728 7832 37611 24277 20838 58358 46024 54530 2098 48514 13128 44242 48801 56838 57841 49699 2490 49167 28192 22838 31417 28836 8396 13590 5977 7974 27317 63332 25084 22164 26531 56417 33813 33827 50300 14860 48005 40328 45275 27167 58091 62636 18174 26426 37263 41523 48526 2093 26525 646 44270 20484 40646 28834 40752 7782 44652 29505 11927 16135 28025 40729 49620 29867 29720 18461 51754 62963 44825 42559 21039 37641 6270 60592 26202 45530 11845 13609 40688 10225 23284 29462 51495 16917 63136 3096 60639 23120 53352 3474 45804 31166 34596 60509 26407 39560 24067 41349 15910 23540 10049 40092 16327 3250 15611 36366 46160 19375 21038 12206 7854 57321 6647 11457 36371 16148 26504 62139 23230 36955 57508 35482 2786 15272 3181 41073 15775 25425 37218 1629 61511 62436 4577 2873 12835 13693 56794 38660 61748 24242 39834 55125 23941 23270 45870 46984 60953 25430 29025 39055 50244 761 26562 45034 35603 49470 60703 16187 59211 4234 6405 36071 60314 33750 19877 24041 62113 14805 4562 524 44173 27599 36505 27561 15447 4417 19753 27462 41008 59857 50673 2075 15733 63374 60167 51569 19731 34934 33272 16440 22614 21170 15709 20266 54479 3240 53318 63541 44372 53251 57470 50642 14466 25439 19320 32830 45733 5101 52773 38228 34638 63424 6559 55000 9971 27313 52485 25239 38597 54249 10277 33253 55804 59526 62567 7228 61343 20829 22896 8760 7126 55970 20293 58425 47298 15297 55025 19824 10974 16958 51710 12900 27717 27416 44784 41860 22362 29533 54644 29086 29548 6861 52530 19180 55985 63346 2448 48767 26299 11195 36158 4003 54981 46347 25053 775 61886 7987 36893 18532 30971 260 33814 60352 18168 790 27266 38213 29199 15931 28626 14409 20637 26612 35786 42555 41842 2335 16853 21585 12460 23967 46689 5936 56337 39493 31023 43248 56734 51681 62357 54107 15769 20569 19848 18026 61032 39751 15143 10165 34143 30514 47869 15091 57632 31519 14431 51307 13667 98 44053 54200 28202 9160 44284 58875 8119 26785 17253 50263 42437 59556 35710 30508 520 8445 28071 50265 23693 57757 57116 5137 46265 31204 40277 6509 40237 16239 36296 54318 23691 5548 9044 51980 17434 36297 39925 52605 43171 2680 36394 64035 18240 56309 50322 15548 29313 30986 45655 6696 22466 9654 25291 39771 24936 45540 46869 6877 61133 47664 18055 52808 29144 9494 13904 23937 49482 42713 55512 30042 13627 64230 27483 55778 2611 13933 52375 48828 58536 5545 3758 22953 8695 22839 59192 25957 34025 40925 28169 55995 56223 56377 44276 8189 33839 5144 15883 44520 3134 9883 5419 49980 13000 60318 10835 22943 13419 57442 56202 11180 42300 934 30149 23345 42347 50493 10147 42465 22812 55523 3748 9302 20020 53306 27670 17196 42531 5319 40870 41452 22845 45597 43954 40382 25241 55364 9247 64172 63825 25071 56991 47763 16561 23835 9144 42691 14122 1207 60990 10596 39059 5478 21558 54063 2429 12270 35867 51076 54032 972 33922 31002 37134 7834 50293 33190 46469 447 24307 52889 57583 46520 29431 18158 13660 52653 24062 48672 8665 12061 60486 60590 56734 23929 39678 59434 46627 35736 13521 37196 28196 12782 676 48922 18030 15776 42738 63111 28052 45667 19605 61166 6362 21923 41991 8763 4903 76 55921 935 21243 5321 49451 59585 16734 16986 46239 42698 9168 53146 373 61610 19392 25628 53192 37908 14963 46995 21414 8987 52624 21481 42820 47891 28809 6795 14491 42181 30828 49869 30271 48702 31041 29995 28091 55355 59778 26475 214 744 25505 60156 36323 3696 22128 59293 31723 63506 20270 27898 60602 55634 37067 55553 2308 26473 55004 56736 34429 55285 10622 20349 18058 34791 20695 63755 54418 12794 17275 13404 10321 48367 54934 21247 25808 10964 23014 63968 29393 23647 30788 28410 62673 64334 27688 17430 51520 26754 50417 28697 16490 56820 46994 39206 45459 55169 50048 7828 51103 10369 10066 8911 5271 6738 59845 58712 6755 16258 5590 16360 16953 17584 41169 25265 29650 1894 8226 58953 48434 58336 54387 50828 28337 4214 44929 44324 53118 37117 30858 32802 53971 37236 10237 53050 17197 53332 10593 62032 48975 15242 37645 15955 29566 13852 30828 42624 20649 53112 26396 63474 3415 42900 53519 26514 11755 23738 43030 29163 52629 1721 2733 45443 12141 60288 0 33841 2452 54469 48883 4766 60614 49505 48193 62510 9059 3212 5266 6658 15222 52757 38781 31557 14448 33960 43592 41831 10435 23688 23057 51828 10174 5756 16631 22794 43557 38065 7476 26891 52492 26563 21597 53643 12892 19137 23649 28226 5474 11975 9259 48213 8086 38358 2355 24794 6044 34473 25196 33901 42447 55542 25349 13995 20835 55669 55117 61680 36815 57857 35872 41837 42151 53436 23007 4361 4535 36202 13376 15451 48839 43782 33371 44068 37961 41848 57148 1420 55870 23345 21996 27354 26045 52539 14199 22244 33661 51216 22744 22957 21133 60725 38170 43770 23487 18577 17959 32832 60142 18768 60289 33695 28157 29168 62116 21620 19088 30249 50619 34924 54198 50186 24020 59417 46635 38620 10096 20290 57485 26177 22230 61357 25629 24704 61487 27672 42121 52708 51351 54 5986 25201 36387 53797 13648 22959 49594 8310 38577 9662 15215 10792 25015 33465 11035 60408 42560 50272 52734 12479 56113 12106 63421 51597 10114 40341 20434 33394 20401 229 6468 60627 13961 776 34999 8506 52353 52914 13684 59743 40436 15523 19577 51713 56555 36699 11932 20415 29349 49947 17487 20150 56163 54617 34907 13938 49342 20532 41858 1683 11842 504 2711 33228 16749 28381 53463 35067 38379 21150 59645 54294 8788 15480 61161 29501 37687 22445 62425 27929 738 36506 53531 26935 38567 18494 2626 37250 22092 33576 64299 24422 40110 43459 27666 54737 43214 61765 32777 14227 20019 5119 9275 59096 14421 55625 62575 30016 35747 43987 15028 14320 42124 28571 38746 48474 33041 61984 13393 62650 48432 2079 45729 45572 5752 27891 30498 33512 13850 42933 47986 46177 49647 41839 34724 22246 24673 7952 47113 17465 48518 46538 39049 50131 58808 18536 24152 41254 16310 37683 54768 42397 7877 34017 37444 49654 51296 44994 45780 29269 658 28273 5167 26857 37342 36325 54336 12505 27936 27798 62062 47413 44979 30200 21371 48358 28371 33321 62092 12751 4761 46772 10786 4588 44716 60615 2722 21365 12168 45106 37833 58879 47536 60267 34421 17784 54020 50973 26258 16760 40757 37682 46972 59982 54915 36217 19074 27566 63344 53338 37975 49632 52943 21150 41578 46363 58098 50320 6748 50703 56592 46068 5326 42644 51414 27470 64298 25524 34620 16347 25009 11881 14206 31203 58394 42167 15630 10284 57553 50909 16528 18554 64282 60490 21591 36579 55017 18034 61395 26327 38848 2712 49729 56626 46852 9578 50658 31226 11844 41458 25665 17119 46384 18829 28375 45552 10880 11712 46408 61854 22464 53821 4400 64477 9714 8982 8928 63218 39176 47346 23070 18568 45436 46248 27311 778 1998 18421 11618 26612 11408 15545 21409 54566 43051 31457 29488 52729 237 42013 19746 55675 28530 13287 12624 52926 51720 15489 59462 60461 11044 29982 47366 20756 43770 46708 10135 53815 27260 56269 29417 50039 46538 5777 9 14950 41637 36425 9023 8825 52847 11245 8136 38676 29442 56653 20647 2158 56529 21714 64101 5996 36324 25151 13386 18556 23355 23188 38635 44581 54465 21168 63823 35060 54908 13296 17276 15803 832 10043 53825 56285 15948 9136 55610 23410 51439 57914 10454 46416 64188 64146 8278 4944 44207 34745 56515 46956 38219 9441 51372 51277 22215 340 7541 17266 63698 49111 59053 33 1593 32782 34243 23395 44606 24446 41343 39525 8476 21187 55886 40826 50644 34040 44097 40623 44197 1484 13087 53193 64492 15843 62245 49550 54967 28160 34963 50953 37194 1653 37692 13504 53386 54967 52167 38284 14702 64263 7526 16266 64369 4046 19628 54857 1827 5231 50390 13081 8912 49300 22008 54366 19306 2423 18504 62658 55396 22341 36090 28615 29015 5165 22343 8356 36849 13883 20731 43586 16378 34733 23563 16004 30010 2535 35112 3591 60945 47486 43120 32844 58284 29247 26249 59219 54007 27426 61562 19878 31389 39339 39759 53692 26305 22430 3140 41077 3132 26524 28579 2054 20284 29638 51990 58155 10418 45944 22330 58539 61767 29403 970550742 3474144360 +1024 42819 25150 57662 28292 41584 56082 22613 10008 6476 11061 8929 62831 46750 17915 21446 33643 10950 59327 14247 6617 54050 63917 24416 1960 30730 5722 17226 10968 23250 12577 41565 47486 36194 36774 28473 4591 37169 43680 33187 18417 4711 47899 34963 30123 9854 56509 5922 37423 63642 54616 39724 48586 49062 13907 894 40072 26477 2872 28760 31156 15399 46405 21250 42644 36277 43893 12666 61548 13886 15941 25360 8574 14659 58684 46975 42141 52861 41118 62805 39778 56520 28553 38564 21040 13239 46286 38410 60397 29035 43631 45379 24712 45144 54269 10072 30657 37477 20778 6999 1836 2286 37345 60154 36840 51411 32995 61354 3760 64448 45874 50250 29563 44529 12571 12588 55818 38638 63351 7790 41040 42059 26407 10047 14283 20085 6968 20017 60345 32816 58172 15490 53811 28421 24976 48695 52817 17127 21886 53724 50116 23704 64365 51699 46309 52215 56532 27036 18787 25792 63900 24819 55890 8424 56310 20905 37761 10912 29119 59523 27938 52486 58818 13588 503 17102 27132 58072 35778 49211 49220 37248 41008 48656 46858 55572 23967 23604 34743 12106 51964 24818 33837 17656 24593 56278 56986 50351 14003 12512 25864 24738 27491 25691 32902 42711 39546 34551 45034 901 18003 21077 10676 60594 556 11908 15731 15719 61989 14563 35219 10981 59755 39681 3963 15167 13526 44337 55548 8126 20171 16676 8420 20639 15716 30630 60820 64394 28815 4751 64412 31032 9931 28388 14531 11004 61511 40708 40865 29995 59100 49539 25822 60869 59503 2521 44196 29051 21860 55017 42589 23359 26424 63345 60258 42176 57648 13960 3661 38812 687 16737 38278 35395 17972 9552 37308 7352 9730 42374 28226 42735 46262 60346 12422 54798 9551 5593 8721 48808 52371 36430 33679 13029 31440 54090 3692 12769 16606 18841 61657 375 52148 40455 40545 51340 7147 57618 15577 15993 58543 36856 48579 6200 20011 16443 20044 57383 18668 14179 27551 47200 42631 12309 3398 56021 49025 25407 46175 25831 28311 41897 59464 10257 27727 24540 63500 12586 24498 802 58472 47163 10761 29235 28441 41714 24405 47214 13481 29600 50449 5496 20819 26511 51083 59305 13344 63595 8621 17450 52555 15548 28680 38976 10933 52913 23160 20528 46376 27687 20864 57497 11128 63831 21213 13478 63736 59507 44032 48461 14992 49416 41836 14687 1838 46522 12452 10779 59027 3389 17208 49550 37753 33586 64250 52029 8179 61671 32808 59213 53063 7219 61117 34092 3074 57656 50947 28761 4947 43250 22709 4060 36386 17392 292 62078 13742 14894 1851 13960 3623 24954 35137 29389 51592 2103 24273 829 55783 34940 56097 24585 58183 25105 18546 27359 11217 35656 20327 48307 30800 42615 7353 25114 28762 30326 21686 35247 21350 25519 13196 45024 43972 26263 33049 4138 4044 27137 36410 36972 51265 38784 48385 18420 29145 50759 12830 59242 51145 53052 50941 35529 8428 35869 288 33105 1661 26682 6700 6928 24516 63964 23432 44545 41518 37283 22772 31512 42588 61147 18446 43358 31070 52164 19713 16641 28561 20931 19639 6518 20522 55300 40628 10732 40561 36966 27600 3625 42708 1021 27632 30668 14407 29562 37288 42606 16088 22697 42106 19392 39177 36257 18480 24294 31594 1688 46130 17647 3468 823 4308 11846 43103 33804 34705 43108 57316 11060 16207 7663 45293 59866 42229 35231 6383 51233 50936 53109 29792 20624 47735 49597 16956 38293 52688 8275 53503 44426 23269 19339 51771 27188 37182 13820 66 22152 7320 58800 7173 8230 19182 4616 11072 39586 24284 33558 33563 64 54453 20915 4137 11346 60203 5832 50410 56019 8716 42024 35761 38573 278 17053 55591 10120 21865 54263 2447 24838 55573 10281 20719 9712 1893 32768 30805 28505 24581 5799 18529 7764 55489 22458 4586 1222 20807 9731 13382 23966 1386 25820 61228 22831 47551 10539 16378 29858 59086 33965 1031 49637 5357 62683 39118 53492 26849 43334 43590 8994 49530 24830 41437 49802 11567 43908 44068 11089 52676 34449 3175 7331 45607 4030 14301 13778 27184 16737 434 56685 8208 20166 16721 57848 26787 1121 1373 19626 221 31338 24077 40559 57701 9713 43612 50322 61600 45318 336 17007 11668 63207 37634 58305 2576 27213 12514 13711 33097 19997 3951 53008 23477 32925 45761 43270 63552 35116 42438 13896 6392 49150 54659 58991 12781 35648 44960 30622 14086 22847 15959 25525 7821 61306 62891 12781 28306 15095 3948 6113 10910 56203 60020 63589 56184 46846 3758 52675 33781 35411 18488 15220 55564 39486 8596 28330 7088 60473 27155 63133 34874 43083 53244 44033 18968 10188 11202 304 11455 20805 63837 17345 42599 39239 23241 384 25832 8684 51164 9886 11384 4491 36988 38279 40964 45483 57653 12902 35520 61123 35714 19862 62044 25489 60786 62023 20931 35398 8723 6169 61393 12501 7123 16001 20004 12549 35282 23759 11401 52245 21863 20616 26958 55822 42547 53336 45935 49984 30862 36726 63987 54114 40065 36107 6427 30074 57414 37213 17066 44353 2634 42373 47938 57304 42107 61639 56889 44349 46508 22194 7631 37292 24698 25795 54882 29734 5568 39474 51461 46863 44122 17409 12806 50625 61247 54625 17459 50986 18686 9821 41692 42149 29314 37964 57191 43902 52369 40786 16726 14711 24283 27669 36736 12329 23717 39499 16785 42093 30388 3346 4170 42615 6293 37272 45135 36616 54449 6963 16887 2938 17900 11893 8558 54898 18664 11325 45109 7719 8430 10773 54930 8690 5989 16977 59673 28550 55355 9642 39681 27474 6884 47468 40820 45244 52546 36321 11155 19508 27804 939 60975 51670 6414 13720 14550 54049 16669 22717 59003 19254 12201 43693 62720 4504 54174 14030 63774 22217 61531 58 23232 28130 11262 51963 11360 50063 62899 15522 57931 20578 59317 52350 20268 7315 59871 35040 6446 38827 36169 6021 50028 16702 27620 38376 45890 37142 786 17299 40534 23972 13139 54784 52820 26040 16214 40866 4301 2131 63426 28780 26036 60642 18970 50918 60547 62267 6110 38725 45929 9624 24979 55780 20992 20850 39381 29845 61159 1884 34391 46954 26014 3033 41132 44755 37673 28437 54649 42976 54350 2679 46076 20391 6584 13822 59734 955 17372 60310 46677 42764 43073 49696 3965 17496 38185 12630 59576 56641 55113 28132 17965 50720 55993 39006 38072 12354 63042 17728 29441 38062 28678 38903 1218 17376 62487 11588 37228 58025 1441 20080 41237 56374 40337 60540 3375 18373 45915 10943 26367 50278 21824 19918 58617 34126 5401 18046 5672 25687 57265 26305 42369 5085 41762 4909 59079 46192 36706 15653 60123 48736 18771 52489 22555 55262 61715 11341 51513 13245 29322 61303 51150 14174 15706 37529 14615 17799 45506 56492 46103 4231 62219 40073 19314 1326 39865 12164 27303 51417 58881 26228 20224 62988 12935 46962 27832 14921 4371 54933 36386 53285 23886 39866 54176 28326 24025 19123 3592 20956 57124 15313 27067 10486 9625 57701 9562 45305 58467 61746 63986 646 52334 957 54890 24821 29485 47130 11016 63383 55741 43114 34244 48349 60987 63477 37671 51839 26392 10101 59287 6867 42835 20853 20345 8207 62244 20583 34997 14617 22078 42457 34799 22734 46433 15739 33329 58051 27915 51727 24169 45471 392 9243 9383 22797 29091 16238 30007 44554 62673 34684 25414 43910 2437 21296 58559 23272 19541 50390 17227 29287 18523 17956 18027 22206 59302 9461 58165 14623 9226 24500 52313 36213 8633 13291 63310 18770 36730 57305 1379 10425 35071 7642 51971 7531 14683 60937 16248 36153 38079 38408 20104 36513 12584 15852 24001 933 31253 19476 13759 61370 2179 41620 30373 26727 50786 24402 44052 64178 44063 38501 26709 23710 2156 49012 12134 8025 17885 63632 5718 14503 48787 25393 27554 63298 10308 24745 49768 30331 36352 42497 27829 23584 4859 49490 21569 62065 22717 54556 26882 47843 28980 11304 46291 58927 346 52866 10544 58689 21415 59903 33897 57061 44393 50908 6007 1374 19570 9674 3957 22509 11618 21470 33631 23352 50694 43243 27209 63098 13550 8514 46002 24414 25913 13707 1942 8092 39259 50031 25082 35612 58633 35204 41613 58290 46917 44774 27258 24038 8055 56611 56308 22284 23928 33930 37696 35260 5933 51222 7842 10364 30784 39562 28411 53065 17536 42159 31012 29407 56513 25617 43960 49899 32906 24214 27665 13237 5136 4124 54352 28988 17587 59612 23996 38186 23434 10432 44233 4067 19142 24636 10121 4935 5105 30026 56071 36020 57963 59237 46695 14745 12668 13067 41147 25387 37040 396 12997 3611 48693 37997 54283 44575 60444 21448 49105 30053 45911 55435 44966 60721 12401 23741 24953 38684 59282 47836 11705 6860 11787 20841 56213 46473 55505 62852 27060 47167 46294 36907 19070 36563 27892 50917 63528 20591 16510 51541 25421 59780 11037 43628 63520 56399 37990 16231 25196 52244 2009 5056 29758 60949 56482 17982 60320 50902 44333 4059 16802 58598 26281 29290 37014 50608 3794 47721 54354 1890 44530 57049 41442 30503 61395 59481 50874 7571 46645 41258 25822 58465 44170 59928 37016 43302 56511 39988 44928 13861 28638 57361 1025 57969 55543 49991 9017 16990 30294 27967 56098 4888 48763 38921 55047 28183 42139 431 10999 11429 58608 43508 43805 9386 46008 59480 52412 41770 8975 14929 20408 27108 14514 57037 57356 14484 5531 61332 46413 7592 8111 62942 52494 43608 17830 27250 61031 55141 13258 40151 43899 47885 49739 49997 11004 21284 12157 25835 60918 61779 61701 59489 26638 45283 47165 21832 43105 10702 37683 10817 14663 21395 5713 18466 38326 48267 7120 30899 56985 59626 2711 9184 24546 30657 49521 21359 55281 24596 7659 48410 51194 23128 39507 4466 51358 46880 20230 42656 41231 14820 29538 61002 29184 61773 3350 2108 38287 48491 10101 35560 36077 16877 24459 23894 43237 31138 26248 9808 5182 34305 62013 49008 11302 22952 23554 63340 29219 45479 32770 50345 42289 21240 31531 37250 34041 53646 41878 44024 35639 55695 13771 39429 35265 58437 29729 23194 53106 9624 36307 54115 35867 49649 47237 5205 55296 61133 60635 52892 44135 3555 26904 5378 29983 15479 58601 56497 14883 14152 15041 60735 13396 50082 6829 35149 43344 5571 61674 41666 1653 50463 20060 13440 54075 14338 31391 21391 36539 2043 27528 24195 37771 8969 58511 627 2670 49082 51476 22348 38052 45861 6252 51426 59571 42379 30067 16049 22959 26204 29231 28653 1717 34464 12672 11501 30271 3867 27743 996 4999 21615 49291 33300 2012 35274 23704 11056 15787 26929 60823 35606 18811 25453 9570 52618 27537 34372 18595 5250 44998 22662 29174 57127 61834 63954 27519 36606 30360 62171 15009 27412 34011 44606 47348 47884 60573 52961 38951 13843 53044 61149 50776 13502 1590 14931 4506 31422 7836 49961 39394 9657 34555 63348 48498 9170 28247 61696 60206 42284 18666 29200 12550 5142 28351 19944 41422 63217 50816 59681 33173 50179 12660 60206 7784 10409 6057 877 17379 8665 49978 56521 25999 18232 3880 13323 51848 5224 63825 5364 27523 48056 36572 55770 24720 16982 53396 49905 35615 661 3712 53079 21403 4976 2677 39968 21193 2732 26512 7504 29832 18337 4647 16762 14982 39485 33280 22377 9946 41643 7498 55418 26060 62988 23438 36137 59276 28813 59287 57877 45103 6602 36194 63486 3783 64396 3044 5361 15639 37972 47795 52536 37658 11447 1286 44983 34629 45736 45969 27729 24124 40190 36651 8698 1866 54884 1641 52854 43243 60735 58278 54883 23314 27333 33483 28204 58639 14935 36851 31119 10886 39215 18303 17167 40417 36568 55411 5520 44485 3816 53043 53874 41203 50651 29006 28165 19112 41827 27987 25465 35868 15769 7005 62529 54495 16202 39996 31385 15669 13399 35227 54810 63559 9473 44587 3690 48938 21398 6982 6102 29414 7057 13270 62862 50070 37617 3136 48046 21507 42881 48580 54677 21942 38552 41506 39054 28610 18959 7391 54336 26755 14326 10620 13260 56149 20830 38828 1676 31180 31467 29595 29250 46238 25617 39371 62395 21796 53757 64268 44996 43302 14070 21713 1664 3802 5769 50206 12131 42358 62930 8017 46654 15655 39528 43229 22089 33765 20911 13992 53746 22265 11343 33801 49333 16970 11467 40665 8266 24411 36211 50041 13518 56508 30078 31118 33333 17828 60159 31057 12820 54651 52351 43507 42186 15989 50205 53214 2 25953 10223 63517 47452 64181 39878 50472 53525 30714 50215 56421 7205 42730 61945 35127 3851 36620 21757 16781 31382 55221 23460 28958 49015 44631 53158 43420 58522 22665 26932 12431 51113 30601 49538 47023 27323 49657 28616 29978 40677 60859 34167 46997 27428 16654 374 13716 17205 20186 33101 62718 13185 51153 56676 57526 18827 56216 63350 63281 37515 20884 19692 63475 59671 16896 46220 63308 33678 47672 235 54568 30117 18959 7398 59359 13035 36229 26366 16817 16173 53025 39351 59265 19195 10498 44495 6473 57035 49079 992072142 1325875968 +1024 20666 2547 53679 37393 9232 16354 7165 17886 56441 55502 53500 19526 31725 37145 60044 31423 5152 55064 24911 44589 50270 4534 7267 13313 22745 30555 24762 28305 20869 17989 29981 6626 50679 27723 31582 43252 45889 48765 58026 35130 9817 48813 24027 9027 29547 38680 60694 4622 58654 857 19942 36020 2177 62008 19278 52342 16370 21340 45517 63420 24532 53181 22408 20171 61948 3524 60011 11384 29871 35780 62916 45520 32870 62297 43436 8511 40941 39438 42644 53274 26139 11515 35077 10990 36480 62131 46369 13980 8408 6740 45368 17052 45459 2146 50552 51884 57560 56971 29203 35784 55759 4789 62975 40298 11998 56639 53940 60503 37957 29588 54642 49145 62580 33159 63167 19772 59829 43127 27087 51471 98 61949 40904 62134 15519 36604 62676 34234 25383 17466 38713 16454 46634 30185 57040 59938 17039 51052 51403 2542 54316 46993 42876 20128 26944 6810 13619 58185 48606 50382 22691 11602 717 33628 25696 20234 39963 63783 61236 29021 8974 5497 51929 53380 10086 56301 15072 62649 46713 32921 31229 30383 44562 35283 52367 43006 34249 43825 47914 52835 17380 17518 37660 33716 57084 58880 54097 24409 53842 17276 18457 57761 42936 55704 29155 2620 29959 59192 11377 38494 55532 20785 49021 3032 14011 49292 1064 36892 29930 62850 3154 45536 18919 6499 11343 9209 25939 3801 4901 62731 56287 51677 11785 41606 59227 38289 46287 24748 35314 26314 22322 41484 34265 8796 15098 58225 8997 53013 41704 22652 64208 25523 59986 46254 58012 40811 4302 25075 38610 26046 381 36689 5542 41740 63324 41657 8346 61537 41589 31710 7056 6208 49459 56009 1446 15259 58126 20469 17908 4658 43254 59478 1935 20648 44135 50317 27205 16169 17283 52349 42086 8704 15895 5023 25895 2746 31525 39909 45870 42201 38528 7043 57892 33517 18666 12968 5027 28729 8235 59788 27179 50434 63790 38333 30622 43440 47685 43937 14114 62744 13984 40618 55316 54804 40706 50256 28089 40933 38266 53884 39664 37659 18186 51919 49446 38552 32892 43930 31700 50690 16966 60234 45072 30160 33481 30571 36342 30905 42761 21480 25378 50724 53019 60476 11148 41893 52135 56131 24214 6591 43533 31365 35653 49824 58104 27498 14086 23464 1392 32927 15607 40273 8431 57440 43477 23527 18473 22761 35907 41642 29467 9826 56642 29154 25711 26446 37657 20536 30083 31525 46435 1497 8246 21629 53107 5735 63248 58558 21748 45274 23637 41945 36043 1200 39151 22345 57027 58772 44665 50315 723 64251 48177 1368 50024 14953 16956 44030 41774 30481 55767 1306 6893 21239 36724 30045 39637 62799 56850 50322 18600 39745 13592 60837 48434 56370 15396 54812 29350 43103 19164 38541 29778 14423 52594 15352 40264 28127 60668 5085 21143 4691 50028 63694 36200 31416 16818 37909 17252 22856 33055 21692 2629 58336 18405 16440 38832 327 24903 50531 50846 44795 45306 7633 49350 53005 56361 52676 14898 19200 30763 36432 12091 64062 56535 44755 37233 21973 45573 37062 51740 57805 29487 44287 30838 40882 40090 41597 729 8186 53580 41733 552 29459 33220 4460 49286 26189 42286 48641 46342 33362 34546 46576 34894 61568 1166 53201 52657 21815 28192 15748 20194 15188 21262 46841 17446 51271 3053 26006 28371 40451 58975 40987 40806 11421 45642 2865 60634 25761 55291 52005 16464 58042 17836 52568 26695 54278 42911 59193 29492 8581 18082 38764 28886 18182 61772 61748 38310 35871 55132 60518 1339 6570 5487 57192 17002 36005 27169 47381 51116 33425 14645 32914 13887 3293 53212 57691 13806 29675 20098 55635 35778 31480 36135 7972 53588 2955 50276 46355 30293 10114 60930 63591 52012 8910 55765 6579 40781 15734 58935 19728 35789 760 26633 45195 60593 59045 34092 7490 49884 2081 32909 15679 62525 7330 17821 63964 28365 48380 13532 50406 25875 18404 15617 59864 61554 25905 35029 55617 54940 30389 35705 14936 7368 35968 34167 29368 28563 51755 26825 28835 7597 33863 11908 30428 43015 49793 5693 38329 771 37368 35913 13672 11240 17494 25438 8803 39998 57373 16728 53621 296 18906 53781 57605 34662 41729 59411 10642 11134 10648 45188 19702 31709 37771 28630 3692 46817 6773 5498 40479 30223 5778 16053 39773 63984 56872 44263 31714 23247 48727 38700 56013 7621 5807 36186 28173 23154 55242 17195 6075 31061 1889 8340 6150 7545 56334 19869 59002 28517 33973 50181 63243 44909 1039 10363 15608 44291 42398 42472 22919 37906 27284 43846 2308 57460 63983 18696 31010 25460 63166 47179 30404 41976 79 42086 50073 63922 55150 16197 63876 37890 39033 29079 54683 30922 62527 60216 9220 17990 8763 31036 36170 23151 15200 8980 22032 50104 6289 26365 12745 18554 49754 61835 23402 47169 62114 51285 22579 38301 58639 36396 25276 26439 52531 28352 19162 6613 18189 47451 4599 35857 33159 25418 45576 20581 59359 18975 20402 37156 49209 19242 56918 28543 26775 45072 36394 22282 10260 44142 35099 8558 31367 48410 19367 10392 19723 3230 29840 20718 17029 54821 6414 15173 43592 22892 8454 34748 5764 53165 38815 35503 54079 59075 43264 23575 57631 5370 4045 6295 30298 54040 58739 38379 45725 63319 21645 1238 3267 47492 54693 42431 4391 13482 45119 61104 28468 22872 34327 52591 9908 58831 38276 1646 58736 6020 27518 44591 3770 17927 36375 61434 36448 39356 34003 12809 56628 53926 12591 21275 13096 5324 53931 57986 51179 50125 5329 15502 3352 37063 62470 5355 60319 1149 16657 52359 44972 64117 47955 28868 53685 42585 41859 49857 10172 19342 22672 289 12319 30125 61801 12650 18729 44595 25870 29103 51253 37643 50558 57171 49222 16063 42691 28801 38336 8422 48619 4862 612 62310 1730 3432 29391 19764 46991 23829 24826 46572 7326 4348 25467 62530 64334 7981 15502 35891 18056 39203 56219 7438 55976 3563 60819 4611 27840 15975 27854 18516 10482 59230 53320 49 22994 51986 35873 33064 4835 20538 54508 9354 38141 48394 29399 3084 3132 9186 48042 55664 50963 54942 49957 4469 49396 35852 8937 26261 50676 41054 19348 34367 7741 36875 40816 5709 56472 26212 50164 8578 63417 54425 2974 20579 1742 50047 62857 14116 20661 35695 43782 33964 37383 43740 44115 46542 48282 15130 62123 11976 58191 46047 25892 23204 16263 59621 24009 3378 34596 42058 47892 28657 60144 50102 28390 13320 11951 51067 6827 62705 20596 58521 21747 32872 13199 25583 907 57298 43302 46353 4737 18157 61256 55797 52538 49192 43238 26219 18535 63598 16025 51752 61963 5506 30277 20210 33506 7057 25929 59210 27200 26829 22266 42985 9176 23895 62875 33595 53668 11721 2344 6565 46685 26282 12152 6236 51888 41337 641 14033 38860 57722 49089 7403 50838 50676 30586 30363 60452 5531 2495 16925 59423 20 42893 53865 63372 19462 44742 50956 49152 15356 44964 14856 29455 24266 3317 59147 57106 26499 29183 54157 42030 47163 26566 22338 45080 50644 56190 55054 40081 12946 48269 37979 15812 64198 15125 15781 52784 36829 29148 11453 4080 27322 24746 39238 61051 7726 9933 25900 33191 36155 28383 42641 61875 37849 35975 13690 59695 35569 60015 5737 57026 18798 14496 15203 4230 34116 5919 12419 21273 35971 26579 20842 45280 56903 17269 27417 58366 39850 31123 40610 24031 26417 50118 44747 3499 13068 44012 18195 11310 4954 22281 4999 1537 22929 63503 3130 10730 47530 56347 14908 50949 21462 24741 3944 54662 28494 30786 13274 5864 21738 2515 20019 2671 45297 2511 50369 42368 43960 56496 41054 48853 63105 5559 8327 46390 61621 45598 40351 672 21662 51383 43997 48239 37887 50966 5334 12406 64139 21330 5561 60251 53351 27071 62284 22925 11236 40321 60156 54494 5533 7186 63724 30730 54154 1887 53585 19933 6206 63553 19434 29399 16437 40665 36798 7690 44555 33152 33786 6489 37815 4570 34695 3615 33424 41986 12080 2797 6207 36649 2810 1645 1051 30001 23974 15036 56650 34690 61430 3780 31081 29915 62113 19932 55742 2215 47225 16542 54547 62431 3622 45891 34318 57023 30957 9932 21934 6665 59895 2356 46967 53684 2728 2464 24885 17755 63349 41714 56278 3948 23665 61967 56078 41661 52150 60489 30495 44444 26113 5139 52581 1484 10940 27793 26923 2299 19452 48663 53987 46157 61107 55917 3653 55295 59504 16402 12057 46442 9360 31283 13224 37483 4240 15442 12612 52940 1344 49370 31281 56267 37842 53259 9601 27771 30562 9500 30380 18393 56286 62836 37049 14336 20079 9098 63484 24565 15095 56150 13203 19332 38883 58587 30550 5308 34435 56930 63986 49173 29200 25474 24244 25883 22662 11139 7870 49541 56993 44281 28570 3000 62579 12568 28892 3497 63440 44218 51933 6862 51537 49160 8052 10390 32981 33386 21913 3825 31561 46021 12067 7526 2635 7616 34629 14346 45856 48355 63236 25203 47568 3990 10962 59063 52911 43510 590 45642 7049 38883 13192 22086 38111 57642 43972 49319 51388 33305 14626 4866 11150 44153 31545 17159 20536 9563 30593 50871 23896 24766 46481 53946 64230 3953 31723 2178 48794 20985 48365 52154 51804 57201 43492 28224 37449 48799 10008 19510 15560 15820 11730 52814 41682 49397 40130 11609 33562 35394 45039 28800 21286 36894 37703 18964 34234 19589 46526 25551 33808 62197 12188 19803 35060 60334 11374 30813 10314 12603 16696 15166 14781 31142 7978 11276 29789 47976 41495 3338 43878 23026 61679 53836 63502 3560 39498 3022 45465 42136 14203 36081 15460 28999 12628 12003 8805 45929 7458 16775 22108 9741 41939 58726 49452 33957 45227 31096 49351 61556 50469 18547 35890 16080 704 37202 16136 51504 44111 44092 60713 55737 34393 24758 2953 42832 6221 55514 37574 61549 7225 54138 39987 34580 4175 30544 62311 49161 48135 731 43064 34007 10778 62277 14367 782 30804 10654 62823 40379 11401 56143 60727 22525 21095 25403 63681 52181 24391 4388 46491 29305 46718 5190 49775 26154 23057 49762 14373 35536 28670 12451 37546 12355 33778 59078 13466 47275 52941 56631 5508 1093 57027 52732 19044 21379 30809 21370 4549 37768 22786 4328 46299 54486 64232 4857 14716 17248 51901 33965 54054 62508 8669 6874 50111 28685 40188 52625 42169 10120 6212 55901 35713 29243 34977 18228 49241 634 37093 45581 19921 60708 13684 15406 21350 24241 42962 50021 18005 9357 41888 50090 21706 40832 33735 26702 21237 59165 49167 54213 6376 19757 25531 719 27234 36869 3680 36558 14059 43403 45204 34009 25209 52089 17604 22740 62795 45239 43490 10794 24810 48606 14848 62572 2489 63007 21584 21822 18033 43612 42334 21425 19144 57465 42755 43860 23197 61054 32890 31151 9883 25016 8158 60768 49624 53765 40468 30131 20379 64132 53235 44076 19541 41776 46125 30873 49112 14950 6585 40880 15158 15492 55113 44013 18721 33995 58923 19878 4962 50717 18953 58085 5376 656 22085 10394 52499 9764 50926 12751 48750 40622 21867 23321 4243 8101 55274 7429 41221 42419 38974 15446 27239 64337 40431 21170 33398 26914 56406 12528 13822 14852 48 40506 13385 26565 39047 56383 20034 17049 60863 10612 8080 5568 37961 60123 28736 49129 20526 33143 37249 14250 10816 27121 34833 59943 16566 28114 4622 54283 38717 15488 61462 1984 39697 26542 22528 60689 6089 1964 36580 57644 6250 47259 36524 22271 60961 53200 25569 51834 53395 64231 16317 50453 4488 5358 62826 54488 47424 56787 6849 10562 2497 15529 50929 33793 34250 52305 173 1074 48287 14284 46294 56661 2128 28539 44760 58008 35448 23345 4163 45298 1910 44913 10298 45752 36265 31736 47712 38959 49507 51211 4392 64388 24999 64481 59076 51304 48161 62678 42574 36442 49982 35369 46795 50735 1159 43816 24370 30405 10259 64224 36876 56535 52473 17235 17483 56049 24429 46886 53875 13055 64369 16156 46317 41734 33505 49352 12558 27564 55794 33224 55944 2949 46765 61733 50199 12908 39112 47056 29425 33996 2363 54395 8389 46921 4290 23427 23912 44584 22945 6884 61229 48214 63448 8664 5036 44981 27461 48071 23363 59464 18142 14106 24881 2404 4721 7690 10606 53259 12578 2855 5195 28292 62808 45995 19194 39465 29369 9530 35733 2299 57981 20168 63111 63862 24363 219 18804 2913 17900 35192 19058 22534 43464 40512 35780 3672 52073 55869 39803 6513 2675 24664 55165 40595 51244 18656 59716 12985 53570 49419 31451 52485 53080 18371 34863 37229 35332 47820 37930 50792 7635 43991 10045 27305 57778 51269 7488 15800 56236 60006 19624 62391 6251 36921 38829 39827 11276 11905 24261 50415 38069 34396 10970 4829 37282 4618 56051 5977 41388 19654 40249 30015 33676 48360 35476 37932 37081 31172 43331 12031 34118 58324 4407 50013 11960 8879 18258 46393 58012 54694 7607 42515 25726 744 28552 18581 58136 13626 45387 21367 39626 6509 5764 47250 22317 35272 49298 16492 14280 24737 3322575989 3472032496 +1024 51772 4 48112 12944 25473 60702 351 34258 46435 10392 50144 47714 49764 6012 38091 55573 22022 2367 26450 45027 4176 31102 59020 27019 4034 24027 3126 29164 47331 61820 48699 64389 23263 48472 18662 28990 5942 47828 6893 42366 62131 3725 37601 13321 57850 16719 39307 62033 11772 31304 20369 10229 41584 21385 1831 9299 45425 6313 20391 29586 19843 59899 59754 8978 46579 28203 60756 50672 4024 15721 16498 59851 23068 51594 38937 21257 8079 42919 52090 12046 56120 49244 40981 54426 27923 36345 5307 62984 28622 51570 60899 59186 5739 54620 16946 11119 18477 48049 16005 43150 6704 60268 970 50948 53769 58946 58459 40103 45702 33443 21624 36896 59430 23599 59008 34991 14972 4936 3963 9357 25062 22050 46839 21644 32893 23742 7393 2290 24613 10475 58593 42711 42821 60361 39887 61560 13296 29554 1542 7780 24339 13272 1875 19863 48856 58454 17292 4493 11080 42749 41044 9013 52089 19586 12691 8679 8754 51586 43140 51057 53598 31498 10561 61514 27960 47055 48775 8420 7207 14532 43968 19002 53092 34121 36896 20379 20292 8067 11648 9698 52180 11828 41990 36491 39579 27327 45549 60282 59194 56384 4962 12291 11707 2091 52267 18837 23293 33476 8305 27406 20075 62177 44800 53768 50718 21086 54931 9505 57179 6035 45228 58378 7972 56872 14198 16587 38200 24510 6745 51725 30543 40532 58887 64058 41932 20845 22282 62714 34629 48260 51368 30085 7831 16022 33833 21466 8531 15697 64444 52052 55039 2389 42071 45981 20733 43616 51968 63895 12024 13188 28686 59331 28387 55394 29916 17247 47461 11029 14797 28098 45485 56923 21199 42785 13902 38638 37688 33396 10758 2976 55885 5854 2859 52747 40725 12218 22588 11072 9253 32843 24567 10351 9732 36061 50796 10866 15296 57850 4817 13189 38380 47467 10691 39584 11865 31400 51908 29039 17365 1925 44338 50141 20891 39343 33216 55234 18396 56525 47444 54617 41935 15740 27018 7228 53557 28140 58313 21463 9760 58492 55983 10201 13914 17438 5424 3997 13127 47152 30997 49663 46565 17982 48658 12269 3403 63817 38999 45087 50972 41487 17464 49694 30697 60311 46261 56631 44385 58204 21455 30551 53220 35320 41056 55875 39642 10581 17127 1004 50255 6955 34112 42675 19686 42375 21910 10690 26440 21122 18889 39104 36192 5314 39776 30554 55875 4100 34927 59846 63042 5378 7766 82 29548 21649 48072 10184 63524 25844 15110 19094 29500 43407 38946 8419 27542 26696 4138 41188 15139 31562 57777 18623 51244 16425 10632 9402 56653 47901 53663 56478 15377 51894 39040 39883 7840 64179 58699 29336 7417 36238 22774 49551 37712 8846 5318 33040 9361 54887 8139 46156 9285 568 3470 64058 8355 25050 16209 54418 16970 19784 64055 57136 23594 15965 21338 41051 4022 20214 41090 27467 6027 56929 52010 43322 43090 59821 36575 30706 35788 5833 24867 3255 43796 28404 14977 29370 43584 17050 41303 16238 17670 25807 52396 45904 11495 20135 51918 41207 56785 43635 36481 49295 43903 13602 34576 9146 18934 23830 6782 63149 3427 11796 49795 21384 48391 16059 37762 50544 63036 57813 49480 61655 25794 51684 10367 22842 55738 43788 4453 2050 24639 62180 46714 19905 50729 51028 27979 8642 22064 6890 52547 51346 58667 18395 45554 62782 49399 46208 36906 13571 14505 31295 10141 50604 45215 22346 48154 25157 12650 21176 52886 39715 24671 52936 26557 47914 8211 45301 51318 23081 48661 24077 29559 5293 60234 58603 17440 2103 8583 26017 38032 40820 28350 38979 26374 16291 21058 53216 14057 33219 15320 40683 46213 59146 2301 18804 8683 8855 50710 57057 19999 50234 27290 61750 48772 56470 22833 18918 25833 22681 36053 37500 9226 34569 27349 48779 26038 35363 6462 4617 14750 1097 232 567 26791 20812 9727 31087 47046 40507 55759 61739 2102 4465 18186 39745 57134 17646 58155 9043 20092 48156 36514 21308 49806 15429 15392 3167 49703 17335 1848 11142 59529 9244 42394 37835 57463 9418 20125 33236 33491 42983 36941 33098 17293 27676 35700 60389 23811 25210 33914 15780 17815 9219 2074 59794 50365 45988 43110 13341 6772 45761 17776 36885 43732 37500 19063 32840 49572 12200 37764 16569 15492 2994 23402 26469 34900 59825 9386 23989 43471 40279 37129 50841 19749 50169 4729 16179 23516 31128 47258 23822 10741 50513 15942 55974 904 39390 11230 51837 39769 17805 23272 31084 26960 18618 40893 56497 16888 19991 31421 48526 4778 53495 6118 44654 23004 28836 54974 15671 40620 17985 56306 9648 40246 46325 45057 50738 42595 21090 54574 53659 59649 17627 62125 63229 40002 42008 56961 7293 43060 58132 33500 60913 5408 32900 3062 40737 14113 56107 52866 57995 49125 30197 14839 11660 57099 2266 57163 10311 49099 23379 4411 48364 28139 8589 6588 51217 48867 21820 30035 1655 17417 50406 34968 13240 37889 11576 2795 19300 8679 59359 58825 59337 28137 1896 54568 15681 43031 34746 19003 2024 25981 5106 10385 62866 63347 22411 47849 5894 54309 4329 55010 49903 17185 48852 30406 18091 54774 48545 23408 35048 26339 38198 15059 23024 12309 57783 43730 40825 42911 18879 39379 3327 54814 38053 44150 35475 48039 2967 44329 38782 47513 45492 8198 23353 27665 40635 13098 15723 35579 10362 62556 59151 60519 16297 26165 17240 48442 12037 41053 15368 124 1316 53966 44364 8357 15468 61609 60824 4211 46728 12098 40724 22853 64238 48049 30999 59065 43060 16650 27456 57923 3909 8470 34729 44781 12250 39945 8790 4917 63683 9924 35594 27768 63730 19655 17875 12285 39259 40862 12027 6947 17774 5548 58755 63953 6052 30862 55204 46709 62990 15555 5656 25399 47828 12094 47256 54914 19538 60106 15821 42878 2134 46901 3349 5236 47866 11996 43218 7687 4669 59754 59150 62513 8811 37237 64485 1489 1079 22312 62871 29192 1345 46495 3006 64201 47491 26533 61763 13013 17193 19240 37362 62081 13376 16721 51554 63125 57044 57005 52339 14313 18884 19748 24780 21649 30556 28386 28033 34701 38794 1684 53717 4429 50674 68 6543 58863 23871 42492 51547 57132 25806 31459 9964 20867 27419 51100 27099 15374 1877 11899 43327 52400 13850 51199 60441 19918 26554 17486 60272 56454 25792 4082 49791 4027 42783 29113 62286 18416 11246 6335 3420 59555 50839 5499 38667 16456 12336 6727 39880 55010 44719 31477 58422 21385 33661 9813 36965 23650 7223 3548 20526 61466 8210 44710 43107 43879 63055 33509 30917 59858 2300 25332 60063 63471 19326 4089 28537 5852 8118 21842 40622 51671 51723 41865 16622 8820 58355 30421 59115 24185 53648 28965 56707 50597 12685 42881 1064 63391 62972 21174 29007 32949 51746 10882 61272 46593 33261 34018 12765 43667 30586 4529 36671 44358 3581 42410 448 928 34753 12582 2746 4674 62230 50458 57417 41529 23230 10095 28553 56410 27663 34535 42755 37103 56399 18188 4845 2906 7667 54456 40243 58598 40402 48384 31630 20241 51793 19281 45166 2302 49161 12603 30000 10500 35992 42759 16412 41378 27313 37761 31515 31477 31490 56242 12533 62470 16817 11393 45878 22270 20195 28350 53700 49426 54719 27365 9444 1901 53366 9959 21055 28020 10193 61456 38584 16404 45944 20537 56688 4928 11755 44916 27947 58478 37475 34509 20510 34772 29305 51856 45657 432 25186 29371 50413 13678 48733 46498 22290 10195 41482 39536 48277 38260 50024 11565 49756 6323 30710 34298 14681 14838 49194 56540 38461 15522 45624 28462 3851 30520 25044 27643 28906 34014 42231 16540 23761 5370 15023 33253 45223 51301 48015 46334 12104 2563 44468 63411 21911 64013 53392 46178 48036 31019 45990 3903 4437 44016 28676 61322 1647 62429 42307 30422 1779 12233 47953 48613 56383 37502 62251 40769 1444 28721 59765 43641 26651 61055 1944 18910 55171 34614 59495 44057 3438 18396 255 35692 929 62015 34596 47136 63906 6413 40842 17457 5079 15063 35704 49004 51073 49061 19386 40159 17344 9745 12783 35666 13100 15431 29628 53185 30850 43808 9905 56091 34906 38401 22421 25117 27141 64435 10841 38132 5923 5937 21831 30283 11221 21073 9661 5618 60886 2573 5397 37106 38172 26831 55378 62375 9137 21594 22407 6616 14154 3749 7557 42862 1588 16945 38796 31335 33514 5865 1582 37699 45415 10281 4205 55817 39972 19961 3661 1722 25309 43371 61533 43257 30412 42735 54526 10412 17281 50248 60299 33795 12190 28077 59 61520 46262 31116 19753 53964 19562 44410 50056 64094 15408 17064 64197 11163 41397 22762 39691 33474 27736 34826 6984 12484 13543 47363 2933 8860 1327 6234 59737 59881 43296 52678 7646 11593 28638 35565 45103 7695 54415 26527 30341 53319 44353 31357 46280 33651 14369 18419 17079 26974 45741 12816 58528 20422 4518 21033 43347 58906 18466 1161 7290 26405 41834 13082 54580 16071 1539 54303 58372 16604 41596 61074 3394 32777 10826 23432 27461 21875 26967 29717 30073 40048 15590 40058 26173 17243 41179 4911 51566 23146 27896 21602 17083 45595 63487 18355 4931 43914 3983 856 43669 39349 56827 38264 3548 22649 10492 27510 62475 47779 26575 4942 11603 15267 2416 24671 985 5081 60167 54750 23235 474 53202 46286 17338 31086 20438 33410 40420 61577 53844 5569 5691 49631 50766 25704 4933 49755 55311 19570 4740 41013 31288 35280 44297 47654 53734 473 2828 10722 41423 42962 43165 13025 10646 21317 23468 31144 19861 1392 19956 47847 1406 24179 7002 4236 35998 37228 1928 26987 21623 25 45029 19602 10944 3811 26104 53762 48879 4831 30390 62733 57063 5748 9231 7751 63787 11241 62936 8173 16006 3164 62260 46658 43304 47733 35134 54798 37918 38245 63230 21814 27990 60724 39733 55267 15980 19711 60568 27968 7212 60199 15814 37608 662 50716 47284 14469 15339 40322 47636 24482 31164 31680 30742 24976 24399 52546 30633 24198 28975 34197 63561 48397 51919 36855 53482 35639 43628 33069 23430 15562 5504 35158 63942 1373 59969 24620 60161 5623 25732 8482 27328 58967 10753 17222 19986 30774 21377 16458 59855 4247 29925 36768 27614 37743 59565 45907 29685 14244 7170 16634 49969 60321 30242 29852 27463 42530 21342 55839 32796 23956 8602 59230 23329 24034 28072 61705 47897 28499 19674 11235 58174 46471 6677 4515 23344 36620 35921 47295 7680 42431 49221 12069 47568 6198 12275 34501 54892 35873 10100 54682 53410 30922 52048 44240 16764 36931 14630 30200 30311 1332 24736 42161 6053 5156 55345 29731 18661 2534 54322 42640 4945 44002 52137 10822 61066 34197 968 22646 56252 58052 13591 6921 21138 3864 31143 55158 42309 41385 63361 53638 64209 48865 54007 19349 41901 53100 19064 51205 117 30130 25947 44616 50703 15144 56104 53386 55222 46475 54742 13497 48529 5056 22137 36918 13380 63118 48319 12443 20576 55015 54229 7885 17292 39426 27900 58782 34939 20987 51921 12705 31201 16574 57770 11096 22265 42083 27932 55645 18000 21301 44275 36574 13279 2771 13185 55019 30462 61345 152 29672 4096 55499 12730 11990 53439 19094 22573 48617 30970 55093 24572 30613 26102 16699 36843 27678 63892 31426 44944 25390 43647 34402 62300 10285 55359 59574 23532 52388 4475 13256 6188 57897 43300 19281 21951 64174 59694 9390 62799 50958 35639 270 15131 12563 21509 48943 41632 60511 60995 3320 20051 59192 8044 34008 20656 22053 3231 63854 57822 33069 13219 25297 41872 47403 58601 3662 44968 22214 30806 48172 38773 52633 18247 42344 23449 28238 41613 44932 49322 56329 53845 31522 58365 1730 24829 55922 29364 11834 62287 2526 18221 18605 22804 35595 60644 59262 63790 29383 62768 59692 45948 13264 23819 62497 9282 48085 48944 13309 22428 24420 49552 25831 24491 26355 27560 62661 40986 10817 46996 33952 13858 54306 41846 25549 7297 42524 50907 5598 14552 52886 8686 13310 2492 8994 6353 13883 13116 16921 17035 28918 56915 19422 10179 15793 49068 59334 55268 42990 26818 10264 20 54097 50709 21627 51499 63422 31600 32870 40193 39990 37401 27421 14185 59736 3271 7872 49283 52301 24022 9651 60277 59331 30076 7842 53198 13333 14254 9534 15553 6305 35116 44463 35085 31493 28341 29735 13248 1362 23219 51494 24473 14327 54931 9105 7357 77 50850 10504 4035 57350 15471 41932 45204 60140 3195 47692 58673 62215 20490 22718 14165 41714 8388 2714 49057 7423 20161 54891 46884 43381 33623 51612 62071 49949 63099 20782 58057 43571 26176 29970 60565 2604 50943 53581 39693 56004 63954 29518 39310 19920 55700 35553 21204 56170 60523 27462 8804 48170 38476 45848 47938 53798 26794 61727 3933 40445 17689 24666 58008 51597 24067 62413 43115 45248 24356 44943 23337 1294 10765 1727 31571 57751 448 37534 35775 57809 56253 11056 19558 49209 28333 59198 58074 50342 33559 8080 50106 11565 1055 42128 7715 2790 20432 46011 62249 3145898926 3471175729 +1024 9501 23074 4109 10296 4177 18835 62534 43421 8308 10286 21042 44198 62096 29852 42468 54385 61043 21165 3946 53693 37939 57426 43129 33831 42453 43489 17805 27200 60268 42312 42764 51103 51286 59863 24183 6800 35195 36431 18722 29133 21202 52498 26799 31148 14175 46369 34370 24284 60267 23971 4148 55453 17878 50623 62751 4856 59827 46026 52768 23120 63328 14656 28516 53232 23065 53787 13624 2432 18405 36983 59233 5219 19173 16509 17780 54518 56788 41178 4965 26194 42724 11623 3449 52022 26446 38227 48698 35547 14775 13656 17226 1721 434 64371 61930 43692 52210 33081 17109 15007 61741 34464 37129 17343 22096 49763 6196 18628 7916 30041 33307 20629 33929 2305 49834 19762 852 39783 22172 3309 18817 8245 8054 33705 57323 55938 13820 41021 49911 49224 14294 7156 44281 38627 55763 20314 31175 25413 39157 9496 15378 23921 56884 61088 35170 15688 4891 31477 6924 43950 42559 16635 49776 50498 44047 51617 49817 22135 10111 63711 42742 27720 475 29683 41440 28868 18386 58083 16605 50773 30462 23815 64347 58109 49866 35549 42239 3682 13348 20940 12711 6902 19380 23178 17619 29830 49357 5329 30542 42449 43674 20922 41880 44974 54995 63373 47312 46158 63117 7432 64150 25174 43099 27050 20215 34120 7235 28083 33415 48859 33042 4928 685 6474 37062 2983 40236 61745 23383 12513 49971 60915 56331 825 46298 45164 8425 27332 57936 19733 40251 43096 33176 25747 22187 8997 64479 12339 44493 49855 49536 51244 57265 53801 35225 39158 985 4473 7687 36490 59985 27284 5649 48331 2155 35616 53279 20592 37679 17965 52388 12290 48898 50308 47570 41652 5671 48238 237 43245 38153 16666 37388 40057 5547 47165 43671 39507 53322 33301 40885 51426 64264 7422 57930 45992 62285 564 25224 54607 1094 15532 7598 48420 42227 59354 45206 4834 47629 11917 48182 13854 49039 36815 56688 22847 63301 2210 27531 10560 34696 1018 45964 53051 24879 8634 38499 47350 26859 36442 10950 43465 63483 31107 49307 51948 25030 44537 41886 59014 50615 59945 50793 58875 49142 37019 45051 31302 30921 5064 16763 57226 18214 803 7393 36142 18618 46031 49433 8862 6417 61171 16644 5525 33941 33144 43297 37861 28354 11221 43716 48066 59881 38862 60156 10610 59023 10658 58641 27359 53237 60075 2130 12613 22509 49291 59943 55858 14420 58416 43353 61669 36946 11264 30574 29246 16173 39601 28241 43215 45451 40526 21965 2461 41879 16335 57149 4511 14733 12472 19746 41798 52809 42373 39336 14804 41637 4146 45365 3335 2761 34853 62470 21012 52440 24264 1207 44927 15344 16575 62623 57163 63793 8252 34681 6917 22668 2092 42345 62660 19462 40519 26447 39022 62988 62118 45419 58819 54263 40591 63454 9106 25268 30382 26478 12726 13575 58868 56817 39234 27127 21341 54792 59903 22104 61005 24235 38435 8648 43135 9777 46838 16947 44192 11228 16371 62493 45497 50731 45000 62140 59771 38434 22921 37441 21153 26001 13172 40708 26128 29099 48270 51309 57684 10655 38224 5772 64060 15824 62740 29014 39437 4338 5703 28492 17545 43730 1608 16 42210 62357 6713 30390 9841 14882 58426 60279 46127 13613 16407 34172 63457 3917 62101 21354 5420 42976 51945 42943 9916 20956 22697 44495 31099 41714 54309 25042 36908 48343 19416 22262 49390 1428 59214 38999 59272 8174 11217 61958 53878 17505 20444 8880 2306 12505 54696 19080 33462 42987 19392 59843 7870 34979 3950 21481 40175 49265 2711 46004 7416 48189 48366 24181 36571 31736 4475 9405 55396 22893 40785 57869 1813 36580 58252 1550 6613 29904 11250 24787 52232 56778 47379 12129 39901 57925 40668 17714 15118 58748 23067 24816 58611 6568 56961 64160 3360 6505 2100 42836 24790 55441 50360 51014 57007 37176 27937 41265 57541 10471 8147 35439 44156 49812 62920 58914 15506 41536 36375 54125 42879 28647 4685 41224 39467 45463 60183 8522 16075 11014 32875 11899 38498 24681 26993 55688 41653 45797 55784 42928 39303 43231 19102 29445 981 6535 63213 40235 8026 4912 30547 30966 39425 39022 18044 21518 33986 41336 2971 37947 34112 18807 51929 10260 30626 40057 9574 5287 60059 6217 9770 6301 3825 33975 48630 51865 6669 23201 27651 27935 55536 52167 50112 23058 26370 37980 6967 55588 31337 41583 45499 60518 50906 61603 61188 33863 6354 8236 58502 63346 4564 57803 53273 45500 22482 22966 3915 57734 55191 29498 15491 42798 6533 23922 52304 44258 64159 7256 1458 11830 34217 44283 41200 29927 1645 34999 20520 44450 49293 8523 40590 27315 44859 33173 4886 35687 27527 43890 41410 3781 25546 11412 2019 28871 47070 6183 57023 57282 21836 63350 20435 57361 29044 51661 33293 10587 29739 40592 2909 48299 14824 13167 53438 53392 63521 49726 754 57916 41237 51814 63779 41892 60142 12322 51334 31159 60542 41811 64071 16865 59553 47193 3013 17165 28375 30917 58351 42900 34892 64192 64138 18353 44843 36828 59159 29957 28317 53550 7295 45372 30777 35146 26712 59831 160 11699 48184 15785 51103 12284 24517 9069 16701 30670 21712 14278 13295 21401 61777 17009 23087 43719 29381 29613 49030 14724 45179 19937 30028 16333 607 55506 51669 42368 37970 58559 39888 8594 15851 15716 56162 22821 34290 2844 36198 28298 13973 28367 15870 40735 43592 64422 22511 43181 31250 1120 19591 52616 38313 2443 984 7906 51962 12906 58698 8602 26235 27745 21896 6445 62818 43640 2461 40366 9288 57806 6720 1035 44731 10135 61956 24008 14688 53715 60933 40448 29656 56288 25885 4073 14623 12513 60995 7354 41653 51058 32831 63899 31235 938 24960 4693 26426 8536 50980 23049 25008 49376 39160 2543 6038 29168 24963 23437 37637 60698 2496 48217 50634 27616 10262 4926 29428 55791 28843 28723 35962 25099 42184 819 4215 53148 61111 64140 30701 34016 4379 23919 51142 16317 50722 22790 40960 33631 53091 59304 8562 43162 33420 5860 37756 19122 21010 15988 24292 16605 46513 39896 50159 61999 12205 54859 53996 25654 21918 16316 64019 48097 14085 24993 38456 4699 56035 27235 5510 47066 10346 49336 19419 55474 41966 40245 48941 17580 59368 20806 21997 62094 18211 58288 35776 51367 33583 36635 20656 23858 30729 19910 55242 55784 46346 5506 26461 6954 44796 56937 29619 4976 56348 28306 22781 59736 30557 34867 22068 415 5897 28539 61718 38419 56220 5880 33427 3377 6868 29535 44457 48862 61732 20178 2469 59255 20920 55314 25165 58505 22298 25132 20821 53016 35474 23482 48574 13430 48468 15170 25206 8214 13819 47277 60399 29477 17363 57660 59221 29917 33369 59460 35593 1631 60166 63551 61633 15426 49295 37701 20830 37983 1055 26599 12318 24094 24436 25971 42351 21453 20589 61250 60864 21930 1949 34414 34408 62590 8552 33988 10676 5701 45184 18956 1344 51764 16289 51296 28312 54297 16715 28183 29835 54666 42109 8876 5370 30500 35021 19595 57206 23364 31505 46698 59053 51559 31133 10296 15173 35465 59705 20540 1327 40915 2708 30667 3331 38142 39480 34894 21075 52219 42387 51129 4111 29746 5693 13280 37464 15014 32925 41806 22916 9803 22936 30259 49796 40391 40218 30273 45539 45235 5103 23681 42136 63385 13233 2089 5832 29495 18638 45886 24760 17560 19646 8640 60449 37763 16425 12313 60363 1581 33209 43395 53909 4173 34164 18433 1288 21391 24604 46159 44249 11445 50254 57076 62912 58010 46312 6577 28507 40470 47863 59043 37534 53582 5942 56323 20697 43047 29496 13967 11917 59205 62670 4602 38313 33672 47430 61657 2236 56614 54638 38962 6100 8783 4425 23729 6462 25598 3155 49652 19488 4393 32865 33046 45453 30954 44262 16202 62788 48426 48111 53960 57312 64151 43296 39479 2168 55867 44328 58179 1756 34588 26462 22870 5834 19200 34173 3617 60213 31278 58627 1953 33543 38915 20595 40825 19882 36010 57365 21087 13157 6240 4366 40430 45819 11838 22918 33909 44233 37992 11675 29911 55824 46470 29986 36508 25660 29061 3697 63416 22961 22957 52554 27825 11023 62493 42183 40950 34337 30787 26004 16173 60040 15624 40749 18836 50841 27480 3548 7912 44665 30082 39989 19645 60552 54591 60281 36349 63747 31400 30992 46302 52508 12015 39225 41574 56747 10484 55142 33704 25109 60718 37855 63371 11796 26924 29248 37605 37341 48040 15759 46134 43384 26553 58809 7529 51111 3516 61997 31289 25532 25660 41796 19213 24385 44766 18166 3149 3139 55264 52062 54426 43482 23163 29171 48374 44165 45907 42489 49814 61943 58499 62429 56603 27468 52845 42743 2789 62111 55106 3842 49233 28943 36882 24820 39204 26793 45965 48933 60367 56155 61421 44746 56068 6586 6364 9210 4117 4465 9475 2490 54942 28655 41029 3214 15121 43639 20130 26 14900 14002 22583 37654 17226 377 5249 17652 7497 59 14453 19699 59974 40752 60709 41997 48728 56675 502 44789 23723 49787 45516 37732 54276 30934 42138 34597 58057 47693 1412 40467 37729 37625 28268 21468 2430 56265 36329 64160 28862 3493 3552 55691 16478 9526 4175 33770 52124 50350 8378 15642 39281 44367 39399 6507 29509 38753 326 1823 45220 50936 24797 56846 11290 17476 43290 29201 56629 3685 46287 42098 40461 7235 52692 8566 22161 12035 16616 60541 23397 64325 3606 33416 22977 16204 41259 12440 59888 22712 40276 55964 37696 7591 33669 58755 428 34015 15446 61892 40752 58767 31035 35946 20195 40539 44002 4092 41951 58471 22976 11708 22937 2079 55820 15278 21768 1169 39502 22502 22611 1151 2173 33773 1103 4195 26017 48708 15653 54297 17062 63263 50549 10511 53318 41673 5253 4351 4588 14946 41655 61048 18463 57745 277 43223 34595 14706 5616 58434 58824 16216 20574 35319 59752 50575 62449 29481 35416 37181 21231 45308 20039 1657 46073 29884 57504 61407 19152 35476 19375 63935 51679 38795 57447 42869 9806 36586 17464 54391 46911 45309 24416 14149 577 25282 44998 57372 39096 56961 9386 48608 51639 49890 58049 29650 49318 62457 10837 28365 52235 19919 26208 54359 26872 3089 11628 59169 15824 1524 1603 8074 11218 59792 56385 33151 29229 23000 49554 10895 25454 32912 53256 6818 49541 48249 34408 53764 57381 17320 46455 25603 4410 10295 40008 60519 63572 40971 8088 41050 61596 60960 56247 20539 9162 25704 53664 27665 54855 49527 6011 9728 29438 41742 33542 36007 26143 1430 39605 45316 50301 2373 52455 1456 26131 36247 42086 12776 38723 6709 29061 11325 7939 33510 34529 50711 42437 6069 43687 29779 49948 10730 50274 48713 5245 27816 40956 2601 14982 47902 50847 32781 31238 53494 14995 59245 3599 4479 39443 44343 5130 62847 8076 18127 36562 56306 22594 42027 26492 25741 54645 2484 4317 42818 46707 12440 9148 40929 9499 2396 12975 57881 41113 46717 35765 7990 15981 24178 31416 53690 12918 2709 3329 46288 58013 13270 6761 44768 48360 795 2316 29034 36261 28968 20356 60634 64191 48368 41659 57889 7176 50987 10921 53784 1591 39664 61056 61100 33177 27307 39989 4726 34293 13423 13046 10048 39732 51618 49599 827 11079 20198 12726 20932 49024 14876 2546 5126 34769 42326 43004 63903 51803 38252 7156 63948 30242 63208 28813 34003 6714 17048 50628 39220 60613 60463 30318 19047 64047 4112 59409 44440 18762 61776 48869 9389 62238 39240 1765 52935 50488 60206 56521 17372 60282 36549 55801 9811 49431 4289 42790 51728 47010 43405 57107 20060 59955 61762 2167 39919 56124 44010 7772 61418 46242 11003 2633 49489 35962 60018 20277 22229 35061 7503 18871 55307 48078 63491 158 24764 12625 64267 27204 47473 6381 56026 3279 2562 49081 4488 5612 63343 13627 38239 61685 41257 43702 24523 53377 55130 22008 18774 17895 20300 40964 45436 33728 24380 3788 44338 15415 51757 821 26049 19668 382 49402 55546 25709 35724 22769 28518 44710 22755 61242 18161 37197 58632 27799 55085 59230 44406 11019 51510 50119 43727 21419 55125 41290 16775 48455 22295 3016 40731 11711 58584 53701 42877 18243 12636 11303 50198 29709 19376 53354 52086 45785 58896 9878 29683 9015 40738 51368 4870 49393 18480 8966 63502 34383 42700 58519 62615 34842 14905 14025 59539 10472 1962 9059 24477 13507 39321 36406 51956 25800 28613 2276 3896 48200 3012 9686 60854 61446 42839 14083 49733 21173 56110 30719 172 13049 34591 36914 664 28567 42671 11608 29057 49296 36359 37651 50621 46832 53513 54341 3634 62077 38922 56969 49063 30041 26415 29699 17575 47464 34873 41600 5410 24844 16149 27312 53600 1909 41932 49875 9157 60082 12948 37943 13307 16978 39124 41824 44731 33321 31138 51394 52292 50186 16718 46376 2554 63945 10407 53233 38899 36065 17621 12300 14184 39999 2187 24391 16918 57664 41253 34839 45218 11241 29658 9703 29457 53011 3460 53747 37254 49863 13413 7820 33329 16745 62660 3222524835 3480459219 +1024 30809 39461 19167 48117 21158 48151 789 24527 29922 4503 20512 39969 53053 33860 31137 46107 24442 10377 30807 39909 15521 28267 3286 12234 20814 23595 58198 62520 17267 39945 40165 1626 50872 42366 36927 54412 2486 53239 14195 5702 31217 913 49884 44312 57153 41587 20577 60660 54332 7457 46384 29925 20616 60666 21881 572 16058 17667 51868 8934 8439 26171 50171 40751 22880 29430 1504 28510 9161 29812 38041 7835 16006 48617 34423 2770 21925 521 20617 41833 29088 29625 52970 25988 53769 24169 2585 56804 50281 60394 34081 49211 34519 7108 9185 45368 17324 50252 11898 2738 39260 9198 26976 42737 49208 53389 6904 33027 16139 16821 7382 22 36864 49115 42482 44678 36228 27433 19859 40987 20675 41868 41660 16805 62602 46502 52315 46198 48036 56553 11575 7007 21707 53428 63635 62239 49472 17775 45327 2190 45282 9889 4888 50607 26472 40752 39673 21340 2074 32862 39858 24012 11707 38413 59101 61514 63544 34907 38499 1974 58456 7278 6529 62283 37840 23600 40888 30725 43083 61904 4213 18388 40869 4232 51755 62271 57927 40545 42254 36108 46375 25870 39511 39531 44959 25404 49821 49288 37347 22526 60404 59373 41503 35537 19642 43451 22346 58187 14868 20842 14906 63229 60155 13623 15891 47578 23901 43417 50804 16952 12630 13184 23484 16022 13152 23365 43706 55202 41059 27501 53708 54271 56594 36909 54044 59317 52753 47972 24724 58420 23087 2434 30488 57148 48728 35350 45525 33503 49251 54057 29007 43376 10391 39137 2732 24258 16494 42543 48322 24277 34829 7448 14983 3139 46454 30470 56951 35118 1563 5611 48527 40939 11687 17425 59044 38759 20999 30531 9713 35539 45194 52874 64450 7518 49623 61344 22478 17174 7198 24363 25781 47109 58756 9753 50772 3108 2684 1579 2966 29609 29501 12610 47001 31397 14637 6713 646 49587 17083 52457 3998 42913 21928 19308 9926 21487 3395 39496 44401 48103 56348 30792 6235 41992 9183 43267 18709 35414 47804 38050 54077 33470 42286 21706 3292 26976 59374 63511 54163 2960 575 31093 30034 47765 24979 35532 10235 4634 21313 25998 5043 17538 10436 51063 51877 62025 41859 1139 50102 27981 12450 9442 1483 41959 60359 41376 63956 18456 49387 17098 29411 35582 42348 21555 7581 10704 44023 11244 12881 6513 45805 47216 16884 11904 16479 1941 47677 31410 41307 44765 30980 1437 17000 60101 5047 15881 10238 29157 48719 35265 44074 30904 62068 62507 56355 63170 63362 13623 7916 30978 24297 17782 23379 19587 39684 13725 31476 53769 34387 36400 45152 22882 26084 7326 36362 48896 56438 3037 24109 43762 5303 48935 58486 48095 19612 40142 9343 28106 19896 46070 2271 48874 5654 23131 11315 54484 28695 4940 61755 22001 31695 12590 8064 33396 37749 27201 22230 60676 29984 33056 7524 11518 27143 16748 26229 59417 24147 60971 49036 42542 20505 7819 45066 9172 6544 3686 38673 14797 53601 7360 60936 33806 56550 55687 2743 18865 12151 44673 23604 49475 42173 25123 689 41394 21691 14089 18895 59151 6264 16448 50859 1255 53577 3678 60897 39487 46571 56690 12649 11180 1662 38466 49365 40706 34767 27956 2923 41090 60748 45172 61492 57198 57828 36373 41814 9656 7553 60570 5098 45023 30006 46581 58062 46255 20489 10824 47432 21369 41330 60503 52654 14487 39411 24931 14443 44662 61335 33673 29440 33712 8494 46161 29954 60657 28020 41882 22853 30073 55136 535 44997 45002 55461 20499 58494 59883 16617 11553 4791 14874 21101 20812 20613 18820 59375 29413 9100 12958 56277 37433 14775 60437 43722 6478 7940 41160 39556 4397 2297 2993 30162 22943 13989 56710 46863 33045 44941 49837 26925 1983 52913 19532 4739 16170 61266 43728 35072 56844 6548 20097 7778 35225 37154 23307 53649 42275 36924 24041 323 31106 39737 14741 9589 20422 17208 11473 54363 60415 26404 36948 17519 9256 2336 149 59960 7234 29484 55479 53980 38921 35982 37740 3978 14009 61117 47392 41903 11337 18061 1818 29913 31675 58635 55796 46691 6264 12102 12178 49995 53389 48681 53374 54669 17755 16930 10024 14427 28073 34115 57878 58793 27557 234 4987 31650 43529 60957 37814 18446 59928 34984 63666 10872 1370 56465 42212 45312 4629 27324 36601 35261 64125 60151 64376 6877 10802 54591 24179 20546 12317 28552 30656 54099 11282 15473 21109 53891 31586 4256 47566 25857 55080 1449 60916 40423 26272 43699 29122 6036 52832 3252 48753 1285 27154 63690 2693 12331 52635 7582 61413 12782 13966 51157 33348 56096 60861 58365 55493 44891 47558 46422 33482 26613 22000 33207 39617 18331 33343 39520 41026 42960 62735 55401 23014 5512 23303 29343 18266 39007 61192 50155 25214 22823 61353 59348 13590 46209 54180 31222 35178 30062 30203 28719 52038 46013 16878 54299 7253 37962 58798 44558 30963 16357 29726 27256 28562 9510 37418 12022 26255 36803 1656 54952 46114 47006 43666 29377 60067 1929 25860 18487 23338 31711 56816 61041 28816 8734 64338 62280 37557 48413 30992 20633 2768 30836 55660 61446 62971 35215 45332 59054 35962 28903 22846 53776 33304 62430 52913 33950 22617 35382 15055 45393 30138 53782 47027 13741 13264 55550 18645 13970 23954 55281 53256 30302 7462 30072 14535 23877 29887 18238 4642 223 20821 18880 4107 21300 27932 36557 34506 28757 709 15611 45359 20998 7618 588 25718 28596 23553 21788 33039 42063 17740 59744 46648 53913 10363 47979 64468 41004 12710 64492 2702 48792 41736 5684 40570 7375 2786 27608 18950 58773 6133 46677 43849 50463 16117 25248 2069 58196 51165 11700 9569 49972 48845 25948 15180 47801 22986 20380 23438 23241 47890 25209 2149 46053 54744 33514 60504 3030 1114 14268 55702 13900 25676 16376 29837 3433 27128 26176 22225 12944 17153 14259 24142 8409 8423 3596 36131 23756 8267 12041 46325 21399 25755 60235 36985 30556 4777 56087 43019 27189 26041 57505 59930 38497 27818 21768 35949 49405 53004 18455 49877 25362 7387 21400 45582 21301 15698 5478 35640 22937 25793 42165 31342 36712 56432 14308 44392 34492 1849 21282 4435 50725 46745 34613 8553 15325 29465 35340 11204 55086 27190 33583 9525 16205 60137 4546 50758 41076 14414 53896 28434 61897 37999 50469 33406 16329 60966 50763 37566 41194 39575 51028 35955 3075 19878 50759 22728 17178 7770 61787 12494 1361 51160 18951 19663 7545 16108 46895 64225 54012 7030 20660 11600 17624 24232 25149 56981 36439 34345 29876 28343 57466 23107 38636 63945 35199 40054 27028 21723 6664 28000 30464 7581 21498 15180 21678 49034 14587 45685 34363 21872 10268 12116 61934 18146 25045 6868 25473 17003 34376 46036 20154 63063 33660 27830 48896 10234 27283 40764 26847 8148 29168 20402 15510 39930 52474 35946 43920 37017 46014 9185 3814 1782 39369 38597 48933 35197 60076 49569 38806 21378 64291 44867 13548 43384 23523 19164 30480 39359 28245 36063 54686 17185 9064 55887 2660 56732 11074 2402 55457 46329 3976 26249 40553 10778 22748 49406 14436 33017 53867 47154 486 19269 23034 61195 34028 41881 63653 48504 33938 48963 10648 13662 50796 63695 38975 14561 8724 37600 41844 42775 15587 10185 33122 5544 56541 58869 39701 17228 30792 51734 16809 31394 54793 36584 26494 50457 5849 7664 10075 32974 35452 10422 45252 23956 14431 18248 18422 34017 30517 5520 10079 28095 51067 9571 62471 19352 2995 19769 43980 45279 6354 17637 40211 56330 34526 28613 37788 58068 41571 49601 13430 53792 17608 21279 50375 30419 989 28149 11405 50920 18881 55084 56411 61771 28762 49330 5076 55348 8438 29882 44177 60638 24630 13005 48681 35388 954 11895 64030 14156 55924 18123 13322 41053 31683 51060 16650 283 59387 3243 17872 16755 9560 14318 61212 45318 34062 49424 45062 4979 22568 54440 30438 16689 58543 4571 37268 29472 57392 43896 9116 33092 30780 37767 63893 61273 25128 9469 51073 13100 30925 63144 63047 30618 50244 42396 46161 13956 14297 31612 24508 50163 20694 63411 20285 29777 45807 22019 47892 53345 62591 62320 59052 13602 60178 56032 43502 2307 52515 6074 19889 55340 23273 64208 31154 14204 10633 52493 7972 1216 58656 22965 55410 41883 12679 27339 61473 30498 4384 50728 36719 44738 7498 62401 57634 11820 43543 41962 5872 17717 6430 56929 42566 41338 9400 9781 16919 44574 4635 57499 48954 15383 43963 25771 25426 49041 45619 52414 56497 4908 34222 54660 62375 32782 23421 20975 27615 24215 40459 11296 2082 59651 56217 60076 24191 33174 48853 5337 10191 55381 12865 38587 49724 46055 8205 39691 58528 1683 38491 20817 36578 49685 1529 27312 57413 45311 6529 31119 51328 41720 4305 52261 13054 31001 5217 8277 42070 47506 43873 45214 5657 15555 51078 50354 14271 28980 54684 21252 7828 29900 50067 39606 21097 16075 59698 2390 11456 9484 15778 38019 8554 63211 9441 45013 52823 62949 11740 29687 1594 8767 18475 7538 46654 6428 23571 64124 4472 1281 40152 4561 60986 15820 61007 61485 2812 53324 8326 18606 23854 15914 43185 41646 28231 38374 12534 8534 57680 57935 40370 24733 33299 62687 34671 37223 20514 51979 10969 40814 48540 10070 38937 39495 57782 41368 20030 62659 27615 41772 54071 2667 3750 23472 28340 9549 46907 57577 9093 36454 47569 14640 53458 26139 24544 29449 50363 24450 53225 39279 1577 37045 14633 61029 39815 30726 27336 14739 50685 50757 41189 6694 56727 62656 28925 50127 36358 62424 30045 20667 52589 29803 46809 38259 62309 14823 13839 23911 58756 49965 4238 24681 54852 11164 60781 13992 30480 24502 18496 55321 61593 63100 17725 16775 63073 19186 61595 44253 17333 20458 48196 15772 59559 19331 27346 26105 16006 24463 38787 19701 1563 11401 19202 38549 30544 12083 15278 47229 49436 29115 14081 44640 26781 6158 40735 28858 50584 37526 12927 14770 5128 36986 36568 44444 50549 27584 60000 39059 39505 52803 49615 64349 24158 27913 29697 54160 49664 14006 35549 29430 38823 40197 42224 53863 58884 2372 62291 31162 36853 4309 25433 9655 11235 15687 43309 50355 7640 30220 14445 39530 24864 54648 24223 7428 59510 25109 57866 41469 33760 63951 35865 36374 7726 22514 17324 58433 49377 58052 34501 53602 28824 58089 28717 31138 17723 39946 31019 36388 25866 11436 57829 9450 34317 39593 7929 4659 16174 36311 884 39145 7382 18131 55454 21994 58875 53186 42248 22321 16883 28070 1783 40318 53083 45245 25959 45413 61926 49569 45477 59849 62499 4641 22510 14830 27244 24311 42008 60412 25401 62277 5679 17415 37823 463 18130 62611 34186 34697 23035 26346 14912 4738 23471 58181 12686 31503 8394 49180 19542 9817 43921 20752 17692 54847 5352 18407 44347 44134 13624 9539 224 8564 44887 64320 43112 31002 13995 1407 30134 13560 34026 59210 39785 61642 21989 49743 63966 29184 9343 62005 2224 33094 35315 1387 21951 55458 6984 9253 16007 14104 8232 62745 24492 30605 49039 59014 25583 28271 28129 25091 42145 56978 49310 38923 11312 61947 59417 16472 41877 1515 37918 33800 402 54759 52343 41281 22743 38963 36692 24247 57130 17554 34071 7512 51442 59025 44949 33850 43108 23932 59651 51100 40867 30772 2321 13483 7923 48261 37421 4277 24662 31455 20390 59967 37079 22012 44339 10003 51660 10027 12798 12872 19109 61606 18150 212 4972 39967 33716 59865 37742 4060 22627 54853 2849 47056 27236 20199 19609 59292 27991 2927 13269 43563 12657 4929 16823 62235 62205 14918 42905 54928 39797 19115 51835 26495 1904 51719 34714 20642 15600 36514 36850 49233 4360 46354 63839 18678 21705 11958 57592 39286 21509 49374 27539 63790 51842 2570 11736 47838 45391 5621 2265 48040 33253 22298 20245 43262 26235 15312 57194 8018 1969 24322 58076 58848 42681 48359 14538 11531 45664 49673 27925 5836 58917 57463 47758 61279 20672 7811 37867 17935 36788 63594 30439 59736 3152 30285 24065 61111 49476 4625 58938 45258 9649 29729 27335 58610 34755 53604 48555 45928 34852 54607 54703 49629 21081 34143 42176 35984 33771 11494 34336 14656 36521 27996 40289 5353 41305 41841 60266 22478 56223 58490 36027 38482 3176 5760 60803 35630 37144 22923 48541 63586 60138 53755 41488 45343 62075 6791 28798 27007 14956 49323 2304 10305 45126 41592 30981 5852 53623 52948 8248 60053 5750 30822 63755 48337 34316 61883 61888 56744 43540 8698 33191 4843 54467 28394 52512 50003 28621 37209 63606 8305 63315 12898 49160 21566 26374 26486 26587 5158 644 617 33831 43018 27953 9861 692 59349 37344 52061 56783 32986 61912 47855 41413 44007 48742 33272 10643 51501 38887 16785 23094 14312 20014 16343 52218 51205 43584 20018 41924 11831 61808 62882 43243 26199 12918 9307 23369 48454 6318 28502 6656 12298 54261 50036 45599 1980 60322 38804 56135 42721 28488 18217 3346682492 3475883033 +1024 33067 59007 29202 96 5755 12096 45776 47220 22371 29078 45101 4969 4770 15049 20204 11285 20462 35549 3076 4395 3229 29866 57330 29521 24902 54509 31443 3592 28656 323 5147 39415 38087 43367 41594 19340 21318 20292 19321 21154 4915 54078 2446 17304 54016 25964 1504 33395 17620 9237 42083 22668 233 9853 56216 36253 12106 33945 64279 19822 64165 11391 50524 1416 31626 28310 43254 45075 16417 21575 26262 8936 19673 2912 62753 52822 42432 23906 63939 27790 14587 56669 51805 13536 12453 53622 51122 13366 62097 48804 34847 44449 64458 54673 24951 44892 408 4204 31680 63629 49123 25327 45793 39818 15503 43653 43015 32934 31373 2308 14079 5469 35363 36558 20542 172 45468 11588 36346 62224 53326 1229 3939 63796 45204 16393 41356 13518 20844 33664 24490 15800 42141 60257 15199 49862 42734 4478 9999 16361 31678 15966 1026 12551 60267 19304 39001 35156 2601 60989 14588 62878 20971 31617 22949 17066 58253 26380 62145 38975 62082 5640 48667 30229 42215 46578 50675 21533 63200 10713 58568 50649 10603 14883 30647 39814 31125 3165 1234 13783 8889 51237 26031 53489 63777 13991 56297 33886 40463 40758 11601 56526 41755 40667 35518 49853 3922 31524 5427 11421 63247 64093 48021 23443 517 5688 43977 23548 18221 27916 61095 27032 23159 1041 32947 13192 28435 31705 53954 40656 42702 49511 20551 52142 8791 48115 4610 12590 36023 25207 19471 38418 36678 38458 20830 9268 8278 19917 38249 36513 12833 36312 2888 29384 59955 53178 19855 21766 54421 20685 22754 10155 41037 56810 26302 52215 23987 53079 15946 33246 7499 2689 10622 12048 13575 30960 60857 3293 49796 62221 36647 51611 652 58407 62486 34650 28145 55688 50384 20065 4649 21721 44078 24565 41969 9831 25424 7761 53427 38116 45822 61352 48066 38196 44050 57663 1281 5287 7902 18681 28284 13643 61594 4040 27627 50431 30451 16020 34754 51520 59119 63926 11127 14616 21771 11689 2266 37184 52070 63792 14341 11731 47135 49743 4112 4527 53852 55056 51067 5062 59021 9982 61779 21049 47173 10159 55492 7628 47739 14953 26602 29279 49481 23436 44692 48978 51516 51914 4421 56068 55935 35852 14393 20182 30523 42031 37275 62650 58097 44942 40778 17461 17945 5167 55662 16665 2910 25304 45645 14000 58751 12228 38911 42422 18649 11779 56932 44222 7451 27568 13263 4527 34453 46118 59186 45273 43718 43106 56060 51192 45039 10148 25341 34752 43925 62949 6054 39464 49011 33184 15692 26226 46256 23356 11571 34284 10041 42133 49758 61268 59176 56983 29026 4396 23137 7414 10062 60294 11169 40248 61641 47526 53194 44527 18983 26003 57683 28101 58870 48685 11463 45075 3797 53570 49120 8597 22005 30822 32793 22913 31647 29882 44389 61420 4992 55501 6947 21997 59508 25419 48801 50308 25297 9357 14354 46595 52897 17069 24400 16608 17684 38132 44068 62766 59787 30895 13386 7438 26185 45789 48188 20471 58510 14206 43859 61854 20883 2032 31638 22214 27285 52076 47969 46478 40079 39115 1242 61880 13268 30008 27033 18948 2857 29851 46918 21738 34082 6237 50241 62634 27090 53783 63065 40136 9497 15269 21561 9636 55103 10611 3061 47845 12675 35440 7639 4965 60219 34339 45656 28722 39195 12212 60306 63631 33233 41599 8494 63213 2336 43396 5257 24726 17622 4121 29107 54353 4512 36796 44041 23279 17214 31325 24162 11440 27301 16457 62047 85 13185 42921 27870 3776 54568 50486 53885 26140 8687 21283 3045 45461 37077 38041 58853 16000 40031 64039 12469 39500 23158 36780 45018 23448 8916 63897 11272 38058 4925 49902 2822 55095 60350 62940 3772 33689 55653 56331 57505 57200 4151 2838 39146 48612 26638 8106 40441 61739 3551 59493 26520 29839 29984 37100 30584 28667 11117 45085 8667 7961 6818 40009 49850 7532 56097 35363 38708 29500 30884 40291 34849 16815 6383 45136 58138 29292 31642 54794 14291 24469 36290 47914 45458 35353 2350 43356 45827 27242 55859 22068 4539 51931 6040 44299 40437 54725 17809 33395 23958 44318 9307 63016 10493 62481 46453 35847 61839 16090 393 36904 48874 5234 5492 50573 17244 51224 10927 28337 39515 33396 54329 14441 63757 59867 57790 3233 29353 8044 54831 50005 10518 50254 30898 35186 14814 3969 19760 3353 35165 31133 22167 28168 10047 14252 57172 18878 46540 44700 55114 61413 55774 9682 8276 48372 4340 23421 13431 10919 22009 56950 7351 38321 28401 3643 34907 23515 2681 24551 4118 37186 18650 10414 56223 40897 57578 34380 63625 23739 46500 5041 8085 6301 14781 18368 56976 34594 55717 53126 26369 41152 55207 17090 42813 7468 57235 9132 49859 46453 36436 64117 23075 29290 26586 23835 2871 55296 42248 13374 4611 7281 63222 20462 47926 23419 59325 23180 29747 55569 52783 41100 52673 48530 40877 12995 59733 51796 41471 38863 19066 29923 60848 268 27306 60731 12427 49127 41974 11286 50270 3751 36579 49456 3166 51520 21044 40065 45675 24730 16424 59680 54125 34864 12423 48860 60568 18824 44232 48504 33060 47622 47824 10265 40134 13567 59284 49065 21541 58039 53238 64254 35298 16391 45615 42601 52404 64271 45983 46800 20390 37881 34259 34581 27369 29194 20896 59332 29188 39519 44012 39072 15258 5755 63962 11989 35144 6558 35974 6364 64213 14398 39807 60820 41694 4031 15779 26092 39520 29608 1069 31708 7320 43109 37166 9232 5716 25141 36104 37835 36990 4947 59047 24629 25367 20286 28150 13415 27792 9088 24112 1157 49307 56159 115 9104 41470 24135 1050 5549 44879 58154 10934 8243 34312 21915 44483 14600 54025 14773 31234 56678 58153 36517 43155 24265 50724 63522 3397 50670 16705 15796 12503 34543 56605 15445 24351 2743 51061 15840 28530 48477 49750 61772 4180 59085 257 37077 39090 50645 44531 45812 5910 47348 173 47610 2921 5514 13872 33765 44081 53704 43147 40966 26863 26700 15975 39446 48367 52879 7572 38824 15153 1878 4635 17270 22339 16798 7466 16343 61765 19450 44783 56053 52721 26258 58824 30448 35979 18723 42137 49129 53344 8224 6827 47855 35630 2597 63584 42218 27541 11809 45033 4296 4315 61453 15787 40246 50196 44100 57015 36828 9722 44122 56739 44752 1828 31527 39946 6038 22194 37402 19469 48928 52265 62725 63130 61023 2508 30683 3426 57336 16582 35133 37536 49128 24548 43622 26138 37755 14737 7314 8011 21487 9099 14493 42884 238 3385 20489 43805 12960 49028 57289 64312 20454 19255 30201 41990 17986 16442 41557 55394 7739 17550 46286 34084 35726 36167 38768 37567 36108 51209 47473 40088 56750 541 34925 15825 6565 47913 61687 45024 25783 13750 5314 38614 41019 31233 16892 6830 3160 48075 28182 17144 37199 4313 18106 6554 19958 8498 39692 62388 1020 14125 16781 2988 52474 9803 42062 34170 28178 60714 58030 36702 43297 38748 59883 27287 30830 33725 61620 9926 27492 53595 34666 191 57756 8001 10388 50661 14591 64081 45910 1757 17695 14440 64279 52005 42390 39313 41350 16526 48973 26724 12193 16144 3377 34161 29089 56772 50201 34738 15263 5345 15241 21986 55812 24593 59861 28878 36836 38451 27717 9991 60332 44095 2060 28623 53174 28220 13784 54006 2198 40215 35381 52273 19766 60578 12442 62958 30375 63585 30305 21679 55209 5769 38697 53747 26422 2408 43646 13416 43307 27363 6222 62283 39392 44277 61440 21697 14395 15941 36990 45450 40768 63817 29117 16477 27432 36037 22932 27168 36274 17299 21849 62412 8890 19514 14308 54503 27619 9123 45888 49781 40406 61686 1298 50961 2013 42064 31681 30915 45115 25563 7867 52598 18285 46696 33333 45870 33819 37453 1524 3149 48189 8162 26047 25418 12075 63092 25827 18337 4027 46196 11063 55556 25175 33596 6219 11056 7980 11297 24584 5193 43816 26388 11195 30698 53168 23351 30118 2741 21331 4574 50995 31091 1894 1526 17701 61059 704 30703 51620 47696 12248 18024 9574 25339 6042 50634 61029 17856 30301 14501 41638 149 2308 7297 39787 42894 12298 63531 15123 53404 3159 15186 55706 61880 51245 51747 53925 32980 54503 45974 17217 22860 10781 6103 12484 1619 63343 9040 55106 7481 45745 53519 34749 59634 8593 51598 16066 60742 62737 5884 26754 10201 15519 36425 60560 54575 24548 25213 9865 33390 12626 26028 34569 20600 39794 2258 39663 38402 59206 47922 26924 18463 29378 45231 58967 55075 61203 15463 30191 54708 44610 20225 16993 60721 64209 17270 62992 21028 14273 13761 50843 43368 6474 59636 678 26995 34642 33133 56975 49478 30316 13291 17516 6580 24854 39280 45857 64183 62507 5381 3951 55514 41992 18614 6636 43799 24566 9261 9392 14551 38200 52372 15109 1724 60979 63145 14293 9400 30963 20497 48949 35993 16094 58402 47753 22510 20870 8781 26636 4291 26234 59518 42505 21830 36819 3828 36489 11984 25014 24735 36832 30833 2539 11623 58393 24010 63165 21167 17572 30081 8244 53321 55181 59659 7262 53493 538 49660 5685 18335 25312 12093 52667 3479 18056 43357 59602 37169 23393 35557 39432 17124 21679 56299 8543 54323 39423 1009 24476 59193 47975 12281 61311 48223 58171 30841 49674 45106 9170 50548 19342 29876 17577 17106 45749 16265 26337 58436 60956 28072 43184 20148 62471 55479 39372 5241 1752 63529 24299 60905 21018 23301 25079 53082 6737 21163 33412 3852 62617 51923 43699 58372 24433 50080 46783 60579 1703 21213 40122 57017 22066 36746 17926 22904 50367 7645 13973 13736 48336 5008 54002 37277 39863 15920 28292 6910 44888 37072 60824 12154 30217 21330 54209 57551 739 2074 23783 53867 43527 53463 45680 52294 30902 46371 40951 52190 22040 39605 21129 39111 55597 11675 38174 28308 13062 2330 7805 56230 20515 12946 60557 50236 4006 20125 24897 62553 17374 40696 43424 33803 62738 9733 55097 37338 56632 4758 7217 18055 62524 20742 47902 20622 41267 53517 33867 19905 54635 16388 21564 29382 52167 7305 61742 25500 40482 50642 53305 16846 59820 18614 62892 15067 2485 31234 55575 60827 56152 472 10037 55497 37752 53008 36390 36043 34293 44689 64133 56596 31197 36595 8298 53444 36918 39915 50398 46804 24622 35689 31742 41759 30639 30189 48800 27714 53302 62399 40274 22050 37755 45043 52167 21379 20017 10852 58601 7397 35387 13426 28387 13955 27182 8964 14507 12477 22843 2568 30635 13548 25592 16 41147 2280 4093 55562 54299 62224 29674 8498 10409 2614 5528 13037 21688 3909 37560 7639 4489 50916 14697 43044 10358 11088 47317 17989 23240 45233 16184 64104 60917 50544 11724 4674 25541 7442 12402 63706 4039 39943 13731 42187 16823 55715 39994 47479 60836 10022 31387 34779 49076 54656 6244 46203 52594 30259 49443 30818 27167 9668 43110 53924 26597 7202 52863 3545 56650 53634 19010 57421 61878 52213 7509 26338 52556 52913 50146 1012 53087 9423 25702 34781 2129 54537 34440 2049 60123 45179 11124 17209 33012 53019 49204 41201 48233 37354 21853 46257 21053 647 606 1921 38276 59224 12305 14654 26721 9539 5699 6827 63276 29595 41551 50520 28065 41715 43961 48629 12313 43749 7291 23352 10539 15154 5059 43705 33792 23877 32872 59281 4191 11224 38756 16788 36058 2980 62698 56640 14973 41305 26156 26978 21676 54823 55252 30885 18013 20135 34918 5876 9395 64146 50494 55172 31443 27881 18170 45405 39021 52924 13928 55808 63834 51616 11038 25198 40323 52974 53105 45948 7392 20242 44811 4542 38085 37918 1667 15546 64344 59358 9482 37922 56034 51381 22803 44763 12209 2646 28774 23746 47088 29151 52711 8077 45733 51203 1520 1342 49157 17704 27765 9373 57980 64204 3545 13978 13607 10840 48991 42689 40621 223 57314 49435 10039 14703 12751 14456 23922 48963 47593 44120 44843 3465 45606 59859 55857 53885 36029 30425 37814 48093 26944 38169 58725 60958 62702 47640 56615 47458 6826 17285 6685 22969 21736 30424 22734 20334 51342 27685 50629 33295 5690 52656 37973 28704 52956 42448 14847 27667 53328 26688 24744 3613 17132 14972 3422 28316 54318 2779 49766 25661 16175 19502 53552 21726 21027 38436 27467 30918 55453 49144 20442 25708 7752 18375 5050 27338 42692 10891 25606 2456 55250 29393 43376 57209 61127 60202 52558 43642 23959 13221 27962 30349 4686 29194 43744 42539 5486 50214 15724 60847 60996 10593 2914 46606 4127 7177 23506 6815 12730 63572 29696 14491 13215 10846 59499 36706 44893 37610 53379 47893 20160 34883 37967 24704 36429 42327 53925 25988 60524 1004 761 20445 16216 25539 18122 20151 58725 34029 57069 29999 44757 53407 29242 28473 51962 22790 61734 2110 7627 59395 51582 56508 10234 50118 27864 21625 28596 18596 21376 12336 43057 39110 5895 52704 56890 60096 1439 12478 54745 27330 47838 38322 32905 26711 1340 11506 49816 33475 61430 10107 23704 23873 48788 27072 3194 21352 59210 0 1313690386 +16 55454 16773 17372 29077 49334 47886 14967 54771 24338 59307 7435 37002 13776 27217 51511 8608 63699 2341 5216 54658 59774 5767 6169 23682 21720 9540 63215 56544 874 34697 2713 24065 0 1251205363 +16 30701 15713 16355 60570 34676 5199 47111 12242 18967 20217 7110 17020 61302 47218 9633 28409 61029 28624 30017 28029 47918 54796 16789 8120 22047 56875 1697 23252 11982 20222 16585 44792 0 3445878999 +16 884 54911 20198 18838 13442 7639 13693 9879 21574 2998 10873 7024 18003 49957 46175 62798 16705 49228 62143 2555 3789 10147 7001 48153 10253 63169 61308 1034 53349 19671 25699 5246 0 3367668030 +16 62624 40323 62984 3505 53178 43152 16060 49172 11506 29426 6126 37012 42016 52054 31726 33821 20834 53189 9224 1958 30482 16251 17200 33913 16601 46909 46022 57211 41209 59318 31077 50066 0 1328218579 +16 5744 60214 52005 51296 38740 37123 30597 60308 18370 10010 22024 60659 48334 19958 2286 64083 24073 34353 17382 61384 36478 31404 20215 64039 25990 26739 50396 27663 50575 21113 41272 19434 0 1294370078 +16 59944 41162 57073 22170 30150 7225 63834 8557 46326 11382 41441 44248 63721 50040 4575 59601 31498 38534 33989 60653 15742 28422 59806 5453 49242 34374 14247 29009 19023 18225 11383 54653 0 3428279751 +16 64072 299 30271 49191 40881 60146 17236 30334 54506 57893 35630 16731 16292 43947 34362 15181 35450 4267 44645 16668 54095 40825 6463 15544 36867 7531 19951 2917 45033 41595 4073 36216 0 1189171679 +16 45108 46075 15098 22836 46684 50134 57147 47540 20468 55787 17915 48376 46785 36885 50118 46278 63175 57523 59611 46376 12863 4890 13660 57633 34070 1704 49231 15071 63010 43745 13741 59222 0 1179365466 +32 12786 6617 61771 63347 18992 21681 15057 43397 27367 23595 39859 11956 14022 61652 5068 47108 25668 23616 50649 17213 12880 42903 36286 51962 42935 28660 32796 30745 62105 52686 22603 912 31095 58137 58422 2392 44345 24716 59232 53663 43118 15943 20592 9823 13447 49517 42621 50119 1097 55764 4450 28156 3079 24195 37364 25485 12979 5287 60967 12247 12898 46289 64038 21949 0 1251120206 +32 38234 8940 55616 52506 35034 22046 44132 29507 44491 3739 4634 34735 37429 15269 43650 25669 33374 39325 5924 2462 61645 19471 26865 48801 11599 43224 7701 62458 57643 1886 23608 64317 21728 10483 9818 16965 29122 5850 21344 58430 33881 23081 48331 58748 34455 35583 34586 47853 50830 23254 24937 51412 23193 14530 63892 62541 31130 40100 28530 35747 3467 37968 24371 36835 0 3439262212 +32 52195 33734 20719 15873 60539 21231 22922 22044 3847 6107 16303 31635 25125 5225 52711 52899 24959 42029 64092 5607 7811 35016 29408 56030 52870 14776 49488 18577 14927 42289 2380 49013 11945 33543 22774 18414 28638 21782 26050 198 9302 57009 25298 44103 27288 12794 55935 61499 19408 17528 21754 61255 52078 61999 41223 53409 22250 14904 48096 51399 21253 11617 41586 8172 0 3423646780 +32 40555 33535 61496 59641 54667 57851 26157 248 35088 48959 14196 47372 22574 19871 64264 41536 57369 52888 10787 40808 14904 7604 50791 34107 43766 44433 4058 34287 57262 26353 18483 39403 19255 55555 47863 56278 37547 37975 51102 33459 28980 45343 37609 17893 52698 31125 11026 22094 7480 53243 30109 57206 54790 49297 22786 28493 42341 8151 16588 16372 18563 55382 3931 54899 0 1235981461 +32 25431 31447 20494 3832 42203 58282 36262 24099 61528 34407 57244 1781 52986 62594 41053 63204 18181 31566 8864 24349 37727 52535 44475 63638 9792 34530 6291 25940 34634 35730 48489 57747 13279 10487 57041 22496 29869 35685 17299 25802 15127 61592 4105 40760 13316 14903 20172 11633 52067 43415 1459 4862 29573 17464 132 5150 42591 33472 55874 3578 60794 56855 39400 30126 0 3413543192 +32 38384 47748 13094 45861 39283 11465 28923 45775 49103 35511 7127 30900 20319 45077 18003 31233 9591 51254 17620 51635 17724 13207 23692 39132 25426 16412 49545 24706 63428 30696 29890 36985 34817 37859 3368 50074 55912 63068 45493 28347 278 51080 41016 35371 29267 1120 29938 17180 52356 29508 3454 25827 15735 12536 49469 38206 48508 20881 61655 57903 63030 28716 23188 3668 0 1317139218 +32 48028 59781 58691 16663 11149 35928 58230 13486 6454 38156 23735 14491 59697 5481 12918 59043 59559 29230 1055 25477 51456 3127 31732 37298 48475 17081 4431 23911 56226 31081 35802 16913 19432 52248 48165 5548 64016 40899 1521 46316 29885 27475 23938 15808 33644 55902 47521 23881 23694 34078 6939 55129 14165 58777 36994 49755 8617 8142 19120 2254 425 13809 56903 25807 0 3381907656 +32 10982 31086 23424 795 24407 12878 36456 40603 3113 48604 37498 44626 19279 16033 42752 6062 56210 11124 49044 43560 14467 17955 12909 58977 47580 38339 8937 45644 50858 22330 55513 49436 50698 58570 37623 47457 57339 24218 58975 54170 25619 62095 5478 46400 52001 62865 6361 41358 15146 45341 18454 1057 200 48830 21098 18548 5859 56403 242 37213 8900 2766 42981 64444 0 3427824341 +64 62882 46268 54525 17883 56862 1336 38572 37301 34195 48618 59326 37830 4604 2394 8341 28869 40111 62568 58143 36270 7798 53527 42985 54208 40312 50095 55248 37201 22503 19467 23015 43738 4287 10481 46883 62533 24218 25992 28478 46189 23010 9654 45355 45326 745 59010 39384 18132 6190 63374 46109 26739 40372 56843 49619 51643 59136 47900 16015 1026 59056 25229 48658 55560 64254 11420 24798 60541 28708 30492 47707 61819 7621 23689 29312 44727 44193 35644 56863 15858 28016 40161 63882 53035 9056 54402 40617 46505 57328 39249 4647 7245 47019 56179 36302 56100 22421 37830 32796 45309 2292 36515 33 36167 3871 54975 3421 62292 6687 13800 9360 28676 11939 40691 18468 48528 60116 20907 33629 20363 1940 680 846 16669 3065 52824 64239 60390 0 1319044037 +64 40582 56920 20996 25816 54435 37198 10388 38412 8668 38738 8863 34525 9002 35422 313 33289 62522 61862 5932 41724 23159 52299 58050 54820 52111 2121 22461 48033 4883 51111 50274 5572 58626 54408 36291 27281 38617 29621 63898 51852 59579 26322 35323 21299 60418 55550 47707 51882 49107 35809 44914 62458 38831 61170 34502 21946 53858 15436 4967 63091 39851 30919 5374 30910 19325 47382 56589 4388 29572 6655 55956 34224 53028 13094 23310 62949 58481 41278 12441 29873 48635 25806 266 45082 55538 53993 13937 22597 42905 24987 25168 56410 55201 54061 51484 56880 54842 53800 45353 64389 62178 62708 54205 63942 44938 12143 8278 34521 39525 3806 48986 39827 53894 56337 34216 13626 16902 19426 16860 61019 29788 15783 50860 12581 20443 14248 17829 44684 0 3456165587 +64 55277 51924 30861 18293 9789 4593 28228 12597 10986 10531 31545 18270 48547 5025 8051 27713 7330 56116 12881 23428 19544 28560 3246 31032 43424 22224 39468 13984 368 58265 33869 24637 29087 35578 34715 48711 36658 37537 34700 41914 25487 16166 48523 64159 18331 10991 9818 31650 7067 30997 63911 39031 48049 39229 29452 4025 33916 20820 558 22969 1439 59797 4375 58880 19757 27253 31384 21891 2183 37749 41445 4568 61452 6820 6478 63012 62230 30613 26049 14799 56000 45122 53352 52089 8228 20868 21786 33809 31596 51383 10401 13447 35638 29225 38276 47636 13467 16700 21719 53781 23210 29462 54881 62038 1188 20164 60940 18947 34385 12508 29475 2926 21446 11367 7493 61056 61638 13444 36631 51849 60597 35843 38565 29756 21532 19957 61176 21634 0 1324278640 +64 45199 6505 61823 57859 18587 19109 11034 45114 16659 36625 19031 46753 28080 43661 47026 51324 16473 59901 56538 58401 5874 53966 58649 57067 62239 41908 1278 44710 55211 60443 28189 58862 12236 33704 55537 56528 1963 56653 53730 63376 40331 40414 27882 3213 19533 45445 26824 62632 39784 5376 33727 54349 41307 35179 36846 59532 37096 7380 4907 44641 35735 36849 53029 29968 10806 25755 24718 10868 384 63083 22024 56721 23283 5070 45657 18320 38152 6476 50384 19498 5533 20738 51228 26260 36842 17519 21473 34771 788 1016 50679 61127 52444 45722 29389 60019 59589 25480 5257 55354 27320 5367 28141 40258 7040 9957 38738 45505 30454 58603 47694 4051 62056 45913 16564 10774 29828 29739 26081 60066 29923 39993 2844 39734 44431 4269 39075 39165 0 1286501183 +64 16811 59873 15233 10931 9098 32900 6805 41226 12870 48426 25141 46305 11205 8016 26204 34542 62019 35648 57158 17108 5124 19436 39173 34852 64161 9904 31031 12061 2847 33000 45443 3919 44622 33948 51040 20341 38036 1318 48391 50132 43599 56461 55636 29114 30709 23873 58614 3511 42537 18292 11574 33394 14308 48733 7578 37187 40367 44385 27001 23881 33560 21120 40462 23945 49585 12454 46319 27660 6744 20135 14171 63633 33902 34500 18481 24030 14564 19444 25204 55699 19216 12467 5460 13611 57155 25167 60783 55481 24010 29722 58916 6894 62033 41272 17746 60148 25102 42605 2340 44303 43278 9710 41432 19567 54240 40583 62150 3604 41578 63430 56789 38542 25106 29804 16720 31184 7650 13504 55188 12288 14446 51355 8442 36877 26617 38498 45411 18186 0 3434279814 +64 1413 45886 50559 44051 18524 37324 60685 601 26401 34106 39136 18110 41149 53846 14568 2758 12854 20205 29558 53816 59997 62579 23713 37342 2894 21855 35663 31600 11280 54404 18093 48906 59465 39710 10612 34946 37751 51642 36197 47832 52460 6149 5151 37973 26961 400 50014 46610 7005 23205 60958 60967 42772 56983 3946 23021 40774 5911 32939 19388 41273 47509 64373 41593 47551 54660 45378 8736 14733 16699 24068 40416 55679 58042 14250 18482 38846 50155 6429 54594 3514 6512 46076 10294 47786 59285 5038 58960 28405 47180 60191 46515 21774 15148 56058 44399 49840 22979 36710 47259 49315 50949 33870 29772 23022 26978 22565 48732 13148 4368 44728 17107 60682 20753 21371 3460 36233 29895 41686 7844 62694 46833 54548 55409 62934 26413 10839 27200 0 1270491454 +64 54397 23495 4914 44516 61472 6155 21561 45435 15249 50311 23002 10895 16324 23928 23686 38006 55245 12655 59261 26504 61443 11074 27063 34021 43524 5148 5813 29209 50807 5559 9316 37816 28919 23262 48935 52860 29434 16013 31234 44148 55785 43689 20845 30287 64416 60927 29356 34299 49648 26720 50479 132 37343 28228 54905 37619 37886 45008 8275 16306 51831 13218 57453 25947 5360 23264 56840 2872 62404 21802 55701 15769 39493 24352 23010 15956 19288 43003 18142 13268 62004 4475 43977 3731 52797 19378 55954 41116 15585 9283 26268 47919 30992 49879 48599 6993 29827 6237 25427 35058 1910 9951 41728 26272 55708 35715 26254 37696 3734 25183 42629 9545 4942 19486 57289 36566 60089 17707 56354 30896 35705 7191 58670 4500 55377 31196 48611 3959 0 1301797085 +64 10399 17837 48799 13413 5494 54362 8732 20896 50323 62887 8544 8722 25114 29532 1263 40526 11239 36634 60499 2370 11712 46356 42914 14326 42065 7313 48822 15095 49238 62654 38406 51554 8589 26289 28887 21631 22083 57873 20279 21288 19787 46237 61231 55065 47338 28636 55426 45554 53322 59873 56882 48719 31453 17841 5400 40970 15527 5856 53854 29316 37661 8726 61189 45818 12621 35446 25420 17038 3093 62323 21331 59443 59475 21050 40813 34648 14415 18982 11427 20145 48708 16258 18152 58998 58474 41423 5761 44993 41728 61463 36392 15984 58235 1645 63803 53137 47323 49874 10051 58954 40077 13129 40557 36153 49408 5822 47829 60769 6034 7935 990 56924 12909 34690 40558 41211 20253 55075 58296 48373 46503 38881 42627 19129 63219 25924 63148 30745 0 1295875366 +128 4586 45970 33299 21516 5806 3521 18920 56698 11710 10263 35193 15058 41232 53365 44088 34390 34338 46693 4451 37744 17846 35625 1897 62328 47762 62191 14984 39092 45161 59913 26735 6396 43568 29987 63554 47755 49870 33228 33241 19826 12011 5969 39234 6709 50040 5821 35994 55201 37556 54658 56072 10082 27423 14110 51127 35863 25918 14528 45070 16271 17493 29110 30550 62393 1089 21971 49641 43952 9677 17111 64051 46046 7272 37478 45249 33528 59089 14586 3757 24593 45538 60370 34287 24533 16200 35480 42691 31245 12252 59173 34823 26119 47373 16169 9906 17374 63080 14815 16506 58848 43796 58993 2141 1488 1997 8138 15536 47935 23160 6738 38299 58895 9251 23189 7705 12857 5380 4706 3202 33494 27369 14086 12199 22203 20741 49752 19984 19791 18655 31180 63176 30758 53135 34650 43161 34427 37540 26671 42389 35503 53537 13642 5705 45364 59031 36018 11748 55586 24714 28005 63182 48882 11083 44158 23580 63238 64258 5860 12151 1511 39926 49834 25763 30059 2416 28860 49492 37946 26864 51282 10083 9323 60885 61818 39586 37606 4577 662 39380 26101 52821 10525 20881 24426 39063 50634 30827 47850 52302 36080 27459 56016 53987 14114 40045 63374 47734 44003 56739 4530 43965 46640 59968 9878 1755 38864 14502 61250 47939 46752 14399 6925 39210 41661 55846 55687 2300 64005 51731 27578 3256 63620 14010 59819 63346 54674 30064 46272 30996 26085 37310 370 7102 3442 46921 38383 42342 60326 57380 23936 57472 15519 23079 3996 11088 15287 51481 3604 968 14477 43224 23290 56315 8364 21940 8184 0 1315468318 +128 50262 57161 56251 53084 43669 51571 23919 38603 19194 39801 18197 38704 11012 39544 34978 19517 34643 23387 26529 4093 52362 19433 36853 59808 4301 63840 33507 40063 54315 63271 61658 43908 22228 57187 38335 37332 2818 34421 20333 38888 26262 48599 46193 45649 37686 12270 55387 43562 9431 62463 43768 17137 8244 33513 34630 43454 33331 44811 41929 4222 22500 12927 53317 40182 14780 60129 51227 36318 54672 57182 4139 37291 58408 58793 23090 50173 36431 21506 31562 62282 900 39666 24132 47922 64312 45097 27748 53982 38072 58919 51858 29684 32961 28795 14136 16407 6446 48849 28526 30559 13644 31181 16713 63072 10801 41404 62050 37285 43685 51538 24540 53146 12800 2430 57509 1976 16329 59244 28043 22905 45183 17681 62127 47456 43432 44658 31334 53555 53535 12075 36370 39191 10932 55658 24616 35446 15166 20145 39530 42498 16996 35245 51766 27025 34101 47978 36379 24389 58525 24015 1692 62409 46895 4282 50970 31541 35864 11516 37289 17453 4831 35836 54086 297 27066 41716 1321 54906 14938 8268 10964 12637 45825 13899 36558 25398 5520 19842 23508 10415 48568 23027 51174 2004 26700 61241 46930 53129 21101 30837 27736 27675 8161 47101 56834 56441 38925 20594 26992 16831 55504 20179 8864 24913 11565 46660 10489 30060 12470 44642 6904 19899 16933 42232 59120 4818 61273 50139 28324 2556 51341 52378 4374 12222 19362 9715 3758 3856 10066 29995 41433 33131 58408 51145 11482 59700 22563 26330 86 31065 47991 63165 20108 61162 22086 53339 3090 61184 20909 29875 34535 14793 30925 27474 30691 35255 0 1326396391 +128 12671 19597 42521 19893 40750 48373 30185 5225 52220 15687 50215 21209 50580 47649 37222 11555 27484 34047 44262 722 41714 53346 20368 40554 35409 19612 43296 46127 59220 57083 4522 24360 2730 36647 49627 11114 33672 42232 20071 34301 14427 14498 12196 46719 4298 16619 13285 25336 27657 60933 55068 24359 42579 15900 23657 13256 34942 55079 40474 53221 60780 12215 62612 19537 31373 40343 7813 33839 27552 54691 63918 52867 43419 22363 47854 24162 13292 746 41193 24702 15730 21715 28332 38181 8002 7921 63922 51531 2849 58199 21702 27820 42595 54640 27867 21770 52058 27915 4078 10833 8863 18382 11252 59258 52929 43967 5126 38244 37609 52793 14375 30503 25044 22212 61708 9994 27245 16192 51281 49784 50139 29612 50335 58480 59632 10323 58194 11265 51438 53865 27976 37600 60472 25068 22765 55539 34457 45823 27912 6413 57068 54753 61895 16711 49915 44167 38383 55725 7762 10949 4170 50964 13896 18492 27261 12296 6230 23204 3045 3164 62864 25288 43413 62105 12204 16205 54518 54433 5246 54948 29687 48517 22516 53372 2167 36781 34688 3798 36887 11497 51860 23719 19298 58170 14653 12078 62110 15806 22539 613 8062 40270 23256 8285 19893 27862 18339 47905 62419 50469 46618 18859 17454 29157 41340 16086 11432 23954 58559 30599 55785 21558 24058 21474 25682 29815 59942 51214 63862 47130 55485 58108 1200 64157 46990 3526 43332 24747 46934 19503 3961 14305 28776 23591 23479 13856 24085 5414 3035 22865 52125 38789 47223 35538 46023 27509 52800 22617 22489 25622 35496 49989 42713 29282 51275 14447 0 1311612873 +128 194 37309 6698 38094 58612 24293 2458 23818 1975 64111 37839 59458 2428 10993 29808 33197 47331 15621 18311 7946 5642 12712 6702 57633 1148 38821 6467 28548 26893 57750 24744 1984 35447 46127 9843 36276 56756 63258 42416 44977 38383 26143 60680 34647 45724 50981 51606 40867 64274 30290 23185 6708 41601 4982 40273 14894 27472 570 14958 61335 28666 63983 10824 15799 42954 18481 39239 4721 10281 13185 63728 36822 47028 20999 59841 44205 45292 48778 6419 43358 58613 41467 57457 49885 9329 20272 44692 52311 43783 37265 39381 40282 58767 63661 24257 64421 63734 16264 5563 7271 14194 6764 43422 45022 29809 57243 12261 53508 12363 21411 60440 62540 33575 59072 7725 61722 43549 37622 17996 12829 45518 18059 33418 57315 29694 12873 41473 5551 19501 3477 56442 34883 42690 16586 39553 6979 61705 31296 59510 51512 5127 44533 9493 47999 37667 10657 34949 45386 11408 28660 7239 63207 3253 45651 56921 53361 59491 12734 63258 10265 36614 46743 43079 21501 22137 18148 62801 11170 62884 23109 37420 5044 5486 52511 55986 45828 8940 23216 34726 7358 38321 3884 45537 54882 26988 51114 26570 57345 64070 18833 44202 24386 46288 22113 19827 47403 44303 16055 12713 33838 62894 53422 58190 33853 35958 28411 36812 26329 21342 35969 14567 36221 47071 5468 54806 26268 26393 54121 23553 2879 40578 39053 21688 56653 2748 9937 26662 32968 38722 20041 46019 53223 49435 24206 12758 28831 39707 52352 15709 40713 47190 58377 7274 24363 20818 48880 12994 55284 15113 30154 40221 40722 46942 18848 58273 14979 0 3476538727 +128 35599 23935 21252 2485 12515 15320 58205 18276 53132 19709 46221 43213 12592 58023 30621 57494 36492 36331 52855 18459 5628 2539 6127 50333 40260 14941 12843 54960 4511 42835 33880 21064 42116 34077 10067 9562 44680 12387 52776 23145 57698 743 12717 10127 906 11296 48459 43761 15854 15948 46268 53068 52939 35759 59703 16087 21377 20667 57485 4660 17521 26561 60267 60138 25119 3975 51434 41358 19818 27834 34529 39278 13354 12731 47957 63194 23824 27498 23651 54845 63589 3498 30265 14594 43996 4105 38460 46036 16713 16961 24848 48763 26655 61418 16754 13571 49681 44706 4547 14862 35448 64235 11854 53087 31605 44844 12703 24417 44846 17207 22610 20478 16590 6917 9647 61538 8681 10679 8953 9535 15584 46663 36344 55583 11466 4366 29816 5973 3098 43683 13557 1469 28977 24243 2375 50426 8239 26260 29060 21156 51899 13130 18138 18865 16623 28847 60542 22987 19106 38995 6313 38744 3690 44385 31072 9998 1669 62862 58352 23381 14165 36084 37225 22929 50585 47401 32772 12830 5170 25278 15939 59776 7204 8536 5596 49369 19313 1696 36871 24513 24102 19997 19682 20434 4535 62154 27961 2994 33839 37602 39538 35234 40532 27404 8616 40793 20858 46918 61855 41815 4050 38981 40923 8571 18451 31514 58489 20456 13422 23217 5352 50989 13371 13356 18370 34244 47315 10796 43150 7016 20675 44013 42189 29589 21363 25075 63017 26069 39568 40584 22691 57907 47610 37166 23749 1892 60171 21790 46614 57901 11433 4545 35078 41839 60480 52763 47597 10124 18482 55643 60828 33054 46852 60578 20951 56991 0 1297085770 +128 63620 18420 41971 45212 18668 62744 18330 47442 16645 22552 53343 2032 38497 57409 3723 13320 63923 19759 42499 35006 13412 59807 2921 55037 30936 19980 50044 40924 39352 54770 25963 36301 14389 9031 29572 2248 49755 36659 12021 49561 29371 29739 57515 57305 733 36757 18776 10159 24441 33932 17792 2151 30911 3753 24830 57852 62685 7202 64338 46163 39216 29007 48212 7639 50165 6553 40566 35388 43328 58290 47820 26390 2790 21410 35377 55641 52705 59701 12442 5364 53872 50766 10323 5389 20751 24699 27007 13673 50208 48753 6146 50167 20062 35672 9292 53133 44735 43963 25787 10788 3725 53089 43145 8784 28955 7416 56557 21883 6854 44269 18654 61037 45484 22871 35637 2369 22967 33157 31662 59936 19441 29780 25477 10110 29519 10585 56467 25856 33111 17694 13095 33315 55095 1092 32862 16444 41211 48009 61088 36365 36602 14127 99 42169 7045 53005 1339 44904 54192 53976 51937 2849 7547 46385 36800 37476 36903 13536 45775 61103 41776 387 14190 36788 30310 33544 23592 6284 15121 35591 41943 41905 2485 35777 17414 16726 11093 4742 26666 62879 6139 54374 64075 45502 55760 17071 21101 21333 38079 47786 35895 34761 17421 3962 61157 22702 43660 52951 45196 44599 26565 37810 1668 30118 28599 3050 32797 24819 15301 22471 2370 22310 62508 7171 37345 48374 59012 59312 54070 1561 14858 330 8323 5745 27898 52387 11549 25012 63655 51622 39790 14251 25181 4323 59455 53705 44817 6373 27514 60044 36333 18036 16787 16908 5298 12027 26722 59721 51125 59271 27134 60437 27965 16030 63012 19528 0 1295996321 +128 60397 57167 377 46083 17765 29576 57769 53946 61640 32948 55204 27308 3760 51781 41482 11745 36087 48707 4970 10708 22301 19290 680 8570 5160 18740 35793 60167 4131 56479 24497 64257 22805 14974 61220 60597 44077 12312 35628 56607 36592 17070 3033 9136 50498 54768 50148 52236 36697 38486 56546 9479 5390 33275 35898 1052 8748 55521 63872 10432 46071 17305 17073 8284 54253 16380 45966 43106 53378 61305 29958 43754 2461 40972 8275 33575 59671 55873 17092 29590 10717 47211 5176 56165 7533 54037 39994 36424 10581 29141 15712 44883 18263 46549 30481 5960 39895 296 30925 58120 1959 37584 25729 25574 55327 46193 31666 24348 20758 24624 33500 6961 45544 36395 23944 49581 36456 11571 63358 50357 16134 19578 20731 33542 28952 19874 54648 41001 38793 63503 33700 22876 16033 6134 62886 44578 51448 34214 42708 46982 46630 5469 27080 27555 39014 61132 4721 10432 18974 42984 42569 44287 56031 3050 22318 54140 18230 36396 28115 29742 5054 45454 37516 55585 5672 47341 21035 56297 20286 46537 2828 284 36373 54768 41054 6373 61053 11279 25096 20262 63491 10606 11057 54793 36679 31409 44199 16851 55184 35361 55574 36347 10741 8202 35600 42417 21759 26967 62122 54854 31487 31417 45596 52091 45414 13053 33089 12530 45807 4030 26923 63529 47067 36916 1994 17602 50637 7894 5058 38093 7847 54772 2640 8065 63377 19354 7384 48391 16793 55643 63430 56285 46370 41272 42791 64196 12312 42567 54043 34842 18409 15273 61667 52950 52503 42120 17400 30674 58878 21464 38930 17879 42902 9635 14115 62330 0 3466374440 +128 8061 3294 64317 1843 3812 602 12690 27855 10375 62093 52129 40647 14811 15419 25628 62603 60382 19026 30549 52611 48237 11315 35049 60056 25508 63965 53615 871 29816 63033 58681 8706 53307 50446 10144 64274 31159 35421 37422 30580 1949 8700 4419 1879 48955 34958 57453 33731 19578 41187 26592 41081 20784 19410 7014 27110 28341 4143 56504 59816 15816 38021 2923 26371 9777 48598 36030 25063 48231 10671 49916 57277 30923 63114 60211 35977 10690 25319 38680 39120 27923 60539 1649 59484 19846 35516 29555 48467 61020 26123 60238 20256 13890 58360 62079 2566 17742 58561 3770 24429 18585 17489 34293 23974 1022 28290 58875 62579 17029 36469 15822 59777 44995 25951 62665 62065 14462 17574 17206 14705 48917 10495 48594 19836 29802 61961 37025 8093 38311 20329 13533 2688 17281 63765 50796 5872 51659 37564 30429 39918 3739 17898 40351 12336 37941 50951 7182 31134 62790 16897 46690 54358 5813 56961 53070 16204 55652 11433 29139 14067 33 50483 12630 6962 62306 40605 37264 58205 55341 40311 62135 29065 53156 22164 13640 3008 42221 29818 28982 40383 47493 19270 55699 49527 26660 19301 28450 7180 24761 25695 60190 4373 38027 21436 4580 49883 46499 22339 46908 50829 23001 35315 16978 7812 2119 21909 46839 18737 21466 36504 47795 41288 12394 24776 2828 30923 3850 9030 8831 9659 61482 20141 45832 11451 50971 47363 31648 46866 22899 70 34030 55737 52584 12322 31004 36046 63224 28525 63172 20743 53771 52938 59576 33034 1551 10252 63002 53664 33600 21611 61205 3513 44943 54708 51475 56597 0 3458834361 +256 28798 20912 36788 44050 3619 39255 27850 9805 52720 58149 12823 32831 63406 50575 26356 18639 37996 47359 35388 37564 11936 45358 40001 6210 29818 45718 27619 34062 20099 11728 62841 4446 64311 16985 1822 62704 14929 23441 5857 62628 57388 39650 31505 44506 61991 19717 45947 56289 33743 21719 1839 16598 52551 52254 45724 45752 60738 8938 54570 39740 41216 30410 29419 39173 51991 27209 13326 4120 40775 49965 40394 59294 50320 4177 21704 45273 62474 12410 48143 49051 42235 31252 32914 55151 13775 9911 9483 50227 41273 56893 20478 20330 29407 7635 40205 11948 45909 28415 45744 28054 38449 8365 52862 26262 23424 16982 29742 39398 5231 19440 11969 12418 14089 3011 58384 56113 9182 31522 59244 14544 38209 28668 51247 35908 26634 15094 55882 43980 1122 24707 50896 17230 46505 16905 55135 54937 8867 49901 29798 5358 45032 2739 50114 41732 38476 34056 2956 42288 49391 5780 16627 40340 12159 25685 38685 8161 48654 62948 25146 9518 18885 31016 26482 53642 6207 10243 25451 11027 7275 48517 44122 1096 5811 30742 26059 44003 36909 64456 27270 18244 11494 13522 24221 58231 41097 41038 10187 50687 22900 17246 25356 39405 43114 59050 29692 33327 9051 62563 16865 48306 36494 44984 1848 25968 25093 1211 10081 47430 63078 3696 63037 48822 59308 26068 27085 41915 10030 48555 52667 28782 18112 49108 46075 60464 30913 41309 6008 22103 22822 20500 56672 23820 28062 12374 13168 20022 59126 21334 58180 41024 41856 47219 16509 14109 23770 22524 40711 52070 48397 4738 26605 23207 55915 55303 28539 5519 41380 15538 6887 49736 43470 14880 39447 25146 10688 10794 37602 22798 55462 63201 43752 36193 54344 43188 46162 52952 49260 24171 13412 39123 3314 20516 51318 48692 46247 42050 30361 52503 10642 19939 18268 8801 55021 46225 10839 33299 9760 601 26957 16892 20972 5037 37642 27573 35746 5048 29554 58060 39296 12840 48129 44089 41329 40728 34808 4594 56926 30934 12547 1230 53912 29341 57537 4592 58482 42515 42261 55359 58808 37602 12942 19795 8318 2230 23234 27400 29077 35313 25660 36740 30409 51720 59828 15189 39128 18399 6652 30602 55468 5807 30535 39559 47274 2388 38398 52293 54981 12802 58510 54338 27910 55143 61672 55614 54009 4898 30393 57902 40199 55767 64125 2568 42533 5934 9671 27268 13334 44962 61033 26236 13000 31482 60970 50165 34161 34728 46036 49838 9010 59889 19877 24288 10993 45285 48259 57893 11627 1869 13111 59880 52515 20473 63702 37134 42844 25599 39847 26974 34744 29775 58009 4713 61504 35803 49328 58326 23013 60973 54073 12033 24133 57177 41308 55411 6829 17822 40333 7542 16751 42794 6622 51346 55162 24085 40878 846 6634 28147 6091 46725 31513 53113 22087 45995 10827 35447 53927 55869 25610 31117 1253 46894 39131 23986 44487 48809 11082 34318 40686 51246 4395 36427 1226 17803 55773 37536 22111 26548 33423 43172 62750 18045 38150 55479 8379 35729 1837 59232 23300 36714 43500 32792 23930 39453 8886 60101 57894 40595 24166 5300 41522 19901 22060 10767 18009 33281 14717 44096 1367 36631 40980 59482 14810 45158 23139 44777 7278 55023 63232 21793 52349 44419 0 1294434465 +256 19534 47245 23705 45849 28702 12163 6848 34028 22796 17963 37227 36330 14184 35749 12910 13997 56749 10486 2535 16229 36698 10102 11284 60047 28013 40099 57668 39996 51786 4958 32828 16245 13540 56611 54784 32968 15953 2248 9996 40110 60679 50673 58436 51437 46968 14462 55743 21268 22412 32844 55998 48434 8426 17375 2795 22053 24139 62201 46819 61994 46269 13496 34205 57504 4735 22744 57020 55408 37801 48492 39286 44076 51380 53275 39593 63326 8135 35977 29753 61092 6669 35408 58673 36498 16647 52361 44455 39868 14466 45082 56611 40323 35088 18883 18082 31730 13728 9556 39495 55198 46017 57450 22478 36945 4723 4127 21727 13698 48895 33714 18240 6757 64004 63400 8814 38500 20650 23134 33667 54124 56401 51945 11097 35113 17218 11474 11191 41810 63739 24700 44911 18612 8625 48033 47747 61192 26389 14099 4768 8683 56835 46611 55379 61747 24971 7433 27240 6757 20979 34683 2130 26129 59414 58878 24672 12120 6710 19321 33549 39262 48615 3643 37865 24935 22964 34194 58089 16668 58250 47617 3377 718 6773 26157 58711 51340 36174 54378 51781 18930 62807 36770 17782 12403 11666 1260 2149 19703 56605 29393 20473 5047 24755 41925 44627 12852 17001 29341 49147 41065 41974 47762 10228 16691 5715 28830 23588 17176 13169 30579 58202 25582 11338 29497 45135 49675 38022 62438 21787 47170 44073 3469 45658 6993 35593 61668 60161 54305 9498 35452 57886 1752 40510 59343 15509 29131 57224 15553 38690 9085 36074 42841 59584 11782 51730 22492 46759 49440 24033 563 58533 2940 60814 17293 55751 50590 30678 129 8627 10394 21512 13268 55442 39418 64064 8904 63898 101 17323 34941 62262 3153 12117 9893 46924 44191 50664 37070 2967 39977 56109 11193 44256 10304 46349 54278 14358 61304 919 52916 58274 60518 28430 22468 18048 50865 61804 3815 59219 48923 40897 24976 25481 28229 34965 38681 41131 39046 3061 59741 28215 60720 46186 32975 8241 63948 8825 34071 4994 22173 18992 33415 63691 54053 64433 12394 4919 5577 27447 30634 52860 25359 44168 31077 1168 37839 41005 21133 46648 16434 56998 44697 47830 2791 14882 16430 37309 1148 59391 58795 25399 7342 5497 39792 64217 26534 27519 62914 26048 49060 18382 27650 61038 35745 57507 39896 15028 40607 30600 42658 6796 3678 24087 35352 53150 33849 54373 34193 13364 64271 47565 37419 13197 34476 27153 18230 37438 21441 21916 21870 62657 51431 6148 6440 34540 20822 47761 35037 685 57217 59994 17471 50569 21046 37977 44342 12007 4656 6324 28539 18312 10085 27889 23753 20588 50411 43613 5530 58887 16470 45042 18260 7801 11627 61586 44438 14277 62542 35237 28199 7823 1407 52004 47142 16584 36156 58594 60698 38201 29615 23641 28518 40506 17642 51608 26342 8770 29148 23963 38608 29388 15256 30641 35750 34713 3682 39711 23517 52964 12201 57296 3877 7399 27921 22391 41731 21124 29213 41731 3503 44444 30315 1441 15343 26346 20770 29566 22532 18372 49100 53507 29218 15705 7293 765 8368 35024 13563 64198 12718 64089 57402 10469 16051 45415 6369 35868 43540 39148 3388 56097 3626 44338 33845 10499 9914 54605 63344 63652 47874 59624 60107 0 3460778552 +256 20259 12856 35825 63786 38908 28759 8468 36651 46881 6759 33705 10879 16010 29114 137 63925 6174 20786 681 11407 61052 55060 10664 63458 59702 16629 42592 40821 56529 29867 670 9911 62440 33320 23170 7205 28555 47628 22431 12148 8808 20613 64311 64288 40421 38596 62735 30841 38662 61396 31534 11772 17529 14822 31318 7461 42252 62340 3005 27778 59019 5816 63392 26700 18894 10700 4072 9880 17163 35327 5968 28182 21149 59030 61963 47815 19042 54981 20510 42735 8400 57590 28829 40783 63643 51095 60238 64391 15099 8980 58008 36024 61965 18911 47943 19324 16010 44138 46970 56584 48336 30650 7265 41519 58575 14012 25937 52027 54095 51364 57670 59985 1034 25507 58155 51313 5582 50380 1982 19489 20139 61215 49502 28862 27139 21098 59564 14718 33542 28216 50465 19883 39231 29907 46537 56816 13539 52739 615 47518 40217 9669 52575 56062 19728 51166 49886 28596 49774 43789 282 60560 14466 45992 11546 52275 38539 59617 47467 62230 19288 26495 398 3947 15899 23686 49257 64012 16917 4443 43271 18430 13345 18207 57538 48554 11865 11940 59623 63194 28075 15145 6319 2840 38696 11648 58249 38595 49112 48930 59760 46019 48276 36652 62350 43369 47495 17478 14415 21428 63808 22888 24030 57057 44690 17186 42037 30257 27992 508 37369 45919 15183 39099 4055 46676 13871 56251 13747 41191 52846 16538 23780 9439 51089 44727 57449 51594 10172 49062 45041 43046 52331 31380 16558 51501 34296 18369 9923 38130 44896 63631 20749 4096 62974 49769 6923 18794 29583 39152 64037 61919 24210 31436 11647 28838 30788 29371 58904 33926 14419 40005 31741 22707 19245 46675 15920 23769 43974 59782 24422 21743 47869 34561 36709 13784 15810 55778 42085 42052 20895 12378 15769 7313 43425 8569 34633 44908 2429 57312 46551 28344 45131 56533 25073 64027 43487 2859 17529 1389 42080 30370 5536 58870 25235 12486 26675 3942 45252 54903 34262 15523 12097 1818 31678 33910 18714 10217 3367 5598 17092 48562 22659 25161 17085 6291 45866 55051 27738 4827 48778 20830 49293 37989 47585 25780 40930 55131 54438 36977 60979 42317 63108 48957 33052 29963 48746 27314 15273 1620 19399 47768 49170 60111 22176 28785 45191 26728 13180 7351 8720 24225 25695 26207 61585 38785 20938 28400 30059 44536 61601 9986 55948 865 16524 10573 9825 55356 33715 28124 37166 11947 58783 24722 38769 60844 48308 46467 60991 39843 12799 49261 35577 44789 25860 38583 28753 13969 48012 49133 40091 28864 57393 56034 31216 35334 27855 24032 40319 22737 5093 42550 7161 57828 16352 50596 39868 42875 54337 62700 49518 23567 4993 62095 29399 43513 57611 23326 5899 55360 2187 16609 3858 8349 1370 27191 36022 14395 36910 27704 64428 22375 45979 64438 29864 33835 52405 20734 37782 3773 43862 60140 51598 13859 48910 34010 41735 13893 47887 44962 36021 34060 17787 26787 2500 57105 42137 21004 7837 40547 56593 15936 39734 10493 29284 33955 35503 27270 30651 28460 28787 47923 38754 24332 30049 33300 6220 1765 26006 49186 51978 3584 26102 45018 17315 48357 24697 43463 19404 16152 64319 8759 7781 23362 53660 10477 48704 7711 56896 48413 53130 21780 0 1326995285 +256 23610 39483 19831 38109 187 34269 24500 25409 38545 59511 14425 13723 5626 17971 46982 16020 22908 26915 52086 29098 37200 456 10076 5102 6338 33983 52361 47755 52584 23624 33675 16863 29620 28377 52044 54958 35174 23474 1310 31124 57854 20242 42153 36481 9832 34181 44449 22276 29782 57941 47494 25271 30067 13325 12338 58959 49232 54893 38297 45758 58482 52510 51393 23765 34605 12268 59304 3490 31643 56352 63972 28499 61431 40219 54968 46873 26741 14796 4859 19999 16136 36114 7783 17459 35502 58965 43412 52931 55828 49670 57721 18959 38801 23173 33662 36530 35087 57329 53113 44709 37302 7875 24151 48733 28962 815 30673 50181 34307 56095 13296 35841 7211 47171 22762 53190 53492 27579 57810 17368 24258 22002 54638 50493 15511 49209 15397 3917 34517 63912 47123 23216 59311 41565 850 8802 8920 50044 9993 24168 44294 52950 12195 51509 43621 5639 5157 8908 56429 20319 51695 9983 37988 56037 26145 18854 6701 6285 48651 30151 29442 50241 3488 39785 59585 7626 38859 13172 27961 47078 19109 34235 24598 47857 59061 31689 59327 2249 19588 30756 6089 46780 53652 13036 48409 18165 55837 19797 51097 11752 58132 54032 54949 0 41687 4925 37074 42485 22704 57113 3973 2441 27795 63219 53041 57991 57764 41917 42367 24762 4324 48339 12172 3613 34224 42234 56119 28880 38988 33315 17834 33655 59908 30079 55446 57769 8364 10067 17475 25282 28134 20868 35503 51988 16761 24538 33777 40376 42212 55859 14177 57420 12114 56635 57968 5852 60023 52412 45228 25385 57448 41692 24059 26264 26037 10400 37416 62212 58451 63003 35747 2586 22782 58838 53903 53721 13159 59591 24283 47422 27215 61793 41233 25653 34788 45432 4382 22203 26581 46270 24470 53527 36779 15107 50668 57318 4420 15197 5727 63658 25619 56586 15816 1583 40709 36582 29825 12007 24382 58047 22586 13502 20714 5672 39330 8374 52390 54976 62107 43184 6980 55369 16833 18143 55272 42604 15810 47975 2306 63827 44270 4852 53936 5085 5105 6821 51700 49130 6575 59654 53198 17267 5123 49261 8386 14248 50224 62614 7399 49147 14164 57447 60001 8221 21170 8796 25817 29638 20029 61444 58023 49646 46072 48629 47200 22606 44199 46246 39686 674 59400 27856 29642 2647 1687 4879 17968 63729 55325 11488 24255 56028 17448 52927 48349 38999 2677 43404 2158 15364 29203 7107 6081 6378 41522 48474 27348 3206 21144 17638 56211 48264 12907 250 1161 42178 8683 63996 7785 49087 10357 54667 40331 12525 15690 35187 24226 6542 51569 19998 47050 21426 8563 54200 62984 59340 33179 54608 1371 49137 39545 55342 17125 57171 19749 6307 6750 30290 38125 48143 63715 45698 59360 3936 29753 1300 8046 2690 62833 22513 3656 62947 61557 61289 39883 54711 11613 37101 18884 49154 11902 43311 17007 20763 36398 4020 50527 51208 14994 24527 31160 37041 10907 63100 31143 48035 48239 25624 38364 45902 44523 55167 2423 21958 34571 38174 31228 25247 22226 4963 16562 23658 17956 45856 5499 59667 49998 11712 45135 8345 49079 374 24064 63417 28120 35336 26759 42379 27105 42882 50066 55455 4392 4210 24216 63879 19707 49881 53734 28253 4575 46034 0 3438271679 +256 28061 40648 51032 26086 41991 54709 36764 12921 57819 8492 22680 48425 9812 29488 32773 9881 5430 60340 38995 57448 34496 24384 713 2734 12402 56877 53389 49334 46525 26895 32978 56616 23432 41075 55820 35486 5064 41427 21232 38035 15265 36235 11656 51548 22901 26569 63060 58027 49311 26228 46484 8424 19721 47049 12516 18238 22624 34257 37192 1467 23049 42125 2285 14614 55498 2085 46267 52086 13435 11806 455 31042 64149 46377 15297 39475 2060 14015 17882 16071 35103 37557 63460 27549 3980 10325 6722 20801 35335 14303 39830 35563 7987 22971 30247 52937 6857 54153 11737 30750 10418 46840 14233 4250 62738 60132 49314 44399 58047 62684 17054 4337 27876 35456 52117 24018 49837 64428 46405 25244 44134 25330 49011 14880 36407 6182 20516 47511 5321 41553 25778 37689 36666 4510 62643 16019 59633 3121 53637 20272 58766 20407 60210 19103 36266 28394 48773 17947 842 57042 4374 29011 11004 41951 49745 12097 41858 30485 17988 3417 4501 2901 14432 8975 56394 8895 18999 33738 21258 34868 60104 17053 56096 50295 5440 17558 59131 7995 26315 48885 54721 256 15346 53868 27152 786 34247 26221 7456 55838 3884 56974 699 57037 41936 22264 56441 4502 54085 46272 53225 45406 11206 56764 39127 27631 5906 53856 56930 63606 63017 40907 41653 52939 12871 49173 5460 36006 45649 10846 31158 58563 8128 55581 41662 17737 64384 45521 9609 8638 34236 59071 13567 48528 1894 48532 15472 37415 17685 14688 30967 51419 14150 48209 60934 25577 63889 31328 56537 60635 61340 2134 62878 54492 56979 42450 5538 57496 27077 37361 44582 36178 20258 35904 29190 25829 11585 1910 44286 57798 20931 33030 25880 18328 4459 11518 53939 61852 39895 27223 41932 57762 1013 45265 38725 16591 10124 48078 45100 17314 16122 21582 2174 3530 49659 41411 30581 9135 8430 9545 1584 57555 58699 51354 50783 42863 38761 293 60624 37406 49064 22320 57020 58737 60917 21468 9232 38451 46923 17335 59299 9626 37153 56403 10981 39596 38151 28052 38857 21515 54146 47171 26915 58056 25660 22007 62449 22820 4665 51974 41578 63701 4971 27742 33304 59634 7529 34796 57285 31734 7954 45203 30783 33764 46589 62038 51241 26516 60614 52671 33461 5268 3110 24263 3671 12494 40566 26650 3170 36907 43504 58020 27745 54822 33995 28165 1113 28737 24244 37156 1250 22978 17244 54903 10432 831 3176 25627 9701 49924 10306 51695 43749 10735 25656 38445 25644 53340 56468 4978 30452 44913 27865 47372 63391 53969 37246 5217 40660 52901 16 54437 60589 28350 30226 25167 3412 36419 8771 48189 18781 15632 25222 56683 4705 38911 58953 16621 3111 21799 7051 59560 6986 38928 22139 62365 46507 13042 20372 14667 30612 61881 26344 13981 47028 37258 7595 61147 35960 49612 58910 28450 25643 41267 21216 10569 25708 20524 36414 48574 21469 24454 40030 22926 14848 6636 55224 27941 43563 8090 60324 37390 57959 54330 28465 49219 29192 18277 63552 64432 37908 58395 18350 34445 39874 57020 56379 2091 1294 47910 63565 6362 56229 15457 31033 15675 17499 40315 32850 9824 54126 4647 35091 6329 45997 44318 1827 54527 18593 59745 21567 42618 0 1311908108 +256 61045 25062 57253 10755 41760 8921 26837 61834 28648 48579 40432 59219 56981 43914 18881 35666 30453 10104 7629 34687 37137 51071 37171 37306 20918 3023 64224 16957 40777 16635 4277 55217 12779 9857 31491 54318 51648 31023 36809 46904 36807 54591 53144 16933 3570 44467 7345 60561 12716 29433 21531 53804 13864 51800 64161 46854 44960 16943 2803 48745 45879 43760 42037 58807 25275 27323 62922 48090 34230 54286 43871 59383 12040 10928 63981 36012 43356 64037 8932 15522 24737 31166 7502 20162 33021 63427 61854 48505 6059 20062 8313 47414 51101 58881 56237 34724 14022 38762 8269 16798 46526 46474 58190 36478 60368 54744 55866 8782 31493 35736 34920 4839 53464 50540 35335 60570 13481 20824 41209 14746 12806 9895 12856 3667 44191 55211 49277 10229 49367 48457 55270 14378 47595 49507 24792 53939 49739 30642 27656 8656 18251 42131 61078 2139 61709 10380 58143 56026 8397 47559 48616 48769 5601 37484 61430 14765 24179 49888 28447 55509 36573 33215 36637 38596 40921 17059 56668 56943 35842 27557 57734 47171 3160 58901 41149 31399 27007 28952 62200 23584 28573 48595 29521 40020 40143 1074 35457 55287 7810 34614 23093 25878 11830 64208 8121 33342 59748 42165 62068 37119 43478 50043 13879 18994 34857 48799 39716 49601 18347 33187 7166 53622 56432 44386 7249 57295 3079 6373 6650 3038 41954 24930 5611 25712 47395 18139 3761 33837 63024 42318 53466 23466 40917 30597 33110 13548 17438 23820 35852 64099 56842 38279 10014 37078 19561 9713 63738 18480 4945 50065 1762 11967 56898 21467 2897 34043 5695 61424 48577 30351 14739 60530 23016 26841 17627 50129 50357 5130 37441 42996 43558 52570 35620 54574 54066 9908 43 27433 50753 21274 35684 45598 20261 8384 45757 44997 8618 45267 23240 22586 298 2311 34957 41476 5965 11429 5991 52370 36553 51413 60475 3709 39183 2800 1543 51983 60691 63105 42255 31709 32920 21996 23832 51561 64353 17847 54466 57502 19171 16279 4678 43928 5891 24773 41952 34415 54420 52435 17251 39479 55106 19262 1749 51629 43089 32975 5159 62882 50063 12985 34878 44349 7838 64116 48774 10856 26623 34534 28928 38326 47510 49199 35739 58676 48117 62853 58853 44060 24268 44938 31658 52297 49357 7935 58745 10925 20215 18147 14658 17998 43473 47515 2267 45954 48610 22733 43682 40187 199 34707 48570 30816 44152 47529 58326 25979 17126 16556 50233 23827 51319 11034 40847 55529 38963 14144 42049 28581 2881 3108 7198 44744 41767 39610 55172 12202 12123 1731 7630 25006 22410 62799 51525 33411 53138 20250 359 28674 15413 15601 62043 31103 34578 36148 59630 62813 35141 6791 60292 1483 13098 39896 54558 51255 58954 1857 37627 7455 24425 17725 42368 47036 54484 52436 31080 23353 53955 35395 22144 60431 23877 1135 17943 14408 56344 24969 23761 54056 64486 58993 817 21429 64411 31536 49736 2757 39817 13807 4128 52148 23273 13218 58748 928 17858 17891 47533 2887 12739 18669 7941 62960 24554 55103 58641 23107 63621 24390 8108 63768 31447 14470 17988 41812 14107 54053 59655 34113 41581 19309 23820 50906 49453 4010 43428 49942 62914 12009 40505 23777 11142 6586 0 3474358475 +256 58479 20795 23890 1179 44582 36197 25301 6044 16238 12167 14801 53487 29941 48078 58373 2833 48558 14238 26305 7283 41336 9521 25368 35657 61157 59352 59777 63483 25348 28936 33487 63308 59089 42619 17110 62605 16581 45304 27996 48976 59322 51662 38957 40455 46677 12171 52924 53024 9019 12579 13997 61066 5411 26586 61739 11998 42163 40006 23293 16344 49702 3010 27646 31678 15497 60893 10827 4701 47961 29297 9939 61373 38905 63106 54528 26789 29382 1243 2511 21500 46037 49888 25409 55023 29348 9671 20775 52529 6516 40377 42511 9668 40928 38291 64316 5715 47217 9309 34442 9029 26886 7859 33776 21749 7778 2574 1253 5079 7566 16251 59940 4688 33306 53319 22281 19403 47113 53404 64290 53021 53777 28966 51889 58630 8505 13169 16529 40171 47484 41780 20661 44031 34635 18297 13066 21547 45827 49901 60935 24448 16876 43550 55865 17667 55069 40503 3357 46525 29128 60596 41093 50977 51559 22829 40701 33147 18635 13701 27692 26475 11931 4739 1947 19341 10540 3003 5451 34195 1441 2483 30615 61997 48277 52985 76 62874 36034 180 1251 35400 11595 6209 18991 44484 52063 34514 39552 38314 9296 56882 6815 62477 14771 20022 58779 63639 42604 49271 29863 61621 18887 40830 19620 63552 17763 52340 12793 1527 29230 39828 33770 21931 30226 3684 45285 20087 23552 47396 39720 16460 56518 7507 43084 63940 15273 23853 12265 43074 19115 63203 40536 31347 39071 21057 44317 14333 55980 54613 57562 40235 41227 1594 7986 39368 14808 12821 40675 47337 45671 48336 29184 1416 60290 63282 46744 23081 27367 115 34365 8996 44328 48759 56063 41568 58245 24150 15906 62049 19936 59299 58878 15509 1220 27941 59957 56017 54267 46807 2450 56593 27216 868 56522 43382 28026 25757 46756 56364 19273 10024 59693 24981 61882 21474 40941 19844 9703 37910 16626 21123 16492 19943 10529 26357 19376 831 61888 13130 53782 58764 25314 50175 44757 44510 48149 36726 48233 35572 50373 52448 38346 18450 3399 56269 24396 57680 63198 62671 37106 8882 48637 7004 34075 38200 23073 62033 731 21707 54412 21070 64345 26413 3021 53728 40616 55541 30992 7062 35518 577 58119 19808 56734 55680 53822 38466 13354 42585 5562 9762 50070 43832 14238 61586 61739 8520 11031 58449 55940 41636 5172 61220 11780 8246 41970 9759 52111 64099 33049 7964 57413 30618 6725 3112 19194 34906 38152 53945 10179 34109 43456 536 17008 22485 42678 17920 35156 2242 52300 39607 5914 24227 20864 57124 59936 59416 33927 23413 50889 4211 16890 50938 60193 50473 20709 16445 8162 54637 51582 39775 20999 53435 7862 5038 11886 46550 36556 43856 462 39401 20519 30930 55727 11702 16843 7662 29591 38853 5240 32856 49061 22294 19625 10561 55376 48350 63381 33438 59683 10867 63702 4345 29987 55895 10787 47185 652 4312 34898 34374 3822 29059 32920 54575 56992 11113 18650 38036 28634 42704 1039 14865 2477 49691 39232 49387 42236 58327 35238 12166 27789 36941 59191 11341 23964 3953 31181 52700 32934 60164 51563 61234 35233 18801 46770 1768 37316 12976 53947 1575 27743 47696 40591 27744 469 40597 1368 30725 43119 60205 61944 34272 0 3469985664 +256 22992 462 17484 27461 58727 63200 29371 14252 21509 10652 46317 47682 60710 25135 40147 35424 52071 58551 10424 17118 31157 17311 57795 40760 12104 11142 47298 46055 16424 16832 47790 28690 49763 54513 50782 43983 38756 34675 1898 18515 5929 56536 60714 47033 17118 51088 8810 52204 46813 39944 57122 29342 58855 35958 5639 20218 41805 62943 60869 2384 54712 1506 33284 51954 29548 34027 25523 49333 60078 59226 27265 6910 61562 800 8333 49879 60406 677 52306 11225 51809 63984 12483 10002 45537 45093 2569 36436 7237 61825 44495 53334 40995 34541 53919 39750 34932 29817 40446 22592 35922 50380 31184 62190 510 13460 18894 3209 22738 62000 22701 9276 34219 17420 3008 58514 8557 63771 31026 37175 47335 20210 56065 6724 34655 26038 50440 1906 6281 45489 35384 63906 47699 54939 39188 60224 50351 22285 45415 24025 36169 19836 29963 34524 41389 36874 62574 3136 59125 49640 53015 18258 60223 59820 20778 23185 63730 36371 26955 28956 26153 6921 47365 44400 46444 6610 63345 25634 56886 9000 19839 12939 41902 14151 36461 29584 4092 4816 674 53546 37278 25307 52717 6531 25947 32885 41359 53777 8796 14279 1777 20756 9015 17503 22358 45977 22775 8679 35005 14941 44370 38436 6114 57720 49674 24578 56263 21491 49460 53638 3730 19055 48271 20822 62505 34034 58900 9118 48532 2493 25384 39571 21925 6164 48366 58782 24435 13769 54674 30527 24516 43946 36989 55993 62378 34125 49150 3068 44526 21682 51407 40513 42420 28031 13500 41592 13354 6584 58956 19409 31447 46409 39910 19099 20381 18096 49259 47391 39823 25989 52144 54720 60302 11547 624 61424 36506 20005 15109 42532 9142 29698 29329 42946 58949 30746 43483 29534 60537 43371 29245 36083 18694 55555 20846 58325 4548 39782 42832 55171 54077 14749 62458 19386 9347 28382 54519 16403 31405 27101 36386 28215 55972 4201 19849 58404 49950 3414 36604 36494 2557 50911 50152 6967 39691 28490 28400 1743 42085 56506 52754 48283 40599 30257 2687 10752 21861 54167 62628 63641 23691 15025 30593 15388 7520 12310 30712 20280 49607 295 57178 25652 26533 19267 16644 8770 51396 37457 6006 43173 57100 57547 10689 15247 28979 1445 23678 24981 31537 31295 629 46087 17374 38611 61818 30165 44108 8238 23858 13517 55642 2599 15334 50896 35370 62886 50183 54833 35501 22893 24980 10700 179 9676 2424 38415 30639 6698 46165 33121 37528 2400 56616 33326 49842 63166 20980 43143 57637 4390 45368 6593 29652 10567 6591 11839 33444 698 33970 45984 42512 44687 27567 17970 26930 52146 55171 23081 50183 55008 11333 39603 12701 47353 56078 28640 16455 17412 39738 19252 16407 42144 56149 57770 57319 20687 26038 16716 28268 15623 14364 60942 23630 35422 14558 23806 8755 21744 63709 7973 29751 51387 2656 5007 17555 23185 53019 3505 2288 38570 33566 786 60497 40215 27311 54608 26792 62391 40914 7346 41671 45164 36863 31608 37093 15945 54440 62196 9324 27348 34233 34077 3825 16075 32965 2580 40499 39405 52493 45977 37420 19072 34317 6319 25163 41849 57329 39918 51995 40623 25334 15428 40682 34145 4964 51594 6100 40950 2564 35766 49834 45649 0 1316256373 +512 19360 38003 8263 51985 40515 64105 61253 26809 27826 3552 53138 38574 49712 45337 37769 26509 8395 3244 59975 20389 10603 42397 41353 40436 12170 27537 57454 61447 403 61914 16860 61810 37484 1705 35880 18182 61191 53076 43747 20833 31212 34216 43268 4435 46231 56032 19972 43421 614 44896 35904 37683 54593 10763 59851 49613 33310 49790 29289 12276 61775 26926 57157 30285 7528 37540 28083 63043 1436 10605 56923 46920 62815 17814 19822 802 52887 14443 37186 58655 36299 47704 31035 49780 41669 35257 59869 28902 13598 42473 29739 18802 47299 36551 38591 59144 10859 7700 39044 18027 2536 24813 6942 5721 26030 8516 64171 19889 18357 28455 9392 3716 8693 35325 19275 51889 30715 46725 20041 18791 49726 58902 15347 50383 36845 30349 46526 1300 7074 37796 6026 62240 28696 49152 48934 9199 14357 39142 42213 44953 33948 26502 40972 25165 95 45877 10542 33425 37040 33371 60550 5714 42038 35274 52123 28260 48047 16529 20321 26273 17632 62574 39671 48818 20513 27613 39143 36287 1448 41053 44050 22583 12259 23173 53532 63853 15777 24121 48828 29543 10945 34886 49654 41883 7797 10407 16127 37038 3206 15863 1492 52542 57876 51742 43789 51635 28401 51926 32906 60086 42910 55753 2847 46881 57804 64422 48712 37450 64394 19636 60638 57581 46275 34888 48450 6373 37194 11674 63075 40709 27214 39476 58996 54439 5349 15879 42790 22735 45970 19152 45456 11342 47943 47767 63148 59263 48566 3589 7527 11803 61297 4396 25949 59811 17190 34199 10524 47726 42075 56501 6762 36843 53703 28157 6190 27352 3903 4214 60000 47582 6160 6550 44126 26734 55490 63811 7225 16412 23251 45773 61310 46980 37386 12413 9749 34254 7154 29068 229 8504 60089 9207 56827 40464 22119 17460 39599 56222 1218 47961 28222 34857 19523 52953 27306 3196 27644 13740 57970 31231 8673 7709 35579 31370 22823 1688 11604 17186 5393 7978 19707 20973 36015 34504 21167 9839 54000 29330 15004 19069 15717 53048 38884 38850 20703 26922 28220 40811 63559 34741 47398 56500 35921 6359 38427 16710 56571 62120 12853 16780 53368 37282 42516 42794 56945 34923 47466 18753 56252 36203 7895 29291 40205 45860 54874 63079 24620 27525 32833 27774 34881 35371 48184 58329 34698 61223 45590 58175 51883 58750 15353 62706 12339 53331 4453 42917 39219 57267 52190 3975 39681 58995 56056 55410 11853 13573 55147 18385 26652 1468 35275 9935 19325 44541 50714 48742 8032 27355 21391 39361 57672 62699 10440 48289 14127 41407 59388 27914 61015 40628 50246 51582 49953 17767 57638 62492 14398 18676 38762 51119 15452 50066 23726 42218 38662 58376 61227 56929 55212 32858 57841 5891 55980 25600 57573 42554 4051 59595 61060 60348 28098 3339 38626 11304 51523 16224 19403 46305 57058 29838 14570 46983 10180 40751 45714 38563 15635 35408 55201 61343 23766 15086 13753 23074 21873 57425 1618 11059 25938 30550 22161 18486 20953 44209 49374 50482 50668 63468 10251 23088 37717 35774 60641 6364 34636 49284 2948 11293 7106 3621 7631 8230 57140 7256 1986 41481 58471 7671 31258 8788 20196 34372 30889 52299 12767 47286 49 31494 18391 19280 43136 25222 25260 40403 61694 41615 15290 21101 24741 51709 56488 56149 5422 61949 27661 240 50505 17475 27300 4209 12265 28753 22695 36782 46552 9121 42285 35281 36991 57427 47139 27219 53096 18724 1432 48643 57768 40452 22747 38950 33467 36514 26743 55330 33028 20978 15005 29481 22309 47829 50247 43436 41060 55244 10433 46379 24703 30803 44592 56170 31428 18360 28166 15195 7227 63327 8620 45755 27843 41268 39859 29939 738 1193 20492 62292 15188 5404 51712 25903 46674 25348 3027 37531 59205 17810 17734 33456 41115 61982 34719 38825 17457 39667 50826 63553 41545 19233 62482 45748 30862 25472 48467 60625 55964 60733 24634 45435 36651 19740 33462 23196 48335 59564 18649 23660 25440 53937 35304 31365 62366 26331 20759 6523 58985 60464 56952 34625 44664 17558 8292 22696 11859 14827 3615 21052 52858 34496 31668 8423 23809 19524 37798 7199 62034 45619 21587 51337 5687 36320 14573 27468 47891 7857 14046 57632 64226 39398 27367 59602 46887 58393 18832 10411 49828 22784 31563 55707 11513 64192 1255 59240 50652 25235 47766 54674 23040 32938 13904 16676 18296 2634 53875 61409 59117 46041 62901 39031 60060 55868 28344 5724 50284 39292 33655 60147 57534 24802 18845 60317 25695 58909 61295 25870 2541 44063 30225 48087 43003 351 45355 408 44681 3628 23254 52983 29435 11326 20330 30032 38614 58072 38237 25100 33683 50309 36959 35135 48681 33729 16469 61092 16197 38746 4145 51012 36738 51608 40528 56604 5638 36315 55769 11684 15628 61257 44171 43135 38701 60734 41800 21690 34355 3325 59710 51651 15364 14110 13896 60228 19762 44582 51467 38814 1533 11587 47414 27586 54728 27172 28901 39510 44799 19604 9046 51288 64069 35768 4770 62109 48290 24244 50314 6887 8471 31246 23344 6352 55743 8660 39334 47934 2380 24402 57194 35821 9129 16481 54989 31233 15687 59361 28843 25366 19248 59161 40280 52611 3848 42170 41398 52559 2650 39685 29053 28328 40420 53911 33246 3219 6806 20083 10217 2326 57432 40032 62004 37677 39809 1744 4949 36541 38826 16620 4679 15893 29066 58408 57415 623 44688 8019 39858 41216 50199 55951 9853 2046 59493 30358 22665 22955 56441 28711 35918 7602 59247 2930 32976 33102 20423 51993 59969 36097 4982 15270 42240 38035 63607 6996 43285 31496 61624 10932 35696 38421 5392 3238 40431 30585 20307 16710 19946 512 26648 46385 49908 40439 6248 14126 9568 43040 46387 47182 2625 57795 62511 32871 12987 19781 10359 182 63356 61451 21343 63786 18210 29654 20935 34117 5899 61498 43230 29172 4859 35231 48127 19323 21326 51474 54227 54822 23458 413 54880 52697 54470 37097 6597 1273 58790 58550 665 23895 45773 7412 45952 8505 17008 43779 47810 58233 27606 9479 45882 3867 38178 7837 28341 15322 866 30046 57467 8342 8897 21393 39074 46630 1141 35116 18233 19720 64126 31626 51749 46877 45952 60214 55252 54894 33539 53250 13251 1460 10121 57030 8564 22608 45761 4367 16554 12690 12890 7933 51699 22146 13922 26899 20877 50679 18636 4753 29384 217 47525 2619 7397 19729 51592 16450 20267 1659 60884 35083 18511 6070 7060 38875 35727 60460 1152 31117 43075 57842 0 3450743190 +512 18114 13574 33732 51768 34773 2244 21866 10623 10314 10707 50900 35465 62502 35791 47437 8472 19261 38566 61117 35646 35483 21745 55934 5447 62968 41627 55011 1483 53216 43884 42112 21676 22082 26389 49240 33344 21253 42533 41054 59332 63196 30741 14613 58394 37406 12202 34786 10189 31580 2925 63726 46346 11988 21220 39618 7903 6789 38147 60592 20216 43495 22367 51380 31114 4613 44271 12118 10800 36685 14343 21959 59502 42631 52487 48530 37640 64377 30243 460 58250 13595 3833 24290 20774 25333 40457 61858 4365 55780 46615 52874 41372 10676 50008 25312 25016 16779 42954 55913 28614 47358 56825 33946 22862 22596 62516 16271 49135 54983 35854 54989 36789 16566 33887 58255 60065 42855 3271 20978 30907 51204 14135 21743 54417 58455 2135 37820 61891 8242 34760 6669 35824 39328 48841 25256 22295 16417 50661 21178 39547 28004 60642 37210 9060 19548 19838 40882 44143 52143 57392 20191 4035 16854 53325 23316 45865 33910 18105 51711 38035 13076 43615 52077 58493 12008 2115 28981 38187 61432 15288 1322 58393 37196 20627 18746 8724 46232 28131 12092 3307 14428 28843 29665 24675 7414 22230 23402 36471 20640 12953 42379 23831 37489 39547 52902 57161 2065 14712 36134 5558 25584 6710 63818 5370 5244 61980 37903 52804 15274 2189 50526 46417 42291 54206 41302 19995 813 26635 26837 25684 37341 12036 21203 56038 33302 16882 25091 27917 8698 49186 11385 21479 36380 41880 12891 1686 9017 52621 60278 6569 43048 34306 27507 24042 64267 63856 7406 60153 53568 4543 27011 27721 24124 61445 64160 5588 9468 5048 9672 46962 47761 53194 23873 31443 55344 19347 3157 48345 36542 42788 16895 51852 13384 48448 51221 55326 20543 2685 40637 50128 45571 46233 36357 52558 42214 28168 43008 33719 17477 23076 49109 54254 5111 35747 60216 61406 57029 15893 46387 51362 39798 10311 27116 44974 18478 24043 14222 13948 56229 38005 18836 29237 27495 64400 60493 46057 29172 53992 9329 34571 38627 42858 37263 59910 63570 13851 23436 57907 62784 1003 59340 26646 60065 35275 44608 7636 37154 29692 62674 16680 28431 49769 49842 43723 41037 51205 22458 45496 57948 21075 2625 17443 19672 47239 26578 43016 35194 44543 63780 997 5003 7638 63046 10028 20529 21908 6804 47945 46363 47761 40352 63675 55833 24438 39749 38570 1678 33756 14687 38522 29844 8212 5400 33916 49758 3662 38969 34225 14652 59197 16641 26424 48861 52918 5811 53475 57192 7769 62667 32895 5261 41293 22762 36449 53141 11150 38193 29181 21346 29529 57547 9027 2978 51906 45532 8971 31740 42320 30463 20366 9360 52402 37863 59272 10727 64224 10597 34075 54452 30032 25395 41336 50077 45524 60483 45915 61151 56236 5288 24677 22935 12885 16396 55549 16723 43779 46527 19370 59663 41177 14387 8587 33055 22192 7160 37937 46757 7627 10159 45770 19053 48687 38018 4933 10176 24149 35488 49571 4139 6028 2007 41122 38272 17589 14652 42283 53577 1908 60330 27471 62717 41481 58821 22492 46021 64023 24237 43139 26064 53714 23504 46211 16731 45634 33983 29249 9187 26212 57366 31368 59552 7003 48176 41724 46617 10670 14159 5000 19865 11973 27853 52715 38468 62698 44943 14194 7511 18998 48444 3995 5602 2945 20880 64299 11174 35437 62783 25207 35631 64033 57880 58169 31168 42153 10102 50663 13629 11880 35532 12941 11309 38843 21869 38471 15595 30613 41372 48382 18753 60866 62443 30794 47775 39946 55034 28649 8831 11388 55511 36243 26080 64144 6675 42422 43507 34966 48802 19810 51096 46840 57859 20700 26347 18118 25336 45870 30070 22784 45807 36652 55726 11025 14856 51781 47193 39324 62185 29632 54509 14889 8314 13407 2671 62700 22577 56042 48118 55462 36232 52578 2875 19930 25120 33936 51427 5012 3672 10170 53915 52780 52944 2280 38443 57814 53587 5140 53996 17950 29923 11844 20415 42123 44514 41719 40165 60556 16069 48622 44369 54290 30958 28202 55625 35880 12854 46312 62484 28450 13139 50141 13075 63576 52152 30758 19269 2487 34454 17148 45839 63975 30521 38483 56310 4334 57295 16774 56088 4693 35653 63645 10347 27841 16062 41092 704 33 33155 11469 60899 30316 48619 41942 36467 26449 2411 5590 35903 18580 11550 43101 27264 15644 12291 9948 39911 30719 49307 61866 11481 1187 43984 39740 16468 23967 28352 24971 56911 35574 28965 8904 34368 45370 43315 13110 13604 19481 15781 11602 62129 45558 41356 58178 6041 28640 49000 11367 33356 57349 54260 32826 39770 5862 36953 2302 17409 51461 63470 19303 15156 8304 56766 29773 684 6683 21277 25211 52932 61921 28886 843 14094 5362 7312 23483 1801 35598 17948 33417 36205 16954 33973 14331 22796 13921 38141 36712 18794 39322 56144 21474 42622 18137 43400 15732 58411 58132 25336 56054 1326 13322 59601 36129 20674 54848 60708 54127 53062 3519 7142 14922 1086 874 38785 8771 41662 13458 37463 93 8056 18739 63007 41241 54649 56332 20791 28592 44000 38666 2296 63966 7817 11209 9862 40582 25767 10870 49081 55293 14618 48130 35220 22571 21147 35678 23676 49644 31338 18099 21711 4513 63916 20415 3164 57969 32834 17727 47888 23834 24674 578 37891 13133 6445 29906 39735 51840 61657 3656 40869 28137 9913 26573 24323 63172 28016 5968 9921 57771 491 1261 1570 54357 2335 59319 60409 50083 59333 60725 9923 36241 10641 53457 22749 3905 40029 9810 9424 47147 15488 11882 11112 27763 24160 36230 27328 45228 43787 60964 46022 51993 1637 5123 6369 360 26562 11721 2871 61539 36140 30401 14786 51860 61168 37449 29340 36499 25338 52100 3606 9221 19561 26558 62189 27624 25971 54808 26341 2142 61530 30964 48739 33645 30026 40698 51967 28158 60667 27313 14371 6623 34122 60854 448 37147 46611 24883 50510 14969 16510 1692 25572 21367 39237 59213 18988 55786 23918 2919 25030 40186 57893 13787 29565 47968 62295 30228 4593 64125 33888 49440 25032 53593 8046 61102 26061 51338 2764 8198 44407 9326 26512 55884 6502 16622 34640 54156 14669 49272 30471 23509 58274 9728 3819 49207 18723 54485 48328 51688 27505 37050 36349 18474 60760 16906 1290 8669 18524 43202 22563 42693 24583 60337 3989 960 19138 54769 26287 12498 46238 36712 9193 54205 3785 57997 4090 46622 43728 12261 36283 36099 2694 13191 8880 54042 38154 51391 13696 8 8582 55035 16382 45068 12197 39226 0 1304994180 +512 18418 20108 6534 42249 8478 52830 16480 2210 26131 1083 50187 24273 8888 35459 11512 49999 26973 29004 21679 15533 25224 3670 25955 9733 15676 11656 24880 50714 52324 21673 8658 19250 17399 7397 44700 12182 27109 24158 20258 38029 42017 26648 12602 7243 14863 56081 7636 48670 4830 19372 12017 1564 6516 24182 9304 42696 54523 34136 14831 51692 58255 14938 38156 57722 17722 25025 14263 27862 18382 58252 19387 22373 10223 50367 44411 45439 13282 39689 56443 33364 52206 16509 25085 8759 21866 39573 8452 50616 63053 57483 64401 29419 16545 5208 50979 40012 21812 35559 45910 54959 4129 15837 62589 7496 22235 5510 36671 30896 40830 11797 53207 9659 1618 46071 20130 5384 42777 21106 43168 62037 63387 42610 33062 20584 35880 30415 37973 59637 56755 148 49612 46301 17752 11247 41676 40611 59128 35768 58935 23483 40141 36379 18834 20127 16727 28803 59770 33804 28491 2711 38797 16807 21333 20327 42815 27220 23734 45603 27579 27852 63661 43693 28857 41181 26542 30115 15931 30751 13265 20531 47726 24985 39590 36869 7709 17847 31698 15041 34506 31130 16711 10102 8015 46721 4344 19329 45616 28794 37904 13179 52315 40261 19667 56363 59696 14346 50041 3609 28959 2210 1272 54966 17675 34574 51056 6811 39496 62767 8383 12224 8951 1218 4405 11787 32861 14106 41517 18974 1480 56565 15554 54868 33424 45830 4148 15365 8259 43303 57137 29763 6187 17383 22715 20768 919 41522 18599 49818 60302 2974 57889 2113 38529 16926 42559 50805 21964 64133 19404 47108 1551 39065 17970 12191 23017 22409 4173 55268 7 24147 9042 51995 2961 28965 42987 734 54096 52716 55673 6597 44840 16100 25103 11912 20069 60629 39169 63684 51794 20654 4322 8845 18533 52120 57937 7958 39949 28581 35402 44770 7517 24078 34713 4798 60097 53423 37825 49016 47809 20418 20383 33767 44210 21144 11170 62347 3275 6677 4418 62417 42389 35158 6532 50917 45543 53552 38739 37 39624 38481 37436 46401 48443 50448 53747 23123 17126 29192 22587 31280 36235 2845 48771 44684 25106 27197 29328 45966 17728 60749 30040 59844 43264 14597 60724 40847 46490 27200 58474 57669 62852 61435 57257 60302 5450 14289 8505 29428 26646 58981 350 38080 14503 8488 2439 27091 39969 15853 16687 712 35570 7459 41336 51323 8541 49011 39842 26811 31272 64133 8095 48746 55579 49139 9472 51652 23651 49087 52422 27534 33473 13043 47266 3614 45026 36107 12147 5545 41424 45522 11562 41077 16600 24061 50432 54185 11361 59635 58821 59435 18119 48931 36258 48897 1765 49979 24120 50203 19205 2843 7317 40204 8556 12590 43590 33131 10848 48774 39484 13798 22798 2164 51507 10552 33138 46510 47259 2594 38387 15001 13229 43227 14682 63971 6651 37893 14336 12788 9236 60055 7851 32885 22672 56518 29993 12110 47832 15598 34938 16730 27547 57886 59412 12491 47207 15232 5700 40161 37814 1959 38518 60920 38782 40640 38592 52647 18502 59363 22034 17063 14620 29314 28990 62718 59192 48561 40245 24238 27553 2188 30292 18428 47527 9611 1834 2580 37084 58561 27568 18913 52190 25407 8943 56768 55448 55559 21131 49283 22384 4421 1957 4940 57139 16392 24954 38231 52869 27291 28671 64420 3121 34854 3437 36174 58597 47615 5810 41013 8642 1794 13064 52942 464 27614 60496 52997 35287 46590 56040 14342 39126 61467 14833 57956 16183 40004 6989 8008 63472 13436 42584 1710 59062 20165 24187 37151 36997 60768 46748 60328 35997 22667 52640 11244 3045 9261 15727 28261 11955 21319 36333 59287 56416 20602 63460 29117 48895 12146 16998 35920 2151 27893 22135 23275 25699 57879 38474 34321 12514 23818 50860 52021 50015 22872 28657 60897 57169 54932 36503 35507 9805 38522 22426 5433 1395 53921 31066 17195 50914 55112 30528 23130 34766 41099 30463 50559 11650 17716 40207 54818 35466 48945 59417 34214 13000 34207 17687 62392 36593 64052 55210 48694 39087 26183 51251 5879 56397 6455 61112 28477 13442 1738 34801 14297 58926 36131 23314 37482 45975 1762 54338 57218 27624 61102 52861 15545 51241 22629 38760 699 21582 59119 38930 11725 17058 33663 26567 16645 29696 19103 4620 12711 6925 38226 21683 4739 56414 43843 33814 12094 6174 5674 2853 35901 9032 54949 31542 13101 55491 39486 1552 3468 33459 40372 15805 1154 214 59743 27406 51595 33669 12340 18080 63871 37840 16870 58312 51769 45963 1768 57044 9091 1201 60068 11429 63511 61279 42265 47429 61884 7856 43196 52855 27926 13565 20256 35313 26129 12941 30154 15242 36613 36835 30680 31312 58439 61486 23517 6808 7614 47031 3648 43619 16631 44623 58020 47959 64185 26291 24435 44997 11288 11060 27229 36577 34495 45136 1996 30603 38527 31078 16202 39007 24635 6243 394 22721 8591 22031 37871 45814 46045 40255 49282 25106 64188 59044 5717 38619 56512 51615 48770 28894 13023 1360 25152 16357 45147 3105 19812 8978 53516 27412 59529 52001 19049 2133 38970 49968 35254 9194 56026 35613 43676 61026 52042 50817 4029 513 8742 3365 42855 40812 35339 8150 45736 33314 5798 51728 3017 50698 25927 13869 7236 16962 40891 49117 27965 4603 64469 5022 61658 56881 5652 58672 19893 4190 18751 59557 45032 21709 35783 28834 34620 15096 35673 31211 40331 12832 60133 42248 55855 34719 13386 48677 27127 36233 3396 38300 63406 9058 55465 2343 51123 60328 30508 38220 55380 24457 29908 53723 49840 15998 59494 35680 3343 17058 57610 18531 35507 24317 25091 46293 13172 13640 45711 49979 14220 1270 49468 15518 49402 11129 3715 22808 13913 18360 30040 3655 46097 63357 43533 15292 22511 4981 3551 46962 23889 17583 2560 48080 41452 47879 25016 54574 51836 7380 10886 28110 63398 25048 44063 25795 18605 42943 49172 38531 45872 62623 36455 26989 5096 56244 46726 54291 60610 1385 46051 45070 6114 48432 40284 55637 21488 20373 22217 25848 52738 13194 15861 6676 49218 5497 53729 37064 13991 20661 45204 18576 44848 19886 2866 28639 64141 16770 5064 28606 42681 2409 13360 57606 25379 22985 33849 49738 1200 14845 9625 32801 13382 21992 47194 41835 47087 3671 5977 62170 10530 39683 7271 48727 34382 866 18431 60967 36721 5190 13792 6386 43285 52918 3025 21342 38546 46659 38055 295 5878 822 61912 1229 31327 60040 50211 44708 22188 30046 52647 5801 33207 29327 54896 62704 54743 0 3459210302 +512 11181 14206 45635 36441 24727 62861 27542 10170 34452 19694 58325 11603 24194 60485 28318 36119 40909 1644 26130 41771 29313 30736 389 56537 54110 54965 27438 4508 42621 4774 35508 11201 50456 24856 46237 10978 44068 4212 6664 40592 62483 16215 57699 50296 13210 9664 56394 47358 32998 40958 3998 21675 47822 37548 26128 59985 4277 17150 36231 6006 20096 44922 8751 6952 31416 5000 21475 25023 23786 40446 868 33299 39579 17686 17463 9703 20214 25841 969 25637 5416 33805 37602 23690 50622 51273 8591 29706 58507 52016 50406 9282 43804 57570 4735 30543 6886 28161 52697 12431 45345 44769 34312 119 55016 61425 46119 46734 21268 17736 32833 16995 39844 5819 9524 36998 38485 16450 30044 51497 581 30267 23146 26962 25546 35899 11798 53333 21534 28857 17329 57120 20873 38661 56938 12356 45242 21967 6007 55583 19664 14397 33076 17068 44325 17978 34284 46145 20604 9231 15569 43427 56507 42133 14493 1444 45171 285 26797 3616 4736 54733 50517 46419 52990 10467 27453 46038 19516 21953 60972 31735 35287 35095 21376 56843 15012 8035 61459 62661 28832 18343 33334 35611 42322 17956 54365 21497 1957 25926 27681 54460 50012 7932 29885 47495 56091 23150 12652 12673 44531 57619 23067 50745 55660 4909 63973 58393 20552 21915 12150 27440 1271 16948 34725 45492 21109 891 4869 43451 3038 1574 8953 27929 18544 24473 17140 37028 9215 44206 54092 38116 5588 487 35844 8233 62446 33828 39274 21255 28223 48993 36603 61213 26344 9493 28462 38019 33514 551 25663 4538 38395 37701 39587 2960 21919 24915 21149 61550 44481 9013 26325 57561 17019 53457 7966 18809 2539 5595 8457 33238 38491 7763 5304 51257 3492 4279 57662 63571 17749 31387 9100 11484 58759 46859 33800 32948 44348 63142 37484 46055 7274 46982 59398 59086 1355 35257 10837 8221 16709 36529 48069 61828 12564 54421 13875 26046 1363 1899 58420 6320 51030 53369 54605 21827 62776 61258 3718 6950 29129 30461 50166 9763 47008 28608 791 2660 50895 22853 27351 41500 47877 12025 26846 51060 4907 14210 22068 53721 35080 17298 22389 12850 10266 52257 36669 52168 9608 17864 9336 54813 34018 2966 40109 25261 38101 58687 7426 35296 10939 5026 22382 24733 40326 6969 8843 57134 55956 10466 41622 18697 25554 16533 9046 44584 30634 63667 25081 47171 29017 1464 36699 5653 9617 45737 63295 46078 48633 29900 36984 44148 60798 18335 1663 18473 47679 4610 49712 60531 16604 57758 40610 15124 12286 23619 35424 38068 29536 42090 12049 54565 35698 64467 6873 20198 19230 35496 51033 55558 38146 48452 6573 23606 14931 7153 48188 24222 47409 15335 37202 36495 45964 7233 63816 36879 35307 396 28154 40863 25068 42366 54686 44671 50538 18690 51425 21999 38132 22701 6484 45097 19450 21445 49510 29341 22186 62076 58182 51373 9852 38867 55809 6379 8642 20525 55541 50423 42274 35819 24282 11663 18615 22321 50429 25260 43305 21779 41856 19028 15428 6172 29909 25524 45608 9236 59388 49666 60300 57679 30301 49660 33951 50914 5107 60940 43123 24966 2970 42994 30616 28923 63287 58444 63399 31395 58355 18640 59570 16079 41341 5727 50140 55410 42590 40177 23174 22511 64385 61086 54234 63418 28526 27689 53099 12095 27807 61807 60739 15389 7498 16110 14534 5999 4609 21354 36320 39107 17967 22435 2588 9501 33287 58502 5985 30474 27977 38151 5600 2664 27118 12179 3069 23629 325 55985 16339 4882 36275 7576 41347 49984 52914 48711 41142 41912 5247 26181 63276 39174 58500 12941 36933 56336 28723 63200 18938 24842 14976 28139 34626 26159 6199 52046 22835 21977 19219 17366 48039 11726 9911 53373 1888 58768 23 41456 40232 64290 58478 52024 35626 50883 5612 4623 22078 28666 20804 58902 28608 23259 16461 19258 41840 42791 47952 38953 11610 27407 23595 30897 13455 3933 38603 59284 2239 63790 33116 26835 40343 45322 62792 12115 55990 34994 10465 41426 9461 2138 62352 28406 63192 25046 20959 16254 54148 60975 30913 32807 11593 22156 37630 20470 58570 11363 42721 61407 41259 59921 52552 25795 63748 540 31309 7498 11668 5184 39651 44553 46012 42991 6928 17648 13058 2199 28777 28946 54962 23378 54952 47302 34415 29377 23734 59374 42892 6240 47538 46955 23292 26567 45503 33387 4582 57952 26847 41465 10883 19649 45098 34033 30133 14062 40302 57727 6143 5368 29147 22036 60925 52796 38323 9201 13226 11145 39199 14151 45327 3904 12487 28146 4443 19857 52704 41133 16189 1889 6336 15624 48172 12157 56820 61492 39130 33054 38990 57575 32972 20005 34519 4838 61523 14842 40148 60785 35584 55407 21996 43792 19068 19604 14264 17674 40701 11399 28319 17613 16378 24760 20372 11711 3051 12076 32812 1483 8425 35583 35437 61694 3335 1982 48384 22085 54623 41317 41384 44394 34293 45120 63789 62266 49113 6061 43179 49774 5486 11431 27545 55409 41790 27145 10544 37976 40132 33655 27814 36421 2286 38451 12108 17561 4438 33847 10980 57339 55362 51349 21204 63176 2941 13443 57905 14071 35826 20410 42585 43245 51047 53983 63073 24223 12666 49457 27826 44953 62282 2776 59745 11757 34787 41817 47001 52672 22211 41028 10063 1882 31243 36394 23311 39100 31054 23463 43818 37343 39615 12671 49252 43036 42652 50962 48030 36085 44185 20567 44214 17743 53997 28374 63398 34339 11144 37579 31438 17198 43644 53974 5950 5549 1904 40274 21241 56360 59020 53771 39832 6950 54599 53432 24213 23842 21808 15233 64295 38644 42041 6418 48284 2453 58970 59198 58083 36211 64464 46659 16464 39021 52406 19634 1453 18682 41387 47332 51165 56305 29008 810 61821 31125 22259 51698 50343 45766 23457 20861 23021 2034 26235 6342 14392 10675 6000 40931 54309 51361 12907 40674 47060 36441 45419 13249 26473 39480 20392 43618 41213 7202 39603 4288 48495 63714 35168 7576 7953 15391 27719 55904 57677 27993 21315 30613 39841 1366 14363 56405 16850 46005 24082 42622 50095 17261 21428 57705 18221 26842 58019 16973 14653 57912 57377 45681 63367 26663 11221 60194 21852 51288 1275 6526 56555 37495 37216 50875 54263 60902 12760 32995 45023 36620 29326 33625 50251 21249 27680 8125 41712 15037 25670 39730 38204 8750 18273 62058 2056 62997 20678 60088 47578 8050 954 61292 38346 524 24084 9530 42569 61168 44414 38465 2487 4542 8953 37066 24533 34533 0 3466415338 +512 18837 9527 61180 22340 35060 41508 24096 38122 62502 30923 64040 39536 60505 35955 63744 34778 62956 30992 33061 16153 19006 15739 59280 8757 22302 48560 57832 63936 6188 44178 25355 50468 7781 60637 19387 42555 64110 11721 30967 62443 56782 46637 16915 36536 62959 59291 62123 62668 10971 53958 911 1952 28624 41525 1116 56505 14561 22172 59192 16527 41840 5492 23739 56238 25863 51804 21951 34187 52256 1921 22923 36427 8339 33767 34275 3307 20538 33896 48562 20801 47636 17797 10133 17793 14331 13019 41507 30569 44419 50524 47798 15344 101 61662 25116 13806 22964 17329 33844 62331 33541 40177 5633 2103 30640 37152 53275 13259 25699 60330 27226 40522 2450 26925 40741 8080 34791 8291 46443 11436 57524 16875 41523 21499 7510 7603 11172 18687 54572 57735 14346 24329 15347 20964 60963 60771 6572 3380 33760 40168 35427 59729 54655 49265 38330 36767 47697 1860 55755 19425 3818 16320 16899 61747 57859 1221 29547 51387 13691 33705 25512 60486 50774 8992 58311 16733 45797 44054 27780 10563 18314 57591 54042 26980 37234 975 24761 54424 16312 49408 26948 18323 53404 42929 47591 25248 51483 6085 26463 36673 51201 24441 26260 24297 21480 2985 22432 57940 44282 3113 47304 8469 42490 20753 36175 36504 41003 8123 5761 62221 46616 4256 2807 43316 27133 21982 37319 33141 3257 18689 27433 48945 61578 44685 53892 1766 1123 60528 51294 60025 22806 49479 42027 58741 6421 30685 40514 63546 8690 45543 5882 53922 20691 63835 30383 12716 56959 38393 63543 48027 29544 13617 35073 44108 43283 21570 37709 52889 48453 3691 12332 19273 29310 17151 7835 44220 28179 43027 36182 47342 13353 34493 25041 15044 21633 58906 63478 51542 54235 7585 9515 31395 14004 39186 64411 60901 6783 29250 26465 15662 26124 50607 16924 41402 38098 28366 3326 21061 41541 57108 10114 38565 24977 20075 29720 33507 39464 38099 6792 19307 7357 31066 26431 40209 36686 54553 60608 14241 29339 36982 48108 56789 27220 62870 26597 41251 44056 10117 486 49507 13439 60377 42523 36527 1707 55208 63670 30223 55703 29621 36655 45993 51747 2116 57622 56204 45204 10465 43723 58878 26669 23169 48209 38780 48888 309 44449 30289 44663 11159 26270 53041 37493 3089 35744 2465 43781 12015 55969 10219 35467 42273 10872 64031 24653 56192 22480 62116 7175 9333 56085 55310 17123 5760 49200 15126 19061 9815 38859 46255 22441 1248 37122 34139 15820 10138 10388 35810 8405 5057 17178 26925 27529 51151 7519 50531 7866 40075 45995 9751 22917 1447 56576 49287 1399 319 12965 27086 59243 3394 57572 17779 53842 55265 30809 23213 40509 27569 21080 18336 2338 37764 31570 8882 26628 46968 47580 19992 51494 15440 54979 16801 8898 31295 18991 58124 36728 4092 59788 34223 53491 37328 34829 60250 36366 17548 11875 3819 20501 54544 36517 18080 60050 20528 59192 43381 34009 56422 31471 41263 53490 59684 29075 29656 60159 34628 33258 4972 35020 4286 23429 42885 20657 52105 54175 31247 27776 51251 42525 14387 61083 44428 54266 21889 57306 57685 19373 430 51642 23344 474 2214 22989 17074 54847 40585 26268 41231 22589 1777 43499 2952 19132 37783 24407 51654 58194 19917 21427 24225 38324 27216 10376 19478 24999 38930 2354 9135 64201 3609 30638 17490 56997 49658 41463 19478 42115 33726 18542 49812 17264 30475 26852 45736 34856 60704 36915 30629 55314 55595 55069 32899 1148 47034 7010 1038 35304 48948 31655 45148 43876 35527 16067 4935 9577 33552 21155 41125 19417 19824 30983 43827 7932 19030 6570 22950 12159 51605 48481 24860 16232 29999 39815 44264 20142 10369 40751 3746 7677 18142 29835 5913 34540 26177 23801 59012 22841 38331 13466 4285 44324 27586 44772 34860 21984 53139 1521 56111 28460 22401 33699 55647 7816 58411 62421 35781 22929 12806 14744 51158 6188 44859 46692 49760 56634 5045 51269 7235 60642 17175 33440 55105 27845 7999 38734 16000 43828 39697 50855 12539 37255 7378 27074 39670 12973 16670 46890 41887 36267 21658 52433 10301 37798 5181 13436 40888 62508 56847 21299 8499 7886 40158 57403 13891 14893 59586 44500 18179 36274 15586 18841 31252 17450 47774 4196 38506 8474 30062 29530 27958 53362 25504 53341 2602 22236 36256 58175 15312 22045 11188 22579 41878 40730 6371 44873 52003 3469 49421 22542 51177 23001 15404 1229 13831 55957 57551 21788 576 52526 33730 31379 42575 36871 6712 63962 56248 12599 19315 38375 5641 47764 46982 55893 57556 45168 19676 56846 59786 57275 44849 20598 11365 21929 60780 41355 2671 57129 56737 20906 5847 9930 25123 18945 36014 9536 28868 33739 43749 28598 19917 47386 63797 18737 34644 51497 12263 54181 12288 52579 20726 24060 14084 64254 31270 59445 23072 933 47362 45614 44161 12866 14192 1118 56383 10349 20024 51613 53070 14870 45158 62644 33266 36998 59571 31362 8901 28571 16628 52528 46328 27621 21345 42502 30154 18550 28415 9343 57851 64095 16975 19489 48836 53525 1301 48226 23540 57015 21790 9367 47157 3859 37695 26027 26762 47576 44674 22542 7666 31681 36295 51476 57319 63806 39372 58969 330 16456 52685 41224 54696 36251 50142 34730 25270 47677 6011 52219 5881 44603 43102 12799 7185 9023 10518 16007 58977 61746 10530 37398 27110 13441 62901 52063 41638 28189 19584 55344 28970 5987 45379 16154 30015 23106 30562 49336 61969 2920 13542 14768 40181 11913 3941 15072 56562 19008 16943 53410 61918 46820 14211 8325 7240 36352 10267 51105 18446 22044 50331 41051 61789 36498 41286 1339 56224 41543 32995 15960 18216 9028 38798 3650 10048 52056 15042 6303 55485 62205 23675 31237 7961 36784 1709 57051 42252 5200 6776 54543 17971 37669 2146 30666 64392 31332 41395 22944 46674 29077 45753 48332 58026 22994 24492 57881 9285 6863 63068 38529 12474 10029 24581 13622 38467 60012 43462 59621 3581 33674 64087 24024 43171 48105 57903 56483 5755 55357 20552 62461 14669 33654 8151 2915 25936 26813 26367 61042 2855 50638 20286 37978 4464 2863 3235 21513 25584 53104 37127 48310 44386 25488 30880 24670 39262 34863 54172 32858 41821 38481 31503 25052 36414 27805 47380 50830 14988 18936 11093 2335 54425 2729 60943 7765 17028 38086 3573 53978 51994 63029 239 41064 59904 29727 14640 55638 22748 28675 62270 25379 49280 36314 8705 8847 12704 62071 45003 0 1311999172 +512 8433 50767 61214 8582 9615 3265 41110 63230 20172 51479 10264 2384 20294 50973 12883 42431 34673 35632 5387 30981 60936 9210 11007 53637 52450 2572 7529 30554 43214 51193 25087 51444 61167 20395 38645 63749 46331 4080 50150 41893 51400 54017 40974 42137 22078 28802 40048 50634 28245 56557 20744 50326 41210 42484 37624 175 53860 61504 29247 43708 51964 14990 6130 33628 10253 21473 26496 20963 6073 20105 40767 35937 20880 21387 53053 38452 37711 14448 23655 26394 16281 3628 2338 6914 37669 7146 63955 3000 7735 13059 48305 47859 27403 29322 45498 48276 63805 360 42470 36339 57998 16968 14275 12763 3124 57911 30941 61258 39828 26232 15334 901 33363 2581 1392 53302 29815 34777 9378 40337 47524 15887 41337 40043 63035 57836 59842 36685 1895 38770 41412 23333 36954 53703 20317 19789 56263 23314 50882 21103 62575 55903 47540 9123 17166 6222 62998 51364 43132 30404 16149 43262 21098 54884 44427 50743 39998 48449 40937 50722 885 44549 41462 19197 33722 8456 10109 7272 51009 8133 25161 52446 2173 41084 5666 5192 12992 62421 2439 17215 49994 55352 39384 33210 11249 38104 1924 2490 54581 27119 37014 19534 10201 28991 28470 50275 4528 20396 8826 18371 47234 11700 36633 48971 31006 63870 61746 7783 40329 26647 27233 25965 53191 62193 59819 54608 62356 10868 8938 60716 4531 54799 61040 22950 14767 54256 16532 6603 35026 4338 61269 47885 45000 52340 24734 3789 2203 23434 34652 6902 38887 55964 53202 63496 42813 51791 12410 39971 56408 13793 14031 40776 17023 20355 53587 10205 28274 26622 57925 12719 6955 17864 27356 58809 61989 17867 8863 36114 42150 56768 26610 51008 37168 57629 56144 36150 33132 31572 25317 41567 26912 29942 34719 11466 33516 16390 36911 11773 29165 6182 26683 29454 28119 2236 24813 34029 42292 45872 63097 2383 44757 50015 48865 42006 12417 7519 20413 13922 4631 434 43218 13434 45323 34402 5458 39512 62427 58900 10340 50700 36485 20800 17905 23627 62777 12367 7080 38364 24655 43666 5297 17999 58427 46497 14165 33390 63858 34026 15795 60051 47578 1093 52692 22764 20583 14049 23666 21434 41244 55094 2823 1304 62128 44965 36037 61916 59833 52462 4104 38045 39058 23039 23701 39096 64511 34064 50009 25043 19860 6314 14590 17324 1360 25457 23016 38346 34844 29216 58015 5292 27822 8334 48354 45757 5636 13010 43229 40267 28609 41970 14824 30831 54274 62266 59816 15324 11117 27320 23795 13228 58728 8942 6336 10193 12003 59460 47260 26798 26586 50609 7812 35689 21301 18464 34174 61214 51297 46887 27087 23593 39544 36476 1396 1537 47081 5400 190 49353 14613 45674 51605 45512 58089 18265 33693 3107 36831 49559 45567 29177 49713 2053 40666 19807 64483 18098 31351 37478 42761 50870 20203 24140 6738 42442 53963 37538 43931 53870 18583 52252 1538 35110 97 55621 15725 59581 33392 10753 21428 35894 36191 48727 6628 52402 55938 44024 53697 15211 55866 1356 36295 53173 60264 40092 20383 61988 13424 44112 40343 51859 5613 29639 48474 57304 8316 51059 3363 53081 12893 38307 10218 33537 22699 43605 46702 14837 2302 38408 40803 62714 16442 45964 33191 34923 6517 8519 56607 28084 43147 46979 18325 31464 30646 42468 31175 21876 3558 22569 54770 17548 35237 62338 57328 34532 5326 11630 18731 15707 16381 53304 45314 60087 6149 53145 11354 30630 39542 53616 40943 61207 29625 28002 3573 10533 63827 7432 20230 9167 25622 16413 17957 34697 9881 21135 52701 62593 35803 53708 4212 43165 50202 56353 45686 62491 54437 11520 43285 12951 63387 8906 1798 31510 6215 32870 57976 22955 36289 56914 60115 14689 42674 42405 23607 13499 62015 2268 17687 44376 25596 55752 42025 63962 7152 39464 54911 4765 23926 4091 31497 29071 63616 27547 61185 11506 23567 20151 24315 44304 18737 2918 39341 11704 35523 52669 63339 7975 61983 6747 60456 263 45738 17049 33287 3409 22852 19444 57566 49323 16436 53515 10349 54790 56266 50789 10170 63452 35369 62552 57334 46193 35166 38847 27345 30396 30533 56870 54282 49281 53474 14976 26509 45447 54085 41473 59689 34738 35613 29912 20768 58412 48245 61168 4770 39422 14488 5051 24548 27809 19756 43459 29247 5437 1190 45645 15241 17441 50907 63977 28794 7979 28368 22821 31478 12785 24817 58836 18112 41964 3796 19944 37721 24527 335 58917 17102 52738 49835 6630 4175 63552 37674 35066 40179 63057 41616 46828 18416 29331 41231 25755 8891 10904 34730 37218 61729 21951 6585 38675 50893 63220 38028 29568 2392 29615 62254 44676 44033 33436 58729 13046 10117 52039 60715 40890 29902 10964 29123 40423 47038 5704 26614 58952 13265 62544 36066 51963 14288 31373 54244 30206 23910 64411 43365 47966 57614 6746 57670 27140 50575 30603 16280 63339 62832 18870 62109 24627 1644 56724 54935 25904 41854 50639 56436 13174 38169 24265 12480 12865 9750 7001 45037 27798 34725 8772 51903 15444 35191 8973 15219 22919 34448 55611 34780 34044 57215 55224 11261 59405 24309 19925 31256 2145 13751 61600 58577 22040 26520 11445 27856 10700 7556 30549 12747 36370 28829 1727 28434 161 5906 24829 21226 9403 34748 51130 57311 63682 7625 2145 35801 58499 63515 44601 42004 18375 51297 38735 12103 40847 51719 50441 41834 24486 56833 62974 9318 34877 11062 6005 25580 48606 7008 48994 58607 8172 13506 56339 41008 51475 11383 2409 46493 4532 22116 27973 18410 29600 57893 43201 33047 34059 56438 63187 57292 13455 31001 49075 28344 26577 33049 19910 11220 25528 29566 24909 59487 60736 54689 14186 17798 62688 34939 36648 52703 62977 58988 16237 39713 2458 12492 58404 27897 38406 38840 46771 46066 52364 1026 7255 55067 43128 10209 9534 38417 23792 50114 44156 63878 25315 44524 8628 24484 56421 49561 36382 6462 55059 4449 1599 139 7244 60802 24145 22302 5283 8272 11726 62394 7034 55127 21454 2991 22661 40119 18631 41314 57451 3561 47912 43821 16050 39349 46038 16876 26736 9043 22451 43954 46556 47811 7021 5789 49031 62182 35635 14319 823 48512 62742 32937 48573 48500 35535 52358 17894 50298 13843 60403 29900 11487 56779 18748 41942 36340 56842 46436 25873 15664 34534 26282 61695 30566 58736 47709 3307 52451 823 14631 62609 59700 58619 6516 52498 27564 46300 102 5669 44578 15555 26109 51514 14580 23196 39457 37809 0 3484480886 +512 61295 59219 3804 2594 40473 30640 13401 39794 44634 41442 6211 22864 43800 48282 57255 55491 27386 12273 5218 48493 22260 57063 53809 40211 59659 59806 17110 48543 20728 44382 48320 12220 58813 20791 20556 29709 59006 34365 20693 5583 35402 21220 6430 61700 35817 28332 63337 36966 58206 48326 8085 41598 64202 19458 61426 61592 23142 9138 36511 56707 44669 9711 10339 22616 55483 22085 48838 52824 16850 6567 10981 22786 38379 8191 55762 14052 49641 46647 35654 55214 6562 31590 34907 53053 8004 52066 29394 42442 42684 37498 15762 15931 36854 29592 46512 42891 56665 10048 38701 2946 1186 58659 11639 11447 23592 42121 48904 61953 9904 60504 18454 53830 59147 8064 30866 53883 40578 32967 8157 40891 18047 27768 42199 31544 54949 52898 8796 16998 44448 35170 26117 11983 24649 12559 22589 21815 5141 28160 16187 29963 25114 42567 59413 27811 8199 59431 52014 31380 51574 39920 28407 54694 14061 6377 36223 50733 43197 36116 41599 53561 48505 3510 62143 29523 34256 421 58718 62286 5850 42964 22694 16990 64416 17424 43442 15067 42509 21836 28001 60974 2177 63401 44983 43770 63392 25416 39240 37527 8426 34770 58397 46223 51349 51750 43010 39310 13748 15344 21989 18061 48748 40794 23045 10735 8537 55536 4742 57367 16863 26564 13962 52654 47660 54665 38795 27797 766 51916 3381 61690 19391 18625 24771 3499 12170 50955 20364 7229 39661 41788 57311 54272 9304 61572 11448 16763 42069 28210 25770 34118 25438 57418 29981 46878 54238 28097 16869 36254 44489 63890 49310 29065 23388 52799 54265 8673 30110 28112 15058 10689 22757 53052 58972 44421 20488 4451 42367 24670 54185 9289 11628 5016 49219 30492 54912 56019 9351 63357 62835 11880 15989 7117 39922 4455 27596 12471 38746 39184 25715 51801 109 7391 12392 37384 45089 27196 31675 12279 43696 20360 62345 57512 29150 12273 54686 55035 45600 6990 55061 41553 33844 5778 48710 12578 37505 48974 40687 47255 34733 21772 41515 41480 29289 51889 21666 7598 11060 22043 22671 36803 51798 8486 20106 60682 45346 62349 35787 56326 60199 33603 34490 2257 11183 50212 43535 17705 44631 10966 53159 26440 39824 59724 37404 45033 54206 42796 30530 51537 57614 34517 63507 57237 19041 60757 52323 24614 31693 325 8417 3150 52375 58857 21657 40561 14483 46358 3084 35676 38793 11648 22969 5686 40937 56331 27984 58422 33843 4395 21708 29546 64374 12323 7575 71 13530 40251 30116 58672 56169 24495 29029 50900 30662 47218 45241 6949 27906 43167 46020 53224 22332 59000 28402 22197 15469 4587 8344 48736 12296 11584 18161 43874 4537 24058 884 51434 53197 64119 62849 61331 24551 46998 29348 59263 51432 21414 27106 7904 31492 44041 57765 64170 44804 55420 58377 39489 50863 21637 23610 9979 39555 52869 63991 19723 56623 22235 3398 11492 2112 58383 59381 2775 19980 24233 25433 41752 531 40278 64365 30804 25924 12944 39115 48858 8363 49184 37282 15834 10442 64498 27476 1085 48983 15234 48704 5072 45455 48504 46036 14250 57871 23190 57639 48598 24270 46071 58444 18076 9205 37901 33245 55231 27635 3810 56284 18742 11873 27863 12881 20228 14609 41997 23085 21208 21150 26859 9681 4155 49031 63283 60533 34756 48328 2550 19675 4047 39711 52706 43304 52135 980 12869 17098 8626 25344 56497 35282 54711 16082 41819 10190 8298 36015 23056 3415 24094 39071 15406 47870 34766 43500 34364 35827 6543 6710 56675 34273 6599 8746 38465 28216 3822 64317 22220 62354 21072 28900 12961 31648 59872 54459 28378 49645 42808 53370 4676 23050 63792 47229 54189 25231 25068 30759 48470 495 17384 54293 60213 15653 29800 61918 60150 26272 33631 13763 9040 61050 24711 55700 17258 40282 31505 48901 59562 61936 53783 15936 34960 22084 18285 1028 34667 14917 16871 25040 4373 35844 4384 35653 14168 43465 3999 53015 30295 51089 57632 49718 10420 20517 37242 15867 9865 46 3295 779 50023 4523 19630 3019 63335 7716 2571 56831 49343 17455 6342 23657 57511 20705 24293 26814 8108 4668 55622 2460 39327 7314 10764 16755 44644 10883 59653 3511 8767 51496 58313 42946 22493 55702 43111 35020 43745 57380 60749 46143 27227 63713 12376 26187 63424 38034 21020 51113 57616 14062 38150 52844 64154 39247 48833 9715 61400 3770 42272 60609 63156 12991 26153 20870 24907 53522 30967 26237 18624 28812 24149 934 11890 36557 48999 50060 31359 35811 9290 7120 12110 8803 55838 11576 13890 12190 23163 58372 31202 60558 62350 63600 17830 11120 24900 29869 43217 45923 50119 58423 31663 20113 36449 21092 53803 11338 29978 26319 6306 3083 53393 49274 19028 11855 13313 3862 20259 20736 23208 18296 63009 30983 63007 487 52081 42443 47389 59276 61608 2906 3173 5042 13289 1790 42372 41642 39647 25781 30164 64490 57152 23489 62366 56774 48612 61509 7024 50011 24671 40824 6039 37586 34618 46640 4416 368 30617 41704 50930 39291 41076 13464 50578 49006 35896 43548 47696 3463 23252 30236 37344 52086 1666 58960 43728 22744 3071 45646 39712 47295 5115 9042 28347 33516 50531 21966 45897 11345 2514 1530 3991 25110 28155 47161 62483 1274 6552 36980 44679 58334 29335 22023 21634 59412 44628 59187 45601 50679 11974 57317 9460 24013 7564 1787 10130 10983 30649 5034 8881 35624 40503 9576 47968 45489 62596 34152 23286 61897 30841 52386 41430 42782 58706 37870 49261 13225 63545 22524 45502 62593 22548 32940 483 45262 15320 52514 52022 3120 57147 41279 62226 25337 30101 62980 47803 22951 33870 52146 43174 40788 58669 64194 45965 42266 59312 38976 4247 20612 41254 49650 6271 16000 34720 50863 3398 54885 59713 63785 56944 40874 53388 26538 27157 30434 27337 8921 15143 52154 23583 26031 1579 24622 54681 11285 59386 38383 49858 26852 34723 12338 35996 39265 9089 18278 33930 10963 13393 59782 44704 8680 5075 3849 56272 52399 35650 43967 42168 46341 9954 28425 20066 15256 35962 15883 33573 42547 10283 20444 17149 20349 788 62756 54831 41809 12429 31124 9210 545 3016 9943 23527 16597 28403 62309 11934 57773 36491 53750 20124 2407 2244 39361 9890 24872 41866 59171 19642 12525 7204 55864 23529 43617 9764 35077 4707 22456 29824 11391 8755 37606 8137 45880 14622 17829 47068 14503 13144 12992 12289 55154 56112 49085 63376 27965 33328 62532 59144 58636 207 0 1304609419 +512 22585 12453 49360 46800 22752 41178 34128 48308 5045 44466 52658 43492 25985 20394 19029 49978 53274 12796 63374 61457 49906 6376 11207 12969 50811 44078 12532 38888 57765 50833 13939 11320 6238 55379 35268 33413 45158 17677 45411 58496 62181 57070 32962 21100 29540 18750 4648 20714 1399 12576 7135 50375 8247 50879 57686 1305 16830 26221 14717 34291 23418 47093 53618 55625 60388 15029 27328 52847 13367 20108 18694 40448 61121 35313 55720 47677 25266 35256 21043 59667 57567 55312 52334 11920 22743 16961 48443 37453 5590 52649 33686 22295 50791 7834 38829 31150 18436 5724 24768 25247 8226 42793 42073 62704 27830 50814 22720 52212 54630 14417 55344 60041 51840 26854 47410 62840 36762 35601 64319 64316 54342 2798 54888 7771 7814 23968 629 21528 42556 36783 15668 43315 59025 27558 24508 38496 35263 53635 6007 27160 44023 43917 53398 32863 17725 18347 62941 47245 24507 58677 2566 28358 56381 9861 6565 39618 57749 3261 61413 10834 60326 59737 41852 21447 62997 24312 1288 63535 2148 9035 41337 58172 46347 36 10000 27115 55980 12369 41747 36699 16662 14691 48897 13043 3925 12806 20575 781 44231 2051 10996 16949 25162 21028 23581 13337 20066 9659 16796 762 14456 55944 3226 55602 23007 53603 30726 23664 2065 48734 6336 5201 5820 483 16026 53713 17357 36455 55366 8292 15239 8908 36087 22207 40446 11205 53869 18299 26390 23673 31552 12077 25421 53490 62116 22632 705 14615 21456 24300 41201 39325 47223 6930 51768 51813 35336 60420 22890 29561 7925 14827 49778 26545 7642 21842 40200 9455 29026 59066 43540 36314 27044 43009 2131 19949 23150 11520 37976 57409 48900 40264 48580 20020 12441 61399 52794 47648 5054 10776 8148 14314 63203 28894 30409 44800 39185 61004 45019 40680 58229 59293 41602 54538 61584 47409 29739 33129 45412 42418 25906 114 52678 59723 63025 43815 1048 27283 62759 47106 18666 23372 2543 61031 2410 24279 2376 62821 16931 34397 53561 62480 46676 22129 19054 63636 27109 62938 21931 54572 10686 48123 30168 15492 56565 24402 22476 7428 42755 11279 44953 12815 43225 55881 48320 7309 27547 23466 12948 44014 20440 8317 36068 141 24212 23316 59529 11611 56210 6480 5707 47847 11946 31706 44694 6902 29366 62709 3893 38869 30645 61380 55006 16947 487 49715 34547 3848 22130 28062 63187 46748 56250 3846 28369 7511 1766 61382 17321 18667 50850 47895 51763 50167 2869 26316 5553 56245 29934 48248 62015 14273 34295 24354 56038 845 55328 45372 58568 10973 19440 24644 26693 7423 19311 47348 4637 60260 13642 14 53516 60545 10776 40094 35861 28036 21372 2375 45589 46257 63327 35141 19662 36419 24891 1985 59576 56858 35204 17049 6649 11611 43632 17489 23930 24605 11563 24277 1898 1358 14962 58700 15658 12535 33578 16590 5910 56072 44076 19034 40048 37521 23964 49854 55175 43651 52687 55588 25930 56371 14495 62491 33986 40928 39611 30917 38989 2801 58453 43749 44371 43998 27416 10243 55792 41251 24324 50872 59571 28896 55341 4680 54613 2557 41310 42864 56651 25962 13968 60927 55622 51145 17404 11334 10879 50457 14405 2246 59266 38768 55814 30761 40551 62362 22163 55538 12118 36914 22510 20814 50034 13957 1972 45980 9800 2048 29111 53200 62563 30057 53521 3377 42824 57419 27461 55810 54185 23540 39591 9776 27215 39747 58710 56545 21726 57295 14961 15424 3166 16034 20026 55778 24837 59736 12603 54149 14124 19644 40698 13681 9474 22577 26685 11271 60644 21220 3569 25762 27424 4280 58819 60133 15362 22960 43131 27557 21786 6200 54597 40115 12255 25432 2358 60466 19656 2642 8095 19857 48039 9227 47896 58899 34015 1568 48472 35852 15777 31077 54704 53606 24119 56616 40059 1667 28135 7667 20991 18542 33517 35989 31149 3782 54423 29006 48709 55191 42675 41059 37602 54990 14930 22334 24956 36416 12396 43786 11525 36031 7566 19777 55198 54653 62052 13837 28387 6931 38229 5615 52390 10795 49185 17916 63955 3042 45664 11519 54894 34350 45864 5351 8712 59987 23178 5960 9667 58537 16419 37024 1454 59897 16546 16999 28004 19919 56782 37000 3550 21069 60891 10337 9317 4360 6554 2674 21901 29069 45702 5859 52239 17695 45393 48869 13629 1791 42185 9638 37412 19655 1578 15313 42665 45467 26746 50306 13727 16124 19192 51694 18497 51390 55977 38872 30434 19034 41393 32899 40352 8545 28684 45597 105 44096 26155 42393 46041 31618 28775 29525 28851 42623 28079 21357 51795 56826 50189 18239 9716 50939 46574 29078 25577 26558 40780 34320 3640 51837 25879 8526 21398 35722 59977 24706 21431 8203 1800 56414 44880 40932 15951 44058 51880 21237 43441 6188 8114 9636 34309 1873 35334 8182 13599 12653 45807 1672 45683 1807 941 2631 64019 52285 48979 42121 1786 54250 6414 41547 26160 5043 47761 25678 5773 10288 47237 18073 17184 25416 58511 25518 1092 17958 41650 31742 42710 5826 30191 12850 22670 9501 41161 62293 56776 55548 29684 55660 52952 54298 56206 63092 37276 53828 36639 34959 58053 45066 48546 23999 12565 11602 25823 19805 49848 6184 60460 3347 48265 61864 15921 62696 2683 48092 58443 48071 50437 2628 40001 58485 5974 4909 4473 48909 30610 34962 58409 733 44915 38586 35115 62805 4799 8286 54616 3817 36367 8320 51229 33059 42053 21141 47279 41290 10053 63775 50371 20538 11680 59870 42466 42473 40247 38866 48504 37325 18308 62072 61867 4799 27592 16065 45693 21139 29376 54440 3887 13656 16091 28577 30637 56346 4170 47939 40262 53858 60565 55173 54153 21463 17274 2866 9653 34258 21176 36160 42245 33070 52534 55934 3825 53507 43000 11455 19169 47352 57733 63347 34553 54217 59527 62708 256 49500 23875 58166 57653 63326 51418 18358 61661 38747 38963 57377 26567 33395 46750 61027 4954 57773 12100 27623 16333 37587 38531 43770 27482 63498 11594 60835 41609 15066 30379 17843 37413 14342 47033 57355 41775 28867 41821 19503 33511 49017 33441 7905 13758 52016 51949 64464 26935 36266 44508 48092 47338 22207 60059 54985 37307 64187 21970 18760 53833 55314 62555 28239 50914 26626 21284 10809 12045 52375 5708 27772 49019 30048 9756 42072 39571 58984 52476 4862 25635 20848 52113 1177 51024 13686 53500 16603 7158 32886 12066 21666 33998 17287 55298 54202 40558 12415 59879 45384 11199 36344 10427 21800 63127 2219 0 3447531554 +768 4184 15683 56053 50873 61954 59012 63428 64160 57903 31606 60043 23228 47189 32917 12351 35884 48904 9481 39674 36896 35432 11570 34251 13342 27361 45907 59890 36268 31654 63834 45503 56196 42997 2567 36496 60010 20723 4835 38844 42549 51368 23200 15002 54384 63151 49059 60854 52243 61998 5129 24065 35968 5083 55243 15789 63692 17169 11473 12452 49409 49299 50508 34738 57689 55998 21634 43901 52008 22008 19865 55318 38138 54802 9775 14834 56165 28174 18300 4839 1348 11628 10581 10868 54442 3639 10880 15837 12404 63828 49329 45566 16337 34674 48044 51222 19356 11619 18059 7597 48925 27858 52490 20242 29754 33130 38560 454 28940 63089 30514 58464 4237 7053 44648 4322 11964 448 4451 18984 8389 48281 42582 47169 22669 45794 1106 40685 59925 15049 27510 14770 37001 39089 52125 24160 46189 2653 39839 28065 20906 42249 35877 14797 1771 30678 1884 26909 45445 59390 3172 47477 58602 58073 41548 49872 11832 11442 38166 57454 37707 23760 62081 35113 27125 24637 37467 3796 61148 5130 62934 25754 44048 24819 2534 57476 12246 24071 64007 59786 28147 62823 55049 34711 48500 44569 27986 41432 38049 62018 26176 10889 220 53505 8276 32770 43291 30404 56188 51314 9122 1846 23506 54810 39463 35376 47343 62519 45789 43709 59237 58651 37854 42667 11253 37981 54153 40638 30436 55798 14721 18870 54495 46185 62440 37241 63416 52227 46456 25301 42393 25648 53678 48447 46403 43315 19530 61255 36538 38941 10991 39309 26711 30061 39196 30972 22127 9214 18138 62873 35178 7749 46038 45627 27759 28943 40901 63284 64457 34988 18740 55934 44278 30585 63557 55926 1350 21368 905 30259 18413 14827 44816 1274 854 26834 35702 34534 36009 57440 50147 49123 26188 19689 8911 7424 35709 5217 62807 43298 47897 48720 24867 36283 30888 4500 137 23755 9970 56233 39085 1613 60402 28163 227 46334 28764 42887 5877 5158 53852 53694 2708 48777 23053 34295 3412 13565 7230 9726 25739 16397 40116 52980 8830 4374 44511 52903 8431 50294 11227 2170 52730 63964 14051 30892 56662 14972 46362 49142 34443 48477 13859 7665 58901 30307 26469 18029 7142 16589 222 58281 55759 7147 62145 40041 54570 50498 22933 14132 31495 17948 7835 64348 6048 10229 14703 23985 58877 54863 24175 18058 28739 58227 16722 56771 28622 44171 39088 41948 48223 63191 41621 8700 49519 59113 37115 59448 214 38244 1193 24457 42154 14878 60882 20959 27164 1049 20314 51068 28814 30267 7116 45090 51250 44771 47260 34403 28982 16345 13806 50005 31217 57297 39567 16485 6254 16858 23346 10020 17817 22250 1969 40543 59187 42022 42348 27456 28649 14721 50873 56207 7724 2756 55610 36416 3544 17340 43747 22674 20376 57666 27203 14001 63113 34771 42798 5596 37524 7178 14509 31118 2701 8307 63429 17002 33357 21827 19665 12187 37347 30733 11100 14053 13078 14295 20495 54733 15669 18833 15011 8139 30549 59308 14936 49333 1610 26540 15707 58002 1513 4355 31025 40131 26729 36193 23844 35151 44292 9885 55029 17350 26385 23863 1229 49850 43441 16217 12797 13760 37189 40759 31105 46310 26082 14210 36528 18671 16473 42070 44789 22551 1231 58510 38897 7650 62601 42534 15167 1796 21567 35811 21344 41550 54320 30790 38365 24772 56140 45346 25814 7414 41080 59618 50544 8993 9070 20651 28265 33634 32860 45692 30349 42442 23321 5846 15796 42411 11759 44785 52040 36101 62721 14806 42745 36535 19509 50923 33971 34582 17847 50572 31147 40053 4354 21389 60042 23962 31433 63734 59893 28928 18338 26248 92 9486 24292 55260 8554 11330 7135 43452 11082 50312 8714 46739 43647 57679 57616 19145 51439 24325 30412 62515 48759 3189 41417 18886 62075 28722 21013 14413 54867 48613 42281 27245 29750 30958 39088 62944 62720 38332 16762 11522 7844 49070 25798 46150 10497 15695 9398 45403 7391 51676 13696 64477 1912 26065 26909 27556 41561 62509 5012 35288 62176 52283 53217 56526 17544 12212 305 36255 3798 54247 49547 15495 61410 51533 26308 15064 26527 21526 60212 42364 412 57727 57771 8099 28699 11547 11151 47158 60095 30042 13459 55465 10851 28907 26499 20874 33604 42188 11808 38411 18154 61650 18273 59707 5287 56530 52538 52523 43647 51087 9002 34 7492 5793 58523 8725 50133 7339 17126 17202 24288 21094 62074 3898 14747 56112 61057 328 47294 7287 7657 53226 23209 24308 20335 40587 7520 61027 30588 5429 50977 5498 8436 34838 20187 30539 4160 21187 16332 59577 7544 4053 60212 5902 58268 3788 17782 42236 63166 46477 43796 63637 53944 9262 30796 50944 61681 45037 610 8655 42463 23125 35153 64376 54892 8343 23391 16445 23973 20331 2898 7219 8666 48548 5663 36556 42487 6903 46858 27528 51671 13980 59770 30766 15304 34553 20804 41683 33927 5944 21692 50605 57169 21075 45816 28839 31714 2019 26763 5147 57925 45500 30561 29737 49905 27191 58017 58053 7228 8534 33315 20675 51338 17076 1873 50517 6785 41433 47759 27676 14433 9428 48079 2176 31016 46951 30567 38720 24563 25414 48935 58512 37609 13634 39093 10158 23464 64389 62702 60983 13491 62706 33285 37654 54266 37671 25184 14783 7288 58556 22979 9799 37876 35685 59409 27832 20117 50364 51684 9256 40837 27706 57854 32790 6540 16233 33730 26939 22473 61548 47344 57538 51819 59788 41701 22912 35633 21868 9942 18395 5057 38334 14882 2748 37941 33946 8636 1397 4229 23311 3494 52898 8257 37434 31434 23913 14483 22170 58564 55495 10795 58969 55554 33070 52519 55000 43995 25457 19984 60985 15334 45739 29584 3389 18165 21783 19599 56885 21667 690 18043 53943 38098 51115 60597 63022 11562 29001 44099 7911 25603 29431 832 42509 15977 15641 40704 10775 55831 58017 29668 27454 37515 52053 20112 2123 37529 5324 11629 18816 1427 18979 6301 47845 16679 37555 52381 23403 23007 33379 476 28398 29240 3149 8338 7842 554 43884 43351 11316 23472 2454 31606 5792 56913 55802 25285 32920 30178 45389 39889 14550 17597 50362 14465 51185 47325 48216 51507 32891 42330 24659 38025 21216 44815 7059 10219 63269 17154 6819 3085 26918 33882 28203 54223 21401 3361 47328 10053 59568 5042 62358 38416 41722 54842 8037 39439 56220 33905 9761 1512 48209 46551 15237 16561 6968 54488 38979 20582 49392 23718 53309 37515 29001 203 16698 45106 47214 50575 3913 9879 10481 28108 47610 26115 63203 2480 41217 57935 39790 43775 48921 31107 33445 12892 63455 41194 49781 52878 36103 1193 19994 5444 43236 7324 50813 29696 5971 19116 27902 16796 62100 7177 19011 20953 37313 5080 1744 61389 12457 55319 46730 5852 54915 25536 20080 12587 56949 62471 47438 34487 53141 38991 10229 15867 59555 13445 43071 10701 23401 6241 51447 39396 61379 45136 11481 7288 44159 25162 58970 25381 60235 16389 8320 51512 9358 17300 24485 11253 38407 26666 18064 40135 46862 20204 57768 19130 48997 46602 59515 59587 61987 30212 52888 30604 7016 42767 41102 42345 55178 5407 2023 10903 53433 12237 46434 40018 54789 58205 2313 33266 11748 37180 17215 12490 46172 4902 26845 12095 17352 6656 49772 54609 23723 7298 30823 17097 16610 59085 46442 4604 59971 49840 53409 14301 60527 63234 16811 16394 21521 48408 62549 54994 25198 4033 59324 32805 30087 46865 21495 52686 31398 63791 27838 14550 37896 7207 29238 9192 35629 30188 15981 26071 11779 35919 15191 44614 52133 26044 12219 27421 42156 5939 3543 13380 37064 1759 58163 43196 63311 59909 45313 46690 16181 41684 17293 36347 4237 56122 20865 22332 11426 3101 33671 49595 64317 25449 38093 507 49243 12165 62209 36887 39656 33527 17512 3340 54745 47319 40506 39568 23246 52449 34278 55038 41339 26194 19686 3458 35810 54335 38570 35751 9107 46554 56604 26140 52921 5331 41885 291 54311 56800 57741 42115 63870 30452 49709 33502 18332 24058 40609 56790 22692 33613 5813 12502 50152 14936 34510 4254 25653 31108 55676 49585 52012 11277 59740 40992 60172 30540 33034 25744 24818 47226 16252 2184 2923 26670 35562 1525 24174 9255 580 35165 41075 33033 57709 58028 41431 6000 45668 37465 10825 9078 30966 7963 44129 23413 36500 327 52724 10260 63921 5427 28960 18792 40701 41434 37141 13854 12372 59639 61417 47995 12360 22229 6280 6363 52467 59980 27702 30152 7856 40482 58598 5832 43178 19254 10270 19957 23385 49279 21070 44850 91 16972 52340 36305 33989 49952 13583 28062 49091 11923 49075 24447 48682 39389 61250 27562 38314 38709 37829 42093 5498 12793 14196 437 23583 35441 25515 18366 36101 10509 45618 40476 63792 2313 801 14744 58646 14397 25940 41489 28091 618 7891 4809 11397 21714 24875 37749 52638 10331 28963 24667 56351 51021 40820 1440 43010 53928 21269 134 25452 54438 38100 28937 58416 9156 40299 3909 39671 57687 56022 26248 41225 25346 45439 62596 44198 37160 34058 58087 18635 43861 37491 27509 11261 48772 16724 38217 50946 41938 1931 36623 34124 59094 12928 27618 4263 32927 2636 37912 47865 16504 9013 8088 34728 57372 27688 10536 56437 52930 10300 38044 29143 24278 912 58058 11799 39733 4766 9946 23275 31563 37241 33498 47193 5134 51956 20123 23567 39400 60917 49471 40395 31181 15867 51016 23501 45521 45415 17880 47155 61465 13611 1579 8062 15902 42600 7227 63499 29343 43237 22145 57017 39077 3890 37007 28553 23590 36152 56575 40158 53681 32854 25908 59375 45439 18285 4642 37188 56544 44931 24473 44111 25418 5015 1141 38638 94 43402 58907 39788 24 8086 36258 37778 10823 19339 24505 0 3476821242 +768 31279 61874 2798 28932 40534 63251 16887 41650 3876 37252 12483 659 45992 4352 40391 48024 37383 18532 5078 35433 12629 30849 41895 33469 28145 57224 6971 60769 3085 50741 48216 64195 54006 46868 53367 24304 2670 14882 4517 924 30988 52268 27909 2120 27528 1114 30079 13672 17240 21434 59771 60015 35737 43365 56423 10420 35319 1894 457 5428 10285 38314 2813 40888 15904 59520 709 16799 22886 45501 33776 5436 39008 29324 42071 41969 49885 40473 17730 56417 59713 36177 18996 45443 49511 64413 19616 36703 46773 55335 53955 25466 20166 49096 24004 48103 40851 62687 50532 12475 31090 53879 36992 28567 60935 26760 59454 30186 62729 6762 27169 11424 31126 27562 59799 53389 41473 53620 40627 50087 22750 49162 52601 10045 56686 26248 38346 57794 8114 21229 15514 33626 59600 34013 20979 8064 15966 2420 2616 38098 8363 6834 4337 5979 55583 58648 61257 15054 28200 50868 60037 37776 44201 47492 33927 11141 57422 15013 47798 19426 54978 58696 45422 15749 42916 63629 8057 42226 38898 24312 36542 34761 56100 41484 8464 10023 55577 693 35062 33911 23768 38080 33956 63278 13187 9882 51179 45379 37830 36637 51018 9833 45110 20681 5381 9266 64213 58389 45325 3866 42453 64209 28477 10830 34873 28878 26971 13666 56239 29498 20976 28451 47595 9867 56259 27196 8016 20049 18161 35216 42137 16781 28147 22982 35443 18087 26421 10241 36117 42002 1483 34481 41240 44716 35579 466 35670 22686 26176 47125 42387 60934 21274 52933 49232 52673 34995 41087 31320 23285 39164 20845 48113 17165 274 35383 49468 2059 62189 25631 14504 37778 57878 57528 42628 55931 29315 61363 26482 38782 30264 35520 46634 44141 55930 23613 49648 19369 29417 10709 54398 23659 34970 5843 36987 51049 26049 14257 58513 35971 7637 30409 30208 50772 14750 20915 14483 545 51758 37086 799 42320 37646 22294 28487 19178 64025 24236 12617 17931 9723 38682 60617 43438 56056 53566 28822 11282 24828 3275 20400 49688 23246 52720 2971 11156 18062 15839 51435 59643 59318 47202 36362 11169 22240 27677 33074 32880 46214 58835 60727 47617 63517 26662 7610 20386 39508 48309 62664 14630 20875 4968 37667 48628 46026 53667 53019 2128 39488 30987 20816 60552 14648 23921 54676 53720 64480 1741 53071 62420 36154 12608 40157 8651 50946 10491 57117 45163 55728 23153 16837 64263 28473 50482 17411 27260 58940 16870 25403 53266 23628 42374 30530 15744 17196 51213 38905 19294 24798 22338 40118 39432 11827 64056 36110 6239 6485 5977 50850 10671 25190 22379 21627 42048 15801 55413 11152 18686 43312 24370 36387 46708 28668 8876 54462 19578 32901 20383 57466 27161 37504 12377 58440 1082 34475 23003 29395 20518 37056 62664 54463 22783 20041 6970 8668 55086 34559 46945 3207 44533 28994 38897 50708 33647 23001 16459 43657 1788 37160 36127 1097 15076 18717 36721 63072 33189 43671 11651 31276 13187 10874 14192 21658 18251 6681 36265 46571 43457 55 22256 25441 47364 51826 59252 39820 41651 21884 2414 1489 23340 58424 31466 44583 57521 8219 7193 48497 22629 28483 52891 27157 45599 14139 37573 62492 47192 64479 47591 14556 561 63763 56880 31726 25337 63226 436 44460 31250 39332 59099 12173 22537 27238 34121 18986 9881 6548 19428 40962 20074 7862 12336 20336 11721 52993 49552 5400 40186 33532 6010 11877 7259 442 61203 35790 50102 58220 57921 49656 14153 35546 13618 53385 12059 41148 60466 13711 55203 27410 4657 26916 60600 26103 35638 48487 37763 29038 58692 29754 41991 51928 28393 30464 28110 27025 45787 25247 20147 63206 47992 14851 62785 50866 19218 12382 12262 26644 30073 37633 48677 57268 13925 29513 1719 40830 36166 38901 57702 52183 20057 42418 42201 4233 40804 39770 36666 58428 30066 7875 63779 43356 16961 42728 8601 52145 5090 54440 34102 47552 24236 11980 44363 42051 56411 19063 8190 26356 52719 62595 50075 51106 25471 17568 61517 8378 20416 51202 22307 54262 51242 41223 53727 30613 40076 17396 2562 21176 30183 20118 7619 22891 62613 22621 34161 53470 56717 48726 41902 41837 17761 50672 18821 46287 30994 18694 25157 28123 3182 13120 13373 49389 37548 22804 26316 62097 4746 33686 9177 42541 62103 6750 26051 30893 26213 22691 61306 58635 6174 58597 50308 51350 58148 49276 51679 2471 8469 59930 39466 34255 52101 22468 6814 52238 34802 33898 39978 32826 6291 36765 26637 55277 17016 3250 29524 10959 41337 30994 22991 46271 37413 43233 28585 26689 44567 49059 28592 7013 1304 39719 52660 49102 8706 60860 48324 42645 26951 46299 50055 841 41445 369 14809 14905 45152 57930 20140 402 15432 29387 56450 25623 722 36712 44553 43035 17037 21262 38898 2850 26126 7306 10055 11489 34321 26447 48879 36936 3346 36352 21766 35082 2802 21561 2246 21610 16944 15464 40327 47164 9415 29351 62274 48568 63156 20366 35487 27545 22743 27426 9657 2377 49043 9021 29752 23563 23539 41903 45341 7498 38775 13273 29719 2359 13539 28273 44081 3810 54302 34133 48218 38842 1410 14968 15724 25160 3491 15161 29522 32992 16579 33219 17760 27203 336 62825 59735 47338 54587 13054 51908 18587 37373 21367 59483 20576 2583 40977 24703 39671 20049 21708 4654 21414 3685 7206 44914 51801 52761 11748 10326 54246 42761 672 25136 60194 47823 41249 26064 58055 20318 25074 58574 35268 7116 4454 42359 39262 29001 16593 40535 34369 60675 17736 4406 41755 4326 62514 56074 27456 33706 16699 22280 47071 17873 14161 7504 19356 9568 375 13395 57315 42503 8759 24108 7080 27220 54509 59937 43515 19275 35904 55023 18987 47685 55513 38672 51348 22665 37872 1771 24910 36189 21350 31205 13362 11445 18650 53199 21102 19069 30218 25868 3390 51989 16657 1402 17432 52442 5389 23314 4369 19571 30627 63302 16254 58635 1178 42915 17361 15298 27535 59712 37836 1180 31126 24188 41563 34522 23055 9528 64390 41215 16283 26810 40487 57036 40663 36222 13821 12015 47876 8587 41554 34613 43938 13154 56272 52796 7087 37965 6555 27051 18454 48266 39222 48890 8076 16095 8233 6756 44838 59082 34115 24671 54424 22037 47120 7173 56875 45259 40094 36435 41645 59719 53875 3983 14490 63524 51402 44038 46400 24960 26861 19655 29033 31159 23680 21384 57666 54424 53978 63144 55375 28997 16353 23610 49165 40356 40137 8013 55057 1462 37185 51784 14429 6006 14691 24599 22438 26121 27618 12518 35618 14621 15514 22652 60955 42820 38332 3571 29871 36489 38184 2613 62407 63561 62170 27619 26285 6081 9114 9434 39465 21960 43528 24199 51762 59782 34070 43552 12774 24715 27038 25374 63910 7406 12556 178 37879 57432 44105 56860 33144 6433 58095 24467 5765 62454 3404 29237 7589 39060 33375 57362 53477 19064 56083 22165 9248 30 60939 44197 28332 7711 44724 38207 37245 18504 19850 22380 35462 23593 38616 59471 44445 30209 48320 21100 41449 4897 41194 41726 44037 21203 53208 39540 50659 12837 26857 38411 34902 45316 51376 61733 61171 38123 56791 33521 18927 17717 30024 56314 61016 2259 25666 15428 45357 49547 17816 33023 42521 29079 33132 18788 18918 58126 24371 50130 23626 57280 61027 55450 55740 64302 45222 18130 26478 2413 39832 55225 14712 42288 61688 27751 18447 2451 35581 58688 59141 8951 42701 11500 45592 40382 42665 12946 8673 37638 50886 20475 24795 58529 37289 34298 18283 50480 11396 46727 34801 61636 9707 34022 15082 43176 50690 63831 10429 61035 20816 24737 42859 33153 40941 21476 18243 5697 33297 1994 31474 43517 25988 61738 25599 29587 16126 1512 21596 28677 12079 42186 45833 29491 16825 39881 11318 13442 26505 29158 16085 36402 40907 56344 18280 61293 60396 11970 7913 48185 3597 52943 5311 26921 34447 60448 43304 49649 63007 61181 58224 11320 3758 52744 59784 53363 50313 36374 57440 37966 13258 50984 25337 40826 2227 9739 20461 6777 7575 1391 3293 56799 54562 16972 35759 40004 63580 59717 20250 56251 30429 59097 4129 52220 46924 22847 60007 38057 26426 8164 9713 36213 54701 37947 30663 37302 16040 54841 46878 3311 36295 29496 56271 43215 34838 27708 338 1297 54900 11812 13511 6342 34025 59427 31680 26053 40768 44524 37658 13783 14221 8862 25343 48784 8131 30752 59036 50765 33161 25531 56698 7978 37732 50791 54495 40356 42358 56146 40155 39178 47046 7754 53103 2434 6844 44284 9942 28519 56924 27315 22716 3545 26294 28507 23346 51750 33544 30623 42153 59700 30657 21657 60360 12814 643 8966 32830 61988 21497 50770 10442 44835 29531 59148 7671 7853 28657 24812 31239 34377 11582 34331 59049 49429 54865 40919 38627 57342 1033 52677 20263 45905 19111 61968 49060 38754 61981 62509 43492 58819 56284 16779 19369 5070 14713 6703 36445 54135 41198 45185 54135 53134 6235 29817 18677 19317 11682 20158 58484 18562 18412 46517 40538 61801 50103 10549 24471 48352 37166 51637 58214 41153 42220 7232 16356 56317 41918 193 33643 6250 45532 1971 9797 15973 21725 5387 35255 58645 28115 17477 62410 16088 40697 39494 1031 37742 56669 10276 23039 45744 44897 17622 45648 19097 59676 21339 12388 37303 5615 56973 13830 14585 25646 18787 55927 18592 1595 1045 30044 7242 23409 28576 12693 43200 59464 38389 47709 23284 38925 2211 42293 51079 33524 26183 27880 46023 35835 53431 2378 11390 22474 30203 30405 40288 29517 59386 49294 59997 19623 47145 49694 57999 38774 39563 47309 57235 44434 62244 18279 46213 26462 2387 53858 14870 19685 9072 20370 54723 54801 16440 52173 511 36896 16727 30060 105 2924 58902 0 1326202533 +768 60855 24391 2621 8599 59047 57424 54688 40389 14562 60572 2292 62581 4988 38750 20815 8112 47040 50233 49791 12273 1417 58914 49752 62122 55292 26214 28674 19367 42624 17630 61893 40375 21651 33370 64434 28219 11755 4090 61238 17324 19109 14435 25368 13592 5391 47171 58936 18967 59463 36102 31609 63942 18712 17789 52977 49378 3337 16692 3764 9181 3491 14144 33476 64094 34025 9169 17655 54781 43941 50487 19011 54718 19656 16925 26979 34171 48176 9129 2434 43285 63117 44934 8601 64276 34933 55442 25904 26423 64492 5567 42185 52650 42893 40221 36652 28235 14059 51662 42266 24375 19645 26639 13467 772 42339 24227 20135 23312 36946 59862 27025 20779 18848 28216 13962 31439 46023 12964 20009 15576 39463 57264 30073 25520 38854 28438 31429 3956 20984 20276 17515 55939 16740 162 46 21719 11046 64086 17878 9547 60945 13125 45951 63606 49531 60835 16754 64328 25121 28751 13454 36426 39161 33896 44090 59185 46395 19299 57168 11449 26323 22660 47667 11848 7778 49716 44429 52021 52164 1653 46644 5367 49162 43691 16329 10591 24268 63712 34628 18434 674 53211 47916 28165 24643 62638 36145 6522 43639 51835 52091 3962 48762 47531 39130 6630 29807 44735 17620 33708 45941 18262 50651 23158 3948 40559 26569 38243 27709 37343 51262 49839 31561 25478 43477 9103 1503 64442 34522 56127 55747 37079 60298 33765 8091 13652 21217 25391 12399 62650 60892 6607 24442 10480 2965 56810 21162 35513 14406 18807 63315 12218 6962 11734 63234 61729 62929 16298 56543 54989 34685 10089 4796 28372 16522 43391 7069 40806 52687 31047 28705 33535 60624 47145 30127 23340 15665 54927 49627 60128 18024 54848 2538 56736 32995 61860 8520 37545 15818 28431 5361 51695 37006 60514 59776 4087 17344 32871 17600 32951 12024 22277 33623 7587 21939 21169 41038 23287 61982 46139 13265 61457 19247 9547 29317 53774 1284 44097 23030 4582 39464 14075 57231 33841 989 48071 38345 64410 41621 31627 34182 142 28679 38577 27318 31303 20674 33681 42483 55631 64372 36397 18213 8619 27296 30581 35424 60242 40907 11774 26260 50061 13935 28478 29690 56626 46570 24088 46583 17733 19907 11441 10938 6458 3172 62391 46305 11044 60130 53022 36593 25574 24011 46837 61348 10924 13132 50841 10517 7702 39650 9183 17823 23828 49704 57184 26191 27649 27248 55130 35303 57572 27691 44777 35801 23492 49014 60302 13305 19215 21385 894 18598 20945 24651 45187 3899 56425 33385 698 33688 13024 56937 64258 12620 11878 11705 15098 60663 39106 58589 21012 27793 6114 50540 2184 26307 34532 59449 3720 50489 12278 13940 10074 46886 14962 18544 52231 29782 60311 56096 19794 5235 22868 42088 56525 8746 62960 18781 34293 18680 36921 40309 6481 48416 13023 54694 59677 38973 8093 38461 34066 29895 43543 31091 21562 43929 44423 12079 30606 23970 51523 37799 3804 2185 35825 45770 39945 43788 13285 12730 4959 54364 470 2566 6541 35694 48983 10295 38852 14765 27720 16682 5592 50976 32882 2303 52308 16596 8275 23027 44619 10888 36655 5537 14544 31419 52654 41655 53689 2745 10540 52521 45990 35058 13400 50714 41172 20391 32979 960 60280 63802 50263 59065 39252 22953 25873 61044 40565 11352 33704 1155 59245 25325 46689 43961 21223 51692 39635 6971 20429 60775 45207 30961 59141 33073 50944 60635 21871 55085 25180 45094 23436 3807 54123 2925 61341 31191 6328 55591 55947 62853 50137 34668 16491 19570 61510 4556 35318 56677 57666 60648 49335 63060 53066 25625 6271 28491 18467 27393 57277 37236 29554 46931 33708 48482 29295 41744 19734 12965 19818 33238 13376 24500 40318 31198 18157 29929 43625 45956 59771 21168 14405 44279 34056 16802 59447 51198 42571 2248 2829 9431 14983 46958 7082 12370 64363 62279 57103 7931 22240 50234 26286 57262 15691 19840 62078 37830 60673 45070 53287 34760 23402 21465 53208 3754 44095 11513 23149 46905 49070 39922 13124 56239 20940 26231 18044 41640 37321 12716 41205 40640 49458 37663 43268 30212 580 57759 58429 53010 13614 37115 25150 47037 34895 64153 42859 14518 26337 49797 8788 8363 53717 63978 57033 17526 37570 53885 43819 52798 54323 45037 49100 28147 61145 58126 56758 1281 64434 5650 17319 2013 20421 2198 54133 1198 50968 47808 37905 48313 53953 48008 59139 54722 19131 17154 28222 61047 63945 5095 12438 3605 23016 48053 53262 19646 20871 59012 43232 17724 12540 49291 38599 7802 21935 34112 32958 56675 27851 35191 40429 33682 23065 49430 51483 58719 8676 61331 53058 6986 64215 15201 61388 27655 33597 18192 7068 8106 49815 7003 17751 54270 2926 52069 58641 58763 9042 822 29022 26197 29923 14860 45804 8169 24631 25288 63155 27946 26515 46587 9437 59994 43575 28730 42676 45981 37361 57752 51201 15785 25927 33422 2763 30222 36538 26958 40067 39137 54499 42455 51727 15604 50909 576 44359 59219 54070 14105 60144 4312 19812 36664 26298 50702 9296 9091 46204 21356 49300 13819 2104 26986 28599 58900 30137 58271 10454 44199 17951 8303 64112 52033 25161 29818 34832 25075 43836 19100 42286 12631 23330 49635 37691 40882 31665 27790 8883 54624 55412 57877 53885 53116 49641 33298 55907 12093 7626 5003 42668 19783 41159 35165 36387 35583 19274 24908 27906 44003 51143 3740 36270 52367 32796 26163 28113 22695 33843 54897 5260 17897 20910 41007 4110 19798 22751 59173 39872 37430 18468 16912 42224 56033 42688 19643 7444 27733 9471 23506 44957 12203 321 31084 13977 28114 61304 27375 15515 24528 55074 25255 28729 25895 10600 33197 50154 4852 58111 60666 47590 45680 20328 54601 17404 9473 17573 54408 9884 52475 52439 34677 41805 20605 7352 55299 1225 16843 3254 22403 45558 23434 41812 42905 11667 18876 6593 7686 39249 26588 48872 42930 33037 34784 13087 33310 51765 3342 55581 44704 58692 60545 229 39238 12844 31107 48604 60425 12622 45138 43879 31203 593 47393 53042 52612 14894 26853 59076 46319 28671 1041 43930 11598 562 43510 15132 39399 48880 38637 40204 3663 56556 46376 27265 5675 59734 36345 22787 49510 7962 48107 63413 38410 15653 53393 16384 42005 24314 13184 20681 7715 57990 23114 25358 38413 60890 6524 10282 48338 40884 46241 23744 49978 16833 9019 62064 27238 49220 23139 49335 16238 18348 56049 59561 3076 5706 57671 60420 24925 29105 37268 14602 49253 2205 46083 60077 17692 57007 46874 40464 29235 51188 44751 62268 41412 27582 26257 34170 18821 52405 46564 45650 51767 54381 7787 52955 17347 44311 33674 29782 38808 34511 44727 3542 48960 14245 59965 41321 37696 50921 23810 12893 39109 27451 7296 22848 11039 40796 62759 58416 43672 16771 24787 29464 10901 14256 9388 2574 49046 56724 39349 45265 39850 8934 48828 9891 56708 19822 38360 24089 33422 5720 20561 26138 50169 16684 1437 26362 25682 13396 56528 44825 46425 51895 33210 28322 4779 39947 40780 5961 3858 51833 63037 50782 33780 11615 56385 29031 38780 2184 8354 8262 53198 64161 17116 28932 7268 16202 22240 42711 28801 29778 47095 41473 57902 60024 56976 17821 36862 54533 55101 29903 63575 41032 135 17235 38961 24432 9301 38818 10282 14519 63163 16299 36446 47934 7553 9032 50067 50787 38177 48819 62730 43267 12958 34074 17133 22881 52105 29488 48696 8995 9216 46707 32965 16205 47927 47945 22557 4447 19498 23499 8538 36950 3902 47640 29057 46925 43508 161 11439 5983 33447 28323 4120 17452 11466 60273 15209 52260 30054 4997 26578 35556 49960 6025 34103 15161 41238 47105 49937 21089 24496 43003 34489 31195 10389 3308 61127 23118 61743 45041 23498 4360 12288 36919 38765 48937 1112 19749 41963 47260 57900 37132 11936 45895 62949 697 31470 18501 25140 26271 7527 58522 50519 9831 48913 57149 24617 51646 16629 37716 15745 11230 18131 15299 7920 64416 53399 59446 28864 59702 37829 41571 37521 47866 14494 39251 13044 3727 62864 18627 1353 42592 52345 58047 52592 4817 42067 62263 21987 43924 39422 62398 37124 57855 36960 25407 1443 14728 24536 63078 40847 11237 58066 21390 5120 33421 8326 18429 22670 28435 19351 62786 18464 38470 2235 39855 17256 42480 47017 397 10868 26241 39482 56232 27822 5893 31397 58333 26398 11323 46604 34051 32900 55419 43309 61313 14231 15891 40939 38902 41696 53768 14005 52216 39979 12948 43703 29855 18147 105 49446 23285 5399 45439 47651 14098 55942 6493 16441 791 46866 12377 20376 2716 7089 22917 38382 19423 2146 58395 19880 36842 29907 40896 49804 43980 60691 8191 60274 11641 58961 22034 45247 41895 45078 33732 20643 12557 52668 3356 36856 41744 14633 2491 49252 62372 12778 13895 36062 8606 40672 37608 27302 23089 4582 9695 62102 29931 36023 49750 57414 50090 44044 34094 44984 64362 11368 22439 34896 44742 60326 18790 29441 7954 13786 26906 41429 45628 35107 36715 59826 8405 47320 42443 42264 39966 50416 23803 9102 52699 48353 25125 55863 19613 57275 25770 5536 31642 10456 18699 26606 51384 29326 63439 34750 538 2509 55150 56268 38969 38038 51965 27350 8852 28168 63618 2799 34682 43229 34941 22960 43406 48628 36399 28651 53299 10029 23094 22839 56343 3841 25102 9397 52798 61703 58956 2039 64002 6364 56374 26732 17268 5705 44072 22881 42183 29762 7868 48733 17976 16676 38772 11507 20754 37503 9920 41998 28579 54782 47131 12272 59714 5664 23757 56650 45747 43595 49608 49755 9221 40479 61394 44605 54647 38747 33964 44806 60661 51001 57354 60325 63846 23169 24068 4050 12477 6224 49548 10050 303 2340 35883 356 7517 0 1286797300 +768 2747 55898 51119 29680 27027 41314 28183 35061 52431 20633 60568 39358 39300 10961 469 57242 18206 22015 10275 46280 602 36979 18331 61562 55430 39544 31324 31105 4680 15930 9966 39086 4044 3943 47985 36383 22327 13847 10093 18756 22650 30113 20207 12648 48367 47556 62517 2269 17332 39841 24185 33610 61406 12092 44608 21737 2861 40292 42957 30131 20429 55804 41613 17361 1303 44321 56507 24904 15457 43776 30988 36571 1134 10680 17362 49024 40226 2914 14884 9422 15942 45367 36545 31071 46330 25305 24089 22805 3347 25187 60549 35691 4906 20472 2226 9536 52988 5150 23271 52494 3005 30922 28534 15802 11916 25715 50066 19320 3639 48116 31645 14689 10812 12580 17030 50611 16208 8642 63951 49482 62490 21672 59972 11899 11261 10201 49344 64379 22359 33936 61713 36737 1923 20120 12103 62077 7994 42002 5234 28416 9278 31003 38311 14212 47261 20860 30834 10708 36590 51123 14637 4782 47018 23636 11575 33640 7623 4269 2826 15104 36546 51202 63267 49907 35359 56807 52027 41789 22549 45424 3582 3962 56458 33125 43613 41502 54815 29394 16623 14671 1899 5473 8858 58329 15487 55384 60076 12329 60644 43815 22434 44510 21584 47269 39824 7767 27860 41480 44993 32942 14732 60501 11867 3936 17392 16478 10485 46321 19916 13689 33743 25614 46280 27412 19295 47742 60704 25919 1648 18263 1546 8337 15204 720 2308 20223 56643 8123 8518 30121 50105 922 56896 62867 4203 46928 58344 60937 50367 48235 50992 60439 26789 58801 14894 37860 44124 32965 5803 61401 56430 61902 57269 40640 12005 8039 47659 61425 51527 22793 34959 54929 2641 56601 23657 28699 18431 17475 44052 14661 9674 56248 51555 52810 15384 44981 2425 27174 27332 56057 23008 57062 36910 51497 33584 41924 3388 30512 41258 30494 5960 63187 38442 1373 5892 38668 44493 8225 48976 19477 42759 50099 4995 29113 20260 34771 44617 62280 17380 7783 44493 3734 6452 25262 61883 54709 50962 48900 64003 47311 14012 33585 41952 55947 7018 47919 8720 30056 25396 47168 11270 40524 53699 44233 53686 3519 27793 28112 57579 1491 19074 24814 21775 30896 54534 38635 6284 57160 47943 1687 54803 62935 24441 32949 61584 35185 1205 21190 18022 56716 30595 21344 7033 772 31537 52560 29716 13787 38730 58114 11655 8460 56340 30483 8761 38651 22149 60713 7113 16162 58876 45661 15058 18275 26392 28653 29853 35717 19091 33042 59551 49637 50444 64077 61957 60654 35922 6777 22684 57670 50287 63176 56284 4514 33797 42619 11345 40116 41967 1670 45575 30255 1280 7702 9290 8543 33116 27975 10860 39254 5802 57058 18402 1991 43247 34862 30244 26254 129 40318 62444 29118 3184 17463 4796 54318 5210 10819 51095 11593 16230 24910 23480 42889 46042 57631 64399 40813 50335 40829 33162 8797 60936 5128 24453 53846 56254 23831 51116 43970 52875 29086 29528 22278 33297 59693 17952 56640 59037 31180 19294 7638 58902 57843 9814 34287 35106 27769 24956 5807 10366 45224 62150 659 14998 6006 23148 56249 608 25073 6260 40778 20974 16308 50263 35393 15065 16324 63812 52824 39818 35095 1180 35671 53405 11778 6758 54833 10583 51177 24809 64171 53352 50047 58618 8727 54682 25785 14976 44979 3638 14929 21720 8782 13406 43027 54452 5169 45324 4293 31205 52077 47863 37770 21439 40201 10341 10476 15006 18814 8891 18042 15387 4687 45637 13856 35530 11490 17904 46536 2382 53517 1269 64124 18490 59965 24053 23876 19145 54618 20537 12894 53839 43076 57731 7632 53689 24331 13774 13675 3905 13236 59423 13216 7248 39881 21701 51866 17920 3531 25641 53267 15505 5253 33339 19534 58499 62086 35046 9855 23498 21473 63605 18618 2041 58627 5845 26771 45073 33648 5561 36981 9025 61149 15942 44264 42786 21350 38182 19089 53473 19981 39465 22404 63722 17412 202 20451 30928 58156 57956 37889 17355 36049 50261 62976 11070 48702 12002 42506 50643 1513 15295 60939 33874 43305 48523 28146 56207 48523 24140 38974 30895 29265 24839 37434 8619 37721 53492 2627 19282 20202 31621 14323 57026 45717 18479 61909 56857 25900 38397 41016 16529 49944 49838 7619 33097 6290 20601 33362 9835 27182 6964 48179 62354 61223 8179 46404 20545 8073 41683 56040 52606 62158 11667 24255 39328 55230 17837 42248 64154 61251 25259 64044 51987 60219 11510 22881 28705 30924 46296 20036 708 56282 55968 15883 26462 58904 51467 4328 51807 13937 13726 59088 46837 8014 58374 25387 47709 18200 34475 91 6693 12701 56871 7766 25132 37283 29944 39141 61760 55964 41102 63566 53847 58825 41554 58273 54491 29176 57870 10537 42031 53092 44181 15709 48928 49672 48227 54589 17927 29060 16824 27752 10456 46700 16965 43945 36304 17218 23576 7885 40024 14799 10578 38593 27332 36465 16387 51905 36681 24882 56225 24732 42869 46581 40261 61982 39061 44070 38563 63036 49525 54882 33409 16228 47727 2963 27607 14435 56819 22066 56182 50722 44783 30196 26000 13151 25941 21600 54571 50398 26374 34154 10474 55000 64116 26769 20197 23746 7023 40643 54393 37499 60159 2300 54688 38314 9702 139 41327 513 23475 52403 7348 30876 221 25678 60570 19579 16572 36608 16618 55943 45534 59650 56922 7792 63824 6786 38311 14684 45750 34467 35007 52422 17784 48885 6301 30810 15978 39652 15950 21578 29208 4536 57094 23533 34512 8095 54762 61816 44759 39874 17805 49496 36422 47041 44875 48288 14671 53353 51678 5044 36433 41480 29059 30094 63582 31016 39704 62682 23780 27020 60380 45213 59271 59539 10874 57435 59938 18653 62663 12589 14266 28802 29362 12496 54961 35800 27381 63221 13766 50596 36566 48927 22419 36365 37262 19090 60821 9840 61615 40387 29590 52792 54085 16274 20287 26815 44941 7775 26602 42007 50966 2824 40879 9508 34564 18309 4650 6255 48620 1612 17012 62185 14149 10542 13405 27352 51749 6243 12150 57359 53598 41383 27774 16686 37833 17631 58559 55255 63027 54000 37306 29330 54792 44986 24415 38754 12075 6830 59347 37089 42098 407 1251 4072 34641 62913 36922 55899 29289 44639 19985 3027 51952 58151 31396 41689 34418 63932 6457 45287 61960 39167 42044 39331 28692 23136 6982 53531 18607 8052 10425 37065 344 15206 45118 44366 29251 28669 10015 47758 20282 1933 33536 48344 58518 48038 56799 50509 52834 30505 57844 20186 7654 55326 38633 2388 4326 20823 45286 48759 49631 9022 42231 63335 54911 20444 7171 19132 62298 44130 43225 22734 57664 4448 63643 14202 44067 39313 5433 34736 33215 51303 43508 43562 31156 24759 47356 44615 36830 30244 40540 11049 27123 39420 38635 23074 37607 20805 40942 44267 10062 11539 13562 16119 50885 25567 3656 17681 25364 50220 59679 60623 766 38048 36281 4359 46548 3406 39853 58447 12754 1823 37870 53737 59857 16668 5264 27599 9317 4761 43079 58882 63717 35155 23006 12175 55314 49126 14770 16610 27747 20073 4602 7296 43682 51343 4439 61696 2311 26375 14980 16214 20820 49365 57142 46883 42234 55828 44903 61414 8966 63721 57000 34194 9030 39852 57907 22223 28089 64195 60957 51509 41148 25533 46191 50870 4287 25262 5126 25485 60118 18929 3548 49393 28776 15195 31616 58280 34247 20496 6165 22600 22902 37396 50742 10180 61277 36894 35861 5888 19081 29521 44655 7307 57512 37544 38507 53940 28434 42110 55417 59400 57555 48831 51322 28603 64431 33764 12699 48085 46507 7433 11447 9347 23781 9204 29895 55893 15878 20489 56474 42023 16663 38966 21797 16631 48202 34550 59512 12802 56455 50200 25525 33365 12494 36287 10227 45192 11738 28934 58510 18876 8089 6491 46249 806 40401 2295 14027 52698 15692 46265 33984 25916 15927 4365 33418 41168 58920 27600 26953 54058 29102 29202 62540 42991 583 15045 38185 43859 63686 51871 22591 37495 36469 1393 60423 16099 58379 10332 29791 29571 6755 17559 56035 38541 1701 42681 9727 37937 17356 62686 18836 4738 28768 16575 33647 60503 17761 62426 38735 43443 21800 21637 39741 56231 30923 12284 5232 49387 35244 47381 11643 7676 7398 43586 8715 30777 2757 50088 44460 20561 28721 34681 54190 27996 60812 37534 37995 47488 46537 22637 25387 22760 17323 20040 23245 58072 64497 40283 23637 2699 57083 33742 35390 45248 12648 41356 51703 46004 45810 16682 61522 30290 2674 23822 59345 19798 29530 53682 12086 28788 36875 44362 11238 8410 59551 22635 21328 29353 50842 54572 23814 60402 705 24538 42642 63085 33059 20886 26120 45159 50582 16873 58215 6501 59577 30649 41297 57052 59281 51929 14966 16071 8889 5279 15793 52693 40554 13967 49653 36142 37997 38368 40495 36818 17954 30851 28507 58501 60142 62493 2414 18082 19512 19254 41424 30839 12845 61039 21679 23309 29083 54301 33534 48555 20935 35523 49234 62276 26820 55592 51779 47043 9125 33792 37577 26909 34087 16334 7895 36090 28291 8282 35709 31369 44945 1514 16026 41005 41127 943 18530 15952 31414 21959 46029 4428 47371 58100 31672 60523 12425 36779 34323 38909 43473 29555 14788 30439 40720 48523 5190 64364 57779 38462 36291 6164 48904 38308 29239 18196 24991 51548 38872 16240 15778 19329 57480 50160 29067 64252 1875 3629 2421 29330 51063 60419 49761 33038 3997 46873 28377 151 6882 62463 24846 58225 20324 33926 30983 10940 46815 37544 16165 47647 12007 21436 45040 56764 43493 18749 41456 23605 44013 54363 29114 21208 40290 51020 52381 29601 40174 6300 58664 7834 50925 1128 31163 56704 26903 56945 53978 40906 33741 39099 14802 5088 46165 17221 38971 1128 37022 41628 41939 34273 38157 8388 36263 54116 54385 46141 0 3474064794 +768 29657 48419 17822 54951 27875 45215 33548 50594 5955 49532 24228 16299 58028 15723 14842 60198 903 31254 17318 50075 63238 21111 6364 6510 60461 33932 48243 60240 34962 30792 60165 26751 39521 26894 32948 11515 12663 49629 23617 21334 38666 52900 18280 52092 64492 9443 58790 14575 13322 30526 59880 4651 3617 34164 30033 23134 42114 972 6351 28776 24213 51738 33187 2831 7401 38549 43387 45066 1651 33359 4267 57362 17762 35694 939 21300 19881 3652 42148 12650 62597 57322 17404 16139 6795 3255 29449 24616 38370 20301 53813 36157 16727 49944 23888 49020 41525 30133 28987 33944 53326 38432 24845 30050 5052 3924 23845 8386 42978 63952 59082 41029 47581 61925 18536 49125 34052 24355 29664 63856 41043 49257 8134 36887 19181 13757 27525 6171 53738 10618 3417 63061 3758 58766 17759 58091 38147 35036 50411 41550 60005 28419 11873 1545 38796 16734 7539 36449 30002 50851 58883 40330 63999 62537 2173 17591 21332 55570 56563 45991 47896 52373 46012 50671 16062 1540 21246 27186 42066 424 16611 18056 38945 34914 10674 46260 34774 10141 32851 20390 22964 9951 24066 3617 27650 18026 57852 8730 49691 51048 14110 62506 7816 15183 63753 43230 49959 16407 59472 15576 47156 64051 44307 27481 16888 32941 2101 17914 16303 19263 27662 47906 22775 13360 44776 28257 45893 8741 35450 26416 37592 27875 36564 41358 19584 12634 29653 15238 31142 45126 4927 45307 29485 3733 31406 53065 60883 35074 29343 33773 29708 46573 51445 44536 15032 4585 19191 28909 33009 20236 33496 25217 44321 16992 62478 48220 26494 48384 8871 28310 30152 34830 48071 14276 42798 40521 30543 10856 18940 17700 56698 29154 50489 36534 10177 59893 24145 44582 57473 16112 37946 35316 37749 36113 62309 39836 54047 43046 8002 58793 61283 19002 29268 8236 2362 13920 33772 39839 7867 59973 1302 18088 63712 53940 17866 5920 44208 35693 23850 51834 51176 19797 15898 57725 42633 14899 46826 38880 43842 60728 20374 9509 43857 27754 39419 463 50982 48510 13690 61939 9141 57277 20606 43637 51549 32840 3631 3965 25305 35247 44028 55524 12170 17510 51937 59195 57593 6723 24904 12953 29481 48802 45438 31521 58189 44380 12839 45956 64260 774 19893 53840 45814 6629 36742 52758 20569 61299 58484 27107 28299 42205 15299 7708 55057 21120 26862 986 31347 16662 28192 4750 45114 11146 29852 62531 27259 46076 5062 26896 7040 38925 64257 30664 59512 22924 23365 49124 27827 62401 60215 21855 25647 5684 30047 64452 6851 24561 1694 6901 12740 41387 40608 13320 23546 37870 62159 47919 9273 37240 29824 63672 57212 33447 45598 14258 52907 35471 49453 34181 57584 31039 46254 15620 58834 42241 50314 43699 19792 10411 5883 53363 8298 51540 36830 14664 37852 6303 59079 56423 1932 45986 2507 8808 36195 60030 63165 54182 60120 55406 62229 15325 24732 18793 21671 43093 43939 56041 49159 7227 27361 48473 49470 19613 34265 13684 60321 1819 24746 56479 28653 21251 59810 17025 4430 10871 63133 37673 26648 9985 47301 50170 45753 57758 9038 2490 15872 42856 47354 47512 1569 47732 24955 60826 39247 56162 1139 24802 42167 55034 63965 18940 23285 25459 48807 26096 54909 5514 19056 41305 57281 40840 54489 55087 21754 34068 58016 36253 8931 17822 57013 42153 13847 55907 425 1153 3952 38721 46289 12035 822 4910 21222 35396 49772 10415 64386 40743 14554 43442 43366 48197 19594 28068 13466 24532 41505 19308 50789 1703 30544 43822 18625 52556 49661 61900 14448 43852 14432 21074 59586 1097 44332 30618 39227 35358 41885 8244 41648 38280 60443 29918 22072 16218 48095 33217 13369 14276 41132 31633 19894 17128 63158 10656 33342 37559 29383 7085 46373 56609 38259 16404 1000 38487 22182 59580 50224 39701 63391 61569 33400 18925 52600 21033 31296 42644 41846 23055 3096 46137 26772 20920 43708 37673 37168 38074 43822 59015 31642 58947 60722 17403 24366 15545 27844 23660 56276 36992 19562 36613 54128 52174 38797 58487 7542 30201 50030 49905 46940 41998 30605 27719 51809 58750 34370 52964 18121 43685 6607 26698 26959 28267 15997 12706 34408 10015 38225 54230 2123 60863 36715 42873 7543 362 29724 61561 18618 47560 16587 37927 36104 50503 57790 22725 41367 25335 28758 51382 62558 59632 59642 56519 45238 34571 24988 4029 54539 6430 53250 23076 23263 59161 41289 48715 26914 11998 59151 61253 59579 1224 17063 56833 33103 14719 30674 39233 16555 6239 60911 45822 63898 23978 8086 11770 44676 1704 53685 14822 27452 24799 27681 37377 35442 19291 58815 18072 4620 51682 51935 21522 63700 6977 6682 34303 7385 26011 34101 33323 59865 10329 5854 46355 57629 59541 48068 5859 55746 39925 22799 58602 46201 55398 9517 16500 24532 3137 43281 48454 51803 59433 49266 17253 7103 20424 44362 38322 33105 14164 21090 35627 41352 48500 17200 36854 43625 40001 17408 61126 47055 45919 50129 27478 7493 19240 12165 34614 48105 56275 58339 23176 45826 45195 14089 58464 6873 4221 43711 34160 2410 61590 16936 37476 50162 7286 5280 47185 33771 26104 5788 29466 10479 41905 14473 24747 46021 60711 16488 10532 36612 62454 48003 825 8135 25157 36534 44782 9913 26309 39872 39869 48311 52634 62377 40044 18075 22810 43163 6569 62340 53467 47410 1452 60355 38216 22992 36575 16200 63058 40002 34962 4581 44490 53716 60256 44132 39536 47603 46771 34943 19456 22451 47908 10779 48965 42095 53231 3369 384 60392 484 51617 39247 55657 33613 37541 6992 14933 61155 17037 48683 55721 26714 3927 1527 42170 9248 4170 37532 3597 49898 59684 54503 19375 51765 43985 30112 47563 3234 31393 27796 14132 39079 54020 57839 8814 19467 37117 46981 49957 27878 16207 28862 35166 55327 13189 55626 19781 28730 4685 535 20257 46982 2058 63520 62689 13160 59422 49373 40648 49115 57109 41009 1685 62173 51720 32807 34451 11672 2855 7174 42027 47001 37218 59899 58688 11341 52225 28667 3138 2331 30216 51529 21539 26546 5235 933 34635 9948 37872 12423 64267 1408 9113 48829 59023 15775 40659 33772 1534 3348 44422 25020 55174 30270 39967 56253 11233 53206 1513 32920 295 20722 114 22251 45108 39422 6350 57165 5386 9007 10690 42547 51991 60975 5233 55588 24744 4741 36449 19821 24160 20217 49896 16322 40951 42516 21747 26275 4282 2305 51175 9147 12939 39100 7035 56274 60409 54745 810 49129 15139 11918 1791 47178 28067 23084 13402 57103 42386 1260 11268 27085 2843 31412 54526 59303 24364 23103 15010 37714 2707 53266 53205 37553 30563 55222 44344 13950 1787 9275 54113 62454 4096 41128 1704 49171 16433 11645 16434 40583 43143 47489 47282 39787 72 41400 7768 27536 47231 7747 49011 62684 45611 24095 35172 43934 27822 58528 38214 18571 39575 46723 60971 7029 54574 36321 35331 55146 49382 42629 16748 38102 10347 38419 13266 20100 24056 4995 5023 6927 62126 19265 12692 8466 644 18233 22293 64114 21828 58781 56053 29330 30733 55076 20765 43944 10703 61369 38478 37936 35871 40623 42661 25387 58314 32934 11976 50251 5141 43920 49043 1409 49300 47911 39400 26306 42270 20300 19628 26851 59759 20186 38661 57974 4948 35129 49496 61310 39200 51128 60349 26914 11207 6227 331 14795 34003 35660 24967 1325 20189 42635 36230 55788 44932 27008 46163 44117 3694 10191 34773 36543 36204 54138 28316 4512 3946 8472 40919 12179 42266 34710 47320 11442 35765 53084 64333 10899 4942 7608 44096 8136 10392 19203 37721 1031 61019 33925 6835 10795 47058 33493 58865 988 1665 948 17813 58145 58708 3193 22726 55227 45737 45424 45001 55967 45917 64100 28265 29887 54357 41692 63740 56492 12568 24212 49897 33309 48421 59443 2726 35496 9626 36324 2287 34540 23401 822 61278 52958 14125 1758 60466 50143 44975 28779 58307 18379 55973 755 38939 50243 48431 39903 43213 4532 10920 37151 59802 36780 945 30035 14211 62969 6396 42212 23724 31660 1335 49969 26824 2619 44627 21692 62870 60527 25186 20805 25871 21676 17746 36008 24382 3977 46769 58616 54753 30604 36327 17463 7769 29907 19231 19821 44588 41739 23871 49207 34353 7121 12485 45577 21436 10409 16759 48408 12860 49268 57117 43962 24706 63085 26773 56346 9712 13714 60646 5487 24619 56182 13881 63822 24311 41964 18528 4638 59298 13818 49327 49560 21599 26157 36975 20282 37031 38830 27846 37526 40796 1084 17874 46801 59719 3768 17177 9978 54785 54029 32997 13731 37037 18539 15088 1820 20506 20833 14789 55198 56477 13638 9336 27574 38131 22685 30415 6598 49580 38441 61761 30015 12013 25704 62151 46550 44669 4750 20168 41987 24049 17371 20001 4373 13950 36360 48542 26691 1978 19453 30357 17183 53013 27829 42262 60581 16639 20075 53238 3983 63735 38461 9003 56849 9918 21974 51124 56230 37140 57491 26980 6885 44465 18056 32910 51173 26047 62863 28062 38766 1427 2899 21780 37887 7979 35222 38697 50500 58962 1930 48934 40861 11305 51599 54785 19208 22592 14439 16038 53790 15030 37975 35840 57614 30494 64364 41714 14248 29855 599 20496 23778 7419 13011 47184 56079 52194 32953 34835 18500 54858 59034 5288 21467 50659 7543 4465 25586 41632 41413 36257 35378 38769 43084 3068 55045 13350 25271 46824 33154 59413 39426 822 25076 19122 57884 58439 6137 28109 29789 34287 61765 40863 23887 20709 56086 31631 18017 44406 59500 47556 58859 59810 11793 41061 54107 12437 12807 59135 62967 9335 57621 55694 4286 27316 41478 11737 53340 38027 6573 44317 44249 28185 16713 55022 60516 28615 59271 0 1288284672 +768 47996 38077 52378 10377 28402 8928 19294 56654 51272 49054 44481 10857 19342 15962 52914 12293 14293 18374 55895 15924 62671 8344 11018 11368 200 45220 20961 62844 16208 30159 42275 47923 34456 8252 38118 19585 34664 375 36648 16558 20719 49162 20268 40705 57778 19319 44210 62731 720 14139 22838 1401 28369 33782 53111 33755 55117 54771 37212 62821 27548 25036 13143 8631 34549 36563 1206 23496 16238 23362 11540 29844 15251 56041 36168 11717 38376 16588 37462 47397 23827 25419 43944 20606 14615 32906 54799 8153 39413 39343 33441 30406 62778 40763 11920 48951 33582 27709 20161 59142 60031 4344 41577 11227 33903 48287 23664 33727 6394 44798 42927 37855 63203 62758 29353 62721 21775 61326 42702 27601 38588 54606 53780 24233 60425 58256 35387 49045 38716 6025 45753 11509 37035 35840 24539 5326 37717 35503 30374 20488 21289 37378 14076 15853 29859 34502 61464 54312 384 37943 30658 34887 6573 24000 3104 6858 16567 47318 18225 38336 501 59337 46189 15320 10859 52638 64209 9217 15212 31457 49677 19394 15242 40115 17139 55362 4145 34726 59540 24446 24538 64004 33398 36378 34572 11496 3991 56843 59997 42955 61949 41951 43196 39536 12125 9191 51876 55826 16556 41580 48295 20322 56864 63623 33912 46357 38220 41025 8726 20753 57819 18877 60306 59644 62832 6061 6673 9199 10810 27824 40415 11052 23532 20798 706 13675 38224 34095 29259 8420 4379 60887 15489 41133 41499 47878 57267 47915 34705 40947 25916 36000 20953 27864 40670 61285 28291 50426 33912 52301 58868 44109 19409 50888 43198 46798 10415 16384 55378 36663 63117 26987 6202 57956 11142 17840 59205 39633 21896 50242 52112 23122 49473 24734 27639 21938 23956 11742 1716 3841 37954 29628 55297 45741 47218 13682 48877 25282 39707 6323 1259 12581 38121 53002 39640 37789 63407 63971 23316 51928 45557 322 7960 5397 38304 6249 18776 10454 1685 19531 27450 55127 27417 18072 62241 48645 24036 27689 42401 24426 23765 57012 36145 4133 60172 33647 29488 38642 24017 10612 2109 19649 62734 9592 30682 20189 47254 63861 62983 46256 38397 41821 55425 47669 15070 27600 27271 30850 40812 54404 44732 44846 4527 47160 4634 34074 10682 12037 43989 43644 11026 36016 7650 1103 43809 28931 48100 46217 54905 21588 1272 17658 55758 22165 61078 41338 33867 23888 50932 50015 17562 43484 34429 53543 36569 61314 10801 49729 55942 54557 27118 8928 47024 56276 47085 40384 13788 4050 30493 12523 25316 26081 23062 61737 53810 49399 57828 27731 29846 58164 27954 10213 30905 19935 4875 22617 8236 61251 34575 44937 50273 26474 35099 27838 63061 22516 29987 58984 54508 58074 61798 24953 63998 25239 27224 26642 51665 36575 4643 25323 26434 51872 52615 17395 43886 63356 30708 21322 1531 27788 45371 27021 8463 45454 50761 57801 13314 10145 1837 24806 61820 6892 40333 23307 59973 24967 26506 54569 28997 20403 49641 27549 22603 6090 39427 44181 13204 57988 33278 64226 21750 50719 41090 42791 23179 44795 2058 57246 20262 45499 23171 29893 9935 19727 19443 33558 21244 7845 40298 28596 36289 40968 63193 24587 35992 1754 7086 55085 50889 29766 31635 48134 15606 31113 3787 60551 8990 48163 49927 51273 57773 23313 23848 39075 25698 40735 33908 37049 40905 7975 52691 25292 25715 18437 55710 53116 37227 22695 48441 53138 60175 1276 8143 61879 52612 20021 43361 2550 54634 46687 15970 37189 12663 14833 29136 12195 3613 48778 36333 51238 23436 54819 10770 48053 11798 29062 36137 46993 7584 3114 6928 39122 41425 6339 12006 14515 31020 48385 54309 17016 49119 59187 37709 16222 30458 59303 24150 46951 59531 1069 60532 26018 3405 46825 35040 59400 23486 3273 12832 50656 42459 50047 28091 39387 57502 13798 52579 46916 52301 18961 57458 12906 47852 27997 51543 4252 50831 22923 21313 62895 38798 56591 43416 4638 50581 18922 2603 4683 14817 35194 17131 27223 2200 3127 34622 34295 61913 27321 59797 46160 3565 6859 22627 64222 5052 58195 51293 53820 4886 49822 24433 29461 53751 45757 53136 59135 34424 2895 14624 18783 16573 49767 22190 33925 14726 52868 19857 18486 45878 14139 16212 42016 58366 37899 44207 53855 2050 49226 11578 8112 40002 61823 63514 4572 43345 21801 50196 60275 30326 46584 19915 49423 51770 35833 27047 42622 27792 15006 7677 29055 60820 55798 39536 57535 39983 62110 54428 44578 37671 35077 54837 56796 15667 6663 12339 46064 10744 27299 8405 35353 58622 14342 46294 59310 61239 31083 57987 33441 58389 25350 16841 47066 26499 14020 49241 28872 62520 50803 9708 62722 63886 41226 52575 42544 5863 49279 16123 29651 14119 35314 39712 63794 44784 16281 5667 10720 45256 41300 17198 58831 1921 14763 42303 33898 21010 1729 52958 6110 11670 15331 15457 30680 9456 34910 9429 23964 60076 23536 14671 6626 63496 43601 25794 24409 36233 4108 26246 57035 35364 17559 17413 62908 42942 10818 23343 59009 6282 10589 58824 31165 14459 58176 50578 30395 5228 62481 49614 53192 14157 36265 14082 25739 12164 59512 7496 34990 23449 10664 10180 41995 59778 24217 46403 47755 29537 37828 59612 42040 20900 7775 17826 45789 36304 31383 17649 59570 33075 4107 1311 50905 50775 59779 14564 35784 37222 29807 35941 52086 20533 49047 52506 15284 54242 23098 39655 53585 62277 8149 29836 18637 14077 47516 8024 50150 64288 15753 52591 56356 31564 59770 24491 55576 58997 51989 63789 43974 39690 41008 26028 27150 23963 27772 11600 45692 62825 22438 55627 46635 22562 15582 27588 4332 9750 54212 27483 34854 42084 51495 15668 13907 6235 63818 62108 10802 25207 26815 47514 47961 29689 36222 60631 34325 1884 58073 28100 8295 52829 41705 6790 6108 56394 59202 62957 45824 54528 33590 41999 53328 27942 56888 17632 58616 51859 26051 5911 45360 44832 58056 56099 49767 28456 17743 30838 4887 25117 25359 27833 41452 57283 5993 48233 14356 8266 43669 51136 8428 40332 39841 24454 17132 57667 40843 28175 53137 27805 39269 14832 8182 42373 16542 56719 5672 6650 47801 61729 54733 39834 48662 13925 12671 7284 16492 56216 35240 26833 40407 57986 18215 45214 57116 37174 61752 57387 34427 363 22199 57411 44628 35281 25647 19574 26872 24232 25064 24666 14177 28487 26013 43095 43508 54200 13534 43192 46330 58167 24087 29856 12057 25768 5561 21194 35797 25100 13663 29846 52533 41634 41771 5729 29075 52028 5168 58336 5621 57595 12185 63560 13705 41269 47036 48233 55817 24024 57588 12353 42586 31313 52180 6446 1921 54132 17410 8854 38621 15256 40661 18210 40396 25669 36626 5115 10041 41043 27266 28529 20863 28809 28800 6131 63603 31090 50099 14248 59673 42220 61964 22524 9110 44724 7823 9998 22834 42196 24585 34601 21763 52450 3461 28096 58206 1871 11163 49835 14422 9351 27833 40230 35871 26949 25662 62122 25272 64451 6066 37752 7280 3208 9775 4399 43474 4480 52828 47130 46727 28814 1261 23618 55032 15845 25229 59602 44426 63322 35677 44998 36637 35914 45060 19549 23009 56990 16109 60733 20663 24195 31605 43094 37095 52639 60907 27932 55615 50026 22015 20720 51116 39227 55523 59817 35141 36956 43834 51407 37116 11577 26824 48015 58296 27938 38927 13110 2101 39618 59506 16495 60315 4433 64188 50626 17522 50140 29556 49437 63737 9725 24515 62498 10926 48591 38981 53016 30033 56608 50323 1071 39863 43811 33707 6959 48135 8255 23605 62688 23270 24008 37129 12977 36122 12808 2142 6503 35528 58381 40860 6218 25906 34762 9797 40496 62299 58592 62942 48101 13449 22524 34780 14460 42260 21645 24804 35866 28709 29545 18449 52007 35351 47872 38288 49862 42678 17873 44609 1503 28316 8454 11298 43952 22815 11951 59065 59116 15811 51900 40856 1658 55285 59255 45476 42436 10121 31037 31340 25927 63835 29514 50552 4980 15397 22616 15699 29498 18260 5938 44693 53376 12517 52520 37887 22288 21576 31412 39400 23383 32891 7934 55959 10984 22502 3720 33056 10994 19438 13530 26420 26115 4015 1592 52725 11613 2820 11987 47798 25531 27708 25093 14473 30328 17294 62546 17273 55374 24193 24992 59833 27781 21489 54303 51235 41451 3753 17965 31394 25263 11629 886 61425 39123 9049 48354 17632 23503 60336 24748 10898 37854 22814 5485 23019 55732 34504 57060 41438 34846 14625 30102 43870 1052 55394 26993 18045 39767 29119 20288 18254 55481 24865 25692 19813 52755 43414 11721 50832 4902 15558 18625 56668 19734 31013 52284 61312 32998 37672 13429 28042 39431 63891 25729 54211 5075 47108 23911 10773 27758 24806 26378 62558 34184 47129 14289 64250 22188 55037 3652 63427 12404 22872 13894 48413 57809 36282 61568 59929 63686 53709 42387 35716 60331 15633 56595 26763 10440 28830 30761 19049 36223 22061 28471 50220 8100 60939 31698 59760 40944 52441 48411 16781 39047 21702 11935 41325 43240 36357 32793 33361 20963 59558 14624 5509 64422 43821 10593 931 36209 54513 51089 50335 28518 787 39532 64083 8491 61631 44440 606 31208 61382 22824 45429 25909 9423 50322 40736 15048 50639 60236 46792 11324 56243 14989 14290 45070 13785 1087 25766 26739 12542 47110 16266 7551 41029 26840 33944 3781 54135 35111 26278 47772 63935 45784 52138 17823 26760 17009 33024 9349 46625 16784 29336 43114 63521 43538 43562 2283 35802 49394 11540 13594 20613 3235 43583 20690 43620 41275 53987 59549 13673 46563 54197 33414 6881 20558 42724 56414 1092 1552 7090 27283 6860 61830 9574 7142 13291 37572 47094 22555 15939 59000 17448 6606 14110 17220 48481 19626 53020 38408 38043 0 3481306067 +768 1947 11082 50373 23535 6950 57315 5340 25471 31634 31328 37380 60316 14214 37089 39618 54313 55681 6434 27637 11612 60815 61799 60074 27754 6148 23818 14454 8695 33133 30564 31393 53802 51560 1745 64149 50278 50321 12556 60443 8855 20338 42913 15093 24388 22237 6461 37218 48037 33246 28921 30262 45277 47245 34681 39155 44616 12969 17784 8066 30542 1233 7067 36309 52185 46543 29532 58818 41827 42258 1540 295 57314 29765 26875 29059 58327 43443 12162 26800 3285 31655 23405 57772 6873 54227 1851 59089 6736 39673 50490 55958 20540 10046 64095 17680 16464 11243 24575 38556 16058 984 16330 938 14194 31142 29259 57908 18074 30251 40938 31085 51056 26111 62495 56409 11388 1817 22493 55004 55597 59997 3763 19310 51087 64167 31222 5467 2622 30772 52858 45812 24965 34973 11938 36300 39134 51951 10069 48706 50507 56873 48419 33 60403 7388 56496 39985 24306 49566 44862 56375 8414 63231 44925 61042 55746 49954 11997 45080 31172 5943 50185 60163 11542 61405 6478 18607 41863 41782 41648 3348 47538 7972 14915 21768 37981 42636 63227 9643 63459 58087 43007 64444 51305 17399 55836 25763 15373 44940 16002 19845 36981 30928 62617 57721 49630 38068 26567 20864 58202 5338 57491 40861 31455 10201 6262 19768 31413 9199 18622 19630 61062 29063 34089 50911 55847 30386 56279 12770 5755 9360 23230 26904 56825 56735 50563 22865 4455 4560 35231 32963 25435 15261 62488 36045 49358 13741 28086 1917 10594 3252 909 43225 43787 21737 15835 51875 58567 34857 49694 52520 36123 20076 38960 21427 28909 52526 28605 4175 21907 6981 46233 56084 9387 26916 31326 30280 48082 7419 23463 55989 15616 31628 35835 5366 33273 39391 11986 17832 29527 33492 12233 38382 19448 44608 19849 47070 3374 18872 29468 24758 36171 20978 6545 49429 52711 620 63007 2523 20036 42226 37927 3342 63813 55799 43392 25598 19855 29869 33346 51777 25468 24462 34297 1946 35708 16021 1437 13443 25248 26985 59051 54553 61737 57670 61820 8835 17812 13923 18669 6235 292 64122 34148 16519 49161 39275 31685 50508 45252 38865 59538 51244 60479 31055 45630 56126 5479 13986 62114 6175 63862 1640 54591 3594 47481 29281 13000 24962 63278 4604 22559 58557 36627 39587 62330 52565 45953 60273 29243 4131 61359 18906 41935 34676 4270 536 53300 217 22087 19621 46813 8395 48422 9668 24406 57558 41928 34847 43312 13765 35250 8937 9451 54183 20175 41351 61533 27921 2824 45127 45478 25456 24568 38242 54057 25420 16528 18191 10891 43924 33647 48233 30309 37427 21351 4659 26456 22826 31695 37797 1455 55153 41770 28041 20282 30892 3454 7685 56113 48136 13799 25558 27492 31228 25934 28943 11318 21601 19489 12134 38915 58174 42608 40453 23338 25811 29489 27293 51341 4929 60909 12916 38377 40621 18126 60422 45944 52001 41644 19638 2024 3403 42348 56818 28364 47736 63493 16771 21957 46518 21995 48597 4352 26411 12523 55316 28076 61486 49150 13323 53742 50548 51422 55952 9346 33061 51478 22203 55868 49554 3252 58362 3226 43465 64223 2664 50633 58243 24078 29780 46093 56620 37945 35293 942 56005 50618 1412 22409 59044 28908 28269 16901 62263 33947 60810 6014 38862 11289 63707 7792 14817 5225 25762 56020 10982 5435 50957 12478 11429 33060 63656 48001 55608 42792 35024 12558 47805 49303 5632 59952 52399 4963 47064 8367 61606 44628 8846 46253 13902 37760 56419 41182 5979 12620 31312 26998 35360 9800 33389 60326 41800 45810 6342 59424 5860 55355 52983 30598 19782 16328 233 17091 24966 3342 16683 50999 6279 42731 44894 19588 16814 50314 49712 14296 14497 44329 19688 19519 15925 61486 55583 57892 21813 11360 17399 12097 7163 46600 14133 62465 37464 59620 56830 15936 46528 43272 54432 60813 33762 28776 17492 59350 34423 46548 14509 41260 57358 59367 18499 23150 48340 60643 36705 1916 36522 31133 46496 31302 42550 27477 31 40210 51214 53638 35254 44058 26273 8755 51640 47058 9534 4712 30957 24132 27340 27608 5302 15268 46798 8968 17744 5245 7990 48827 36148 63752 23938 4052 51844 57504 1972 28806 56308 37889 45941 13240 27422 25567 54587 58360 34569 40515 57298 39266 47878 651 24872 15791 48232 25417 12385 3128 13013 55319 25411 8336 37544 52086 42818 19824 1283 50760 19805 33368 58265 35525 21415 51035 52934 35674 61352 54637 48610 8116 34658 44713 17655 28894 18393 63027 6070 43548 35504 50222 27787 24190 46157 41672 29231 36287 42785 54655 24773 21262 7910 14246 18287 8269 51151 29037 17751 11185 36329 7160 18866 43137 2429 20771 60799 50135 2756 29520 34198 30538 7698 30299 21042 59786 37302 22775 29294 9857 1885 646 48630 49751 55963 23681 58151 25462 49356 54116 31492 35533 9783 24802 53935 14381 5092 9296 4803 21566 10479 13077 56228 40206 54022 14955 45173 63250 22345 15685 30204 48591 21086 12464 28240 9088 6845 43517 11325 18804 56477 42283 17769 13872 40033 33245 18428 62033 63386 52884 7643 42836 12606 11453 31676 10073 24732 11953 37292 9892 44349 7641 19541 9028 49617 56629 25147 23968 54108 30589 47892 12638 61564 18851 55574 9635 39951 58416 46433 43162 19577 33401 8400 2582 44060 9196 47823 21313 27065 57544 23938 52746 18489 44590 44772 31719 52822 62226 52993 52225 4837 31004 34402 62338 23188 11155 302 38659 1919 33896 5293 12652 8852 27684 54641 6497 58354 48679 27154 16330 18959 23493 2742 45546 39252 2844 28893 35267 46865 52755 27050 9520 23263 39104 31042 26253 60772 39699 4962 36199 36052 21794 21405 49371 11992 1832 35645 11292 39196 43620 44578 63908 34135 50296 18801 1770 1927 53668 33303 28005 37522 22102 41397 407 13777 49175 48507 52997 9665 63359 24557 40468 13002 19100 12394 54725 44373 40009 19238 1612 111 7319 46620 56063 19775 56240 6601 43763 26991 6173 56035 47510 11284 14495 30837 19695 20987 61661 21026 25777 749 333 41520 60185 34082 34182 47537 46596 14861 16086 41943 21428 63909 40537 64212 56742 57555 55509 49825 7013 18850 796 4441 39215 18395 29040 28608 9952 61333 46833 7184 9663 11510 6911 52145 61627 18742 60417 14415 59310 9231 33850 18064 45783 11074 1348 26589 64096 47069 56088 51820 32946 30005 22526 61036 15297 21089 21088 18599 53782 1997 62738 22244 27884 28920 55621 22338 60822 20035 60783 5522 48291 27072 23456 43125 28839 44468 16118 60283 37669 1335 54950 27636 59465 55708 2775 14726 1344 33057 26723 62063 47768 45980 62721 37938 46361 38398 24809 5778 59252 35427 55626 41449 12382 45205 28421 64402 48186 21953 21925 960 21359 9272 924 54860 13580 7371 8495 52763 22115 49765 39193 48417 48024 15734 20127 6937 2695 46380 12265 51425 20280 37761 26183 43659 37495 42049 11883 16153 3264 45641 39731 16001 21435 46196 3327 10623 59829 21812 15418 9153 32910 22793 35440 56390 33235 51839 15017 3827 9507 10851 46689 6565 16971 27239 4605 27740 39081 17737 6838 16799 22928 34629 41247 28053 54385 31713 10756 50762 42733 64439 39079 29764 41047 6129 25385 38954 13369 16467 57748 32864 26258 25212 41047 19770 40016 248 319 12534 53884 6571 9171 63499 46906 29232 49586 27076 7635 57943 14151 8712 49103 1223 35247 53858 1125 61436 39380 62758 50552 8819 8357 49552 21084 58908 33673 7042 35009 825 54548 36874 13460 35096 10402 53124 4566 38540 1074 22430 25443 62147 45091 43430 17663 23559 19044 53723 49957 12020 22886 34608 6376 50722 17229 20781 12334 34927 38275 62580 33437 63942 44994 35284 32845 38539 51739 47167 8802 40177 30714 61283 19416 21951 37187 24757 59587 52095 41598 35252 51579 40528 45777 46464 47665 45337 55886 25001 30846 21308 48132 56984 5436 57390 7528 47568 56577 51394 28074 48539 27277 26105 47305 22707 40155 48497 28955 16960 250 30891 19098 8017 2272 21264 47936 699 30994 12104 15962 29939 43753 47551 49413 58739 14277 35902 40584 14518 12687 62244 30629 36607 4542 34145 52119 35395 62106 40092 22843 45760 53735 6413 63308 21130 59850 20249 36318 34939 29060 62591 42447 8768 3213 6427 33325 22031 4019 3916 6040 60539 50993 2389 18252 36079 41883 44254 726 24722 62536 40885 37461 27703 39727 25062 22553 54450 7339 10776 61472 618 5696 24341 18144 2938 48250 9342 31258 52501 25381 48161 17777 38930 3767 9085 25590 11467 26957 24691 16081 40533 64342 55536 21480 13635 35978 41661 8332 38122 42491 36805 24976 13575 62642 8629 43245 49473 34718 27334 18703 24403 45170 36914 40116 49392 36630 58619 28099 60580 3799 41391 49639 28224 54545 31699 15433 28769 43419 14659 22615 55547 5637 44527 5801 27796 15274 20341 22934 63265 29464 35105 6241 6791 44905 62922 8714 49865 57889 62841 33647 11173 4528 1872 64003 59320 61775 2903 37174 4101 36527 39339 46338 43639 13399 11170 44106 59183 17361 56393 36185 48708 435 202 17139 60192 36281 29830 56258 30744 5274 64200 48855 27291 37080 62380 57607 2361 16929 13929 25525 33309 27116 15534 30693 42976 14592 51185 43636 28482 31293 54774 31209 55272 20107 23344 27646 51693 10024 24953 50147 2230 27474 30209 29111 7253 7758 25181 20882 36287 25931 6344 55835 61092 62459 11744 1565 23961 14699 14063 43031 48930 18620 4503 51147 33114 41600 44438 7691 3558 49498 5143 61429 16475 25945 37741 61921 28862 24184 59211 48432 13445 43952 44561 61451 6430 6756 62034 13042 62695 60246 10883 30439 26672 11716 54487 9137 11290 5204 48601 26327 6768 20606 28980 54584 0 1317465901 +768 25591 39722 8381 33368 9311 30636 59808 61615 46745 49208 33147 64511 37445 47906 33267 15177 26784 59824 21312 8532 61520 55641 58867 14419 34125 22937 29354 29394 61294 40301 18723 50146 21921 59827 15877 39848 43846 45880 15687 27139 24317 24598 33636 44802 29754 58097 45339 48279 42493 51571 60637 62916 55712 2256 64283 3271 61154 27956 21567 26292 58929 54099 27492 39348 10887 8183 49425 15861 31281 23271 23510 61808 49431 18690 20764 50283 59563 33668 13921 7434 53426 39904 39058 51622 60296 49039 2787 53009 24791 37655 5055 33010 39433 20955 60140 26296 5024 36822 43765 42206 14478 21085 3914 29164 10562 2366 44020 21745 62936 19609 33244 4086 48825 23185 10016 17107 27221 52214 25804 6026 15031 30967 41748 20724 27368 53517 43063 61893 24396 33986 11855 20932 31377 45709 49972 38990 30346 39729 4049 44098 52560 26889 5749 63510 8954 59591 63164 26741 20386 13729 33003 37699 14872 54602 11152 21744 19886 4710 51857 18744 13545 64099 31068 21376 55544 8780 16205 21578 11820 7102 42612 19312 39376 25204 44369 50520 48372 31667 3392 57901 12499 61874 34193 13951 43360 44304 30670 51377 19475 33597 51251 56513 20467 27181 6267 7658 10844 33788 23636 33397 20597 45428 12722 30431 34227 25182 15346 51667 17380 62751 19540 51767 35065 23061 38074 43901 25922 846 32931 44700 35963 63515 63497 34779 23219 57649 5152 48405 38002 58039 8333 44114 39793 17911 44974 48431 7472 41105 10937 44261 6157 50415 24408 17113 13103 34829 16448 35461 38397 64088 2759 30763 1277 36194 9618 44938 116 30404 53052 2108 59390 2919 13749 54074 5619 40994 54168 55386 61313 47147 59017 10861 51725 4785 35296 20759 42422 13412 36883 8540 10726 7269 48528 53381 15905 59463 48249 56242 9586 36884 11537 64422 36679 3176 33893 45688 19324 11661 43733 47116 36977 62135 51206 20341 44025 622 4396 34873 35900 52073 36500 27142 14644 2191 63556 42032 28985 62215 46984 27646 5795 18412 50532 38322 13756 47494 387 57924 38961 62074 47391 26111 8177 42160 34667 40613 22057 26572 37106 31590 63415 45949 13592 21404 2918 6185 43531 45965 17465 58343 45769 4591 13518 35007 41942 58804 1080 21645 58941 51859 58479 6518 61707 27557 56330 12646 43631 2949 6552 56556 24012 51640 24139 14307 41560 39306 32873 59305 3965 57620 17779 4611 57616 40309 50015 8251 36177 19205 12532 7943 56247 53516 53186 35413 60755 16205 58535 3445 58429 45684 14609 4398 54674 10859 19316 4772 45244 29151 14312 627 30683 63098 27761 26240 34811 48460 35689 22634 36894 38124 15012 34795 50679 61796 5756 17852 38245 35248 53044 38056 5120 43927 16133 56173 34991 21946 8261 23247 56993 11717 17167 8257 47683 21313 61291 55275 26469 48743 56230 4628 44216 21469 57373 61404 15489 15525 26129 26380 18372 44803 59460 26418 35517 46789 25274 11208 61738 7469 31145 24776 33788 4126 48513 2951 4688 22231 2082 10879 17199 63989 40720 47723 51384 4345 28212 2764 63956 27044 12678 23439 47839 42491 29094 48529 24348 36076 38344 30318 4365 47770 27320 61951 3228 8950 61760 27293 30811 37769 40914 14290 45162 61359 16270 45704 22941 6764 8216 8666 10262 34575 33072 52850 43477 9547 4884 12561 37115 30840 24134 45604 64091 7306 10985 37607 17691 46356 44996 42283 31606 27404 63260 63079 23831 49552 3852 17521 63573 10822 20319 14499 20718 52501 40120 6360 36491 14745 50432 14665 20108 47173 55060 25356 58395 45660 44809 4434 46267 58108 54521 41121 47111 36200 43567 56513 55249 11072 63430 55365 63756 34887 43138 2657 36049 46475 30619 24979 6142 60745 57960 3687 58395 60824 22055 9976 53357 6819 25819 4899 61971 4694 14927 9026 34869 28302 36935 38702 57548 52262 53272 28217 9111 10904 18194 23776 23517 40237 5499 60826 7585 12893 36678 8863 37448 16422 1871 6020 41428 21809 48642 44716 29811 27541 214 57393 5642 23944 15194 50106 54240 83 39386 7237 17939 52968 38297 36353 25135 57150 38020 40656 15315 15862 48940 12767 20819 50722 26125 39666 52514 2827 60307 41724 38094 43657 30832 45746 43768 36296 40822 8233 50622 53845 14107 22892 4021 5033 46938 24197 17862 2709 54134 1188 58265 28376 63190 2557 61054 3689 42926 63655 47108 46712 62643 42576 1000 45314 24717 2263 44692 63209 35003 37268 7415 39997 45407 43413 19141 6724 27136 42533 10055 45960 21035 53029 36118 41466 11165 40507 43168 13510 24532 3245 39395 17633 53441 2806 19287 40688 29335 14823 7729 15356 6292 11080 53216 12903 13512 33508 18276 35913 44258 21103 16908 35539 26447 41389 2358 41851 47012 26011 9232 52751 62407 25952 19045 47526 50952 57669 46889 55525 61821 18041 54566 46241 24593 43976 7510 51617 42701 7613 53410 15495 56949 50942 3278 49129 50171 29910 6316 18863 11875 62954 1182 52943 51714 2560 17954 14932 40711 52454 61390 13998 51040 776 2151 29909 16502 22317 57535 55980 37150 24543 55358 53975 40243 4042 33483 64122 42503 45932 30551 62882 24497 46157 22498 36255 50579 48318 18785 25902 54299 24567 52145 49561 34651 28961 33261 54707 38162 37778 1633 58554 38705 28482 13396 34719 56347 23669 50782 54061 2267 389 246 62200 48563 10789 50456 42155 57697 56363 3429 18686 43840 37769 57999 17819 14184 3762 46409 26446 16827 49777 29983 43060 11882 18442 1005 46626 63776 17083 31032 34721 53062 57112 22172 24901 17379 40152 56965 60964 45962 10508 17462 6711 45625 15541 20907 23325 48985 21405 17498 29649 5301 53253 5265 41155 60487 53534 51508 17335 3350 15337 570 53179 7031 9673 22347 28548 50940 48306 53599 63939 47053 44860 23420 40718 19391 3129 35344 6067 16533 15343 28031 61527 18724 28296 49624 38201 62257 19871 30175 62670 58078 44125 22597 44810 20237 25108 54508 35878 699 26705 34977 12297 62235 18154 12923 35861 51128 26001 47390 41358 49131 54361 21445 50508 30866 30012 43124 49054 21286 38262 37779 21172 33201 53691 12724 33772 563 17131 1126 22216 59618 60131 14615 22796 22364 4271 42719 56139 55591 5898 63701 27142 27336 27439 29531 16147 44542 53093 26678 53938 52808 62524 42905 37241 49001 13638 22699 48475 19876 17639 11518 22019 12742 13326 59469 33108 52547 10063 41961 35922 34343 12906 38136 30713 35276 8850 538 18946 29552 1065 54980 24984 13442 19654 4952 12858 17068 42279 19987 63676 41617 27461 24881 26302 6783 48965 34325 12331 30540 7012 4810 24631 55039 55758 56396 45923 35331 57411 58954 656 22587 35686 10792 2995 7351 20685 49875 18811 5895 34285 1842 36646 51144 55251 4468 61239 16969 21019 12170 60148 13735 54234 48118 31488 37612 53726 41812 31645 6501 17274 11282 35692 19622 60899 45116 17575 23878 35367 15035 61689 10544 39852 31128 23631 16796 48138 38154 29047 34981 17257 42107 34296 2562 35587 35529 61255 23004 26648 2153 19964 51890 38739 27068 20070 41924 42189 63698 59167 53631 47695 3715 35510 28071 12231 52408 56711 60054 10240 24807 23930 29982 18651 15617 639 15191 14175 59194 13323 42064 19512 43989 15628 53015 19260 60544 5725 12915 34707 48296 46595 61209 21888 46554 59742 56589 54498 38734 6459 42305 19452 57556 25967 22928 1373 40628 26931 60293 24854 57269 28278 6771 28423 63776 55005 8984 9488 8036 60092 14104 7424 30696 41185 3691 26438 54086 15536 13166 63905 22905 22850 52095 7760 42577 61724 17438 53452 56219 6568 5382 38690 46299 35922 38487 3570 15755 21392 57562 1499 49854 38267 6367 10620 50582 29612 41521 40137 615 14335 46201 45271 43329 41155 16020 22831 15717 3590 12646 39419 2145 2465 24831 33072 4027 1407 48518 16291 3499 8297 18672 15289 31502 10588 63058 48758 43565 16612 21705 53695 22913 60207 42976 22951 24989 916 26715 57789 20724 49176 45096 28441 45338 8209 48702 52627 42005 59088 54868 9307 55681 12320 9272 45865 64131 1813 26098 17709 28297 10235 53645 58575 9110 19634 25371 10058 39671 36638 35212 18181 39783 60225 1896 25564 15246 29445 22780 45124 55974 2142 59785 52167 35723 26228 60160 62213 782 45839 23011 48798 62495 39618 22422 33559 19203 6279 22315 30846 2051 2245 22207 44010 9555 19287 23739 56961 15501 16885 14388 30540 28025 63705 36055 39853 20092 417 44413 11986 37780 47163 2533 38079 47414 8870 50124 23339 33312 48123 12460 50072 37855 60006 59556 28834 50299 37119 28721 35156 35236 37975 34803 25101 62221 6764 9616 17551 17011 60686 38636 30682 6354 27987 23782 46229 10016 23613 26687 8001 10035 63266 41454 15793 58286 63014 47814 20490 8426 45133 22645 45909 28895 28584 53233 39326 23886 57701 52770 47367 33156 23090 47957 7715 38279 8579 8139 40225 7410 56188 36101 63962 62166 27899 14269 58434 61103 13638 25351 43047 440 170 49796 57562 39600 20581 24548 48567 26339 4860 38100 8814 32831 12574 41974 51546 4351 26991 14009 41066 16719 26216 27859 56852 34180 51533 15426 36217 49375 34989 13284 28126 54209 18302 23039 41016 26050 24735 26542 49205 5570 25631 22466 20966 51420 36286 40216 51953 2193 15953 22613 25889 42239 31255 64322 36805 53217 43724 27069 50890 28764 16555 44455 53284 27350 8672 38199 225 26436 5579 29735 54873 55461 47949 14668 48707 48295 14629 38433 4001 12564 62151 62007 60246 53721 11376 51014 24782 61293 5820 58065 16726 56579 20034 9856 37133 23449 22237 99 36510 56850 30959 47603 29933 18101 3937 39878 8403 17777 40177 11401 43967 26880 64315 52559 52648 62123 41909 0 1317601438 +1024 35731 51806 64178 62000 41177 7917 28512 46043 11606 25534 11835 30426 3039 24917 47007 8567 3455 57508 40631 6098 31286 25555 62030 20403 605 45346 39245 41804 38708 7062 10930 41312 28901 12177 57911 37940 54169 42378 10981 52778 49839 52860 58822 13426 43927 1298 58364 27690 18820 51039 41255 63628 54045 16 16592 16691 15711 12424 50267 40757 38370 2911 51834 33443 31637 47100 102 21291 2559 43062 34016 13514 38316 59029 8966 14848 5515 39119 45917 60997 57415 16966 62291 43826 16753 41757 9414 35975 17615 45868 19303 93 18290 60002 4105 36841 39265 19981 57783 54348 26213 30944 28823 2420 2339 11763 25099 43095 36097 52043 30981 25647 18971 63344 3437 38532 54208 37796 19981 21454 23267 50237 1160 47815 62079 37894 63806 58629 26554 48107 30040 28418 54246 43142 12358 25916 36 6306 24911 25664 12755 7264 14217 59131 33928 28512 37725 11015 29318 52634 10986 57604 17531 17005 16417 20628 13642 34928 40448 10981 36086 50864 29318 59121 30291 12751 33504 59191 14055 31476 4723 14452 60518 31096 45108 13836 17525 23157 18685 10486 56632 63472 47396 18904 5568 35301 52276 12385 33328 4388 37837 24724 23243 4542 26501 27130 290 24827 5206 60516 9719 50439 41432 479 37620 61483 2289 2827 55739 24738 30532 2517 57244 61604 26265 58004 62664 27609 42812 26588 60382 43380 54850 13186 47571 48554 42189 25097 47309 19895 50664 14131 3921 16474 61513 8733 57855 49076 28403 5686 36114 5 63677 16921 58624 7174 63204 38105 15068 14898 45189 26580 27573 58571 49969 25109 63463 25441 62099 45067 45945 63103 55380 60340 63862 21658 17458 45619 27152 30876 62685 59661 7978 17782 64137 17470 61959 48539 11124 45137 45351 43527 55767 63871 28606 17612 30604 42111 48664 64440 25453 33 30731 3720 46793 40547 42270 24768 58001 45737 51551 36207 63924 40109 429 19074 10172 15582 60954 62486 37535 46522 6197 46430 39088 50277 1454 22123 3304 42436 10435 63821 47727 20565 23548 47025 18772 26945 46162 43820 2916 52497 12187 62939 18701 52773 59828 50960 44208 39813 13926 49440 9544 18617 55354 22620 31612 2642 33873 18057 37922 46040 488 24927 38706 62765 53945 12562 39400 39590 45536 37371 29375 14990 12705 27632 62074 2959 15100 32938 36413 10615 63930 46325 22293 26806 10637 45488 35721 24572 16800 58762 59240 3274 2505 51719 34059 14707 23167 36755 55922 46412 58081 28022 47418 10798 1318 9295 59433 28606 31300 47595 43803 1775 8074 49512 43595 36164 23029 5966 26154 5748 59510 39198 48809 16661 63210 11250 49445 4307 49328 51959 19830 63152 45321 17272 5302 43816 50490 7472 62706 37957 52198 49799 36642 29869 14570 45209 31651 12648 43583 56532 49067 61502 63843 48765 43327 50409 50146 62780 39713 17207 29048 28556 21120 56046 25755 25650 4584 7621 52330 30954 11324 6192 179 28685 23297 3302 37587 17801 9826 47465 6833 38258 54632 33680 7526 57024 39555 25531 60739 25216 47414 44847 50360 21969 5645 48546 9609 54298 63595 34128 24776 27037 35721 38000 48635 10073 34291 5162 30023 14996 53245 46798 37152 5643 56773 36080 35060 26424 15369 37657 61963 24359 24965 38700 4191 61443 52392 13565 29300 8994 15844 3282 29960 24166 64044 49819 49433 39621 42766 52053 63967 26871 21891 49205 15286 42217 1532 40670 19303 42414 55289 43819 35738 20065 11885 10958 22223 26416 37849 23448 53818 40241 44965 23304 27053 2505 38766 19057 56324 46971 26938 42689 21484 17918 57459 10882 63043 24384 52969 1904 36200 3303 54326 39341 18609 31398 8898 52150 22411 60596 34715 41237 61709 36710 10258 36290 45243 41519 53772 19060 31052 17687 5420 44383 2723 5172 40587 5168 5320 43525 25391 29786 5527 49901 31101 62789 13265 28081 16732 2113 38721 28653 20666 30511 27611 46993 28936 62012 1213 41404 3123 28234 8470 52035 22900 40394 39819 36590 35768 51269 63881 34457 7368 63222 42626 6229 55044 19329 62257 63386 29110 49528 46795 43756 55307 58456 58266 16835 54032 48525 29112 57865 39288 55175 21888 2764 27756 24481 39989 45368 52837 12751 7064 15868 24772 7211 4051 39639 55955 19030 4092 18360 42148 33370 45633 51172 7875 54915 40454 30285 41582 54121 2848 27518 51820 56376 12245 17550 273 2141 17288 57120 36574 46658 1908 38648 20204 3242 45922 30936 11425 11887 19577 50403 41813 11373 28604 28105 21606 25163 35986 20710 52302 155 59744 24320 42480 44848 16320 25877 58140 6658 57488 7045 4825 11194 17483 9189 21701 12377 41779 50520 4390 26503 21179 29804 63475 50902 60730 56337 49550 19443 28931 33220 27144 12167 49619 20935 46194 37597 26504 55766 42831 22876 25886 6269 50417 10428 40330 2481 57775 13906 5790 45978 29632 5743 28601 16396 31640 59141 33004 28789 48012 20139 44586 30214 50122 29377 53687 12881 22571 28362 41843 16256 31139 17014 24804 13754 28612 48039 29128 22002 20639 56491 40075 14185 47672 7005 37863 16465 27558 8899 21848 49878 46561 34406 43586 17761 59746 5521 30048 31026 9062 12827 15190 64456 42266 40253 36200 26855 51886 26288 30501 39542 54097 37611 9236 50435 27109 54172 60820 41361 62182 48346 4774 39970 47516 48718 63567 52401 47178 64110 61847 6516 49618 5114 27305 43622 5550 9589 49254 13912 20235 52197 60107 31462 36809 52571 5461 13579 37850 16896 48189 20490 13887 46712 21532 55721 13406 23743 5185 45488 54842 56412 5821 30001 7934 41953 53637 11980 6103 5728 12147 38566 24763 30796 12454 54337 10364 1635 30264 56916 15813 39793 62634 44742 521 11412 9153 8583 52 29651 55679 54248 17100 52431 6735 19152 17211 38675 2705 51328 57013 60029 63212 25031 30511 50396 48097 63918 40277 11958 22305 26178 8801 48015 57557 47146 10585 54565 12650 26268 20238 13062 24925 12557 4949 23619 9455 16446 57083 62045 31367 26534 40094 13322 43745 40885 28394 29071 34951 50731 20206 61732 31150 39659 29444 28334 59247 995 13247 55482 48059 44949 40037 63115 45076 19842 34128 21058 8452 56964 46326 5848 366 47747 42427 44909 38448 36025 22486 6914 37354 54845 24969 32977 48568 3987 46175 51730 17264 54760 20512 19616 26052 51972 27113 51699 55687 38760 47764 3574 47026 14500 24688 12845 34885 5821 39063 11104 43330 59394 56198 9775 26185 19096 61688 40702 53702 40160 6681 21686 34033 41999 14304 43077 16169 46359 17193 47103 44371 54826 11786 21617 59395 12972 18996 37877 34716 36145 16051 37655 983 38895 11002 49998 55934 2663 16205 6697 16535 40141 43827 61627 56017 23257 40739 4315 53301 31337 3301 41567 490 17713 22735 6798 35481 21493 47798 28717 38143 36639 15093 18091 35113 44874 39280 52149 41210 54192 5909 47003 22155 42825 3705 50356 15681 10742 44021 62055 5557 19064 24167 21183 34010 16870 27220 27660 49121 12133 21365 31601 44329 20999 39649 13694 21209 21132 2738 5662 55546 64327 49219 29735 110 61835 20046 35325 25458 34578 39958 26602 61814 23756 44376 36363 50137 7889 51829 38353 49173 19152 58605 52345 42502 18339 55560 29055 5522 34940 10708 47861 20725 10114 452 8393 21356 60460 35608 3337 55932 30733 6523 38226 49521 45196 44335 2002 50929 24911 30639 11284 54074 19779 48143 4258 55368 39986 50863 296 30151 541 10261 64503 1047 56765 59112 43594 62859 19279 51120 33609 39456 40948 39868 20783 33112 15189 39185 689 26295 41060 23863 35917 21516 2323 38403 35134 1806 14108 1881 53477 49371 41143 3244 26688 36138 55299 25622 37515 50707 26638 21342 29379 18781 21524 20772 31652 26913 28682 61575 55794 7727 56480 49456 15422 24967 28557 21792 3504 16454 52183 33005 564 28169 37881 27087 48639 18561 13672 26633 50962 63524 31479 5348 18141 16967 14675 30912 18436 41911 49255 29812 42406 20818 6998 40808 27158 59568 50149 46423 11127 42439 1219 31485 58204 2290 51493 62768 6704 4701 19336 10500 22654 54308 17606 13032 55420 41353 48738 48974 24334 51021 52498 13886 62711 260 38636 15709 33646 52905 938 35823 54724 45247 38258 7146 2705 38226 47984 9513 61368 1488 33434 19174 15850 62125 34905 41426 29658 61096 22180 56916 46242 18495 59935 20395 58810 25280 43047 44255 29648 11935 35378 46867 13274 31251 4201 54697 849 49282 35736 3156 56059 15715 15485 60594 630 14469 22800 39057 10780 36212 53587 47898 53241 62047 15052 44741 45454 52588 294 50696 35668 43220 53967 31680 61801 50273 22494 41352 53271 4293 30148 56497 18958 29834 16650 232 39380 24307 31648 10354 8155 37234 48676 18641 16319 12273 35388 17818 10221 58304 42814 56105 53346 20423 45215 4971 13972 43144 51983 25059 19329 8658 21556 4216 54113 10721 11302 4686 29315 57436 13454 35015 39858 15217 29964 50588 295 311 25958 55347 11042 8191 7634 58203 6099 19862 24774 3326 55516 162 9843 34568 4907 56394 33989 62450 15096 34940 54204 18887 24510 28236 34824 61218 61304 8794 33428 14733 43008 9867 44949 55401 42494 47613 50847 18998 34243 22225 1839 25464 30840 64430 60305 18302 17847 31608 44490 51128 1571 43071 42100 48300 46464 60159 58317 12051 17931 38737 15117 60352 50970 54237 42478 18175 62122 317 25734 8145 20435 62054 13025 59902 24869 37955 3675 40844 10342 3844 60724 15439 41811 15720 44352 24453 19701 53873 21140 16794 12029 58163 11821 50379 33747 21236 15386 16203 5387 12020 5682 46115 53543 42303 38580 39541 8885 11279 45354 58793 41546 46653 28717 61614 42739 30645 55685 11463 13936 17877 61831 15154 42547 29901 40639 24932 14435 52099 54965 7305 14879 45886 10087 34360 61772 58228 1025 46983 49675 15202 19864 3425 22687 24655 58219 51380 21576 27317 26263 60722 48655 34675 29417 15466 38660 56527 45755 4098 62757 8400 8159 32840 61579 4918 11331 41714 1045 24760 6648 53178 57743 31438 58041 55519 23307 28261 12457 24652 35369 59429 22236 53682 56492 20143 60024 52642 38335 12578 8964 9370 14644 18624 43563 25489 58728 24483 3547 22482 54616 24048 974 14068 24594 36377 1160 42732 62482 51664 14685 41861 46660 7982 45568 16614 44828 55639 882 34586 22374 58254 37738 30815 50793 34737 63631 58887 44629 3459 27840 7606 26303 1215 2802 57536 25325 9907 52587 60922 35397 56587 43767 7316 2561 35520 22339 47225 38377 38609 2958 23018 62211 33852 49277 25009 46327 2888 11384 36070 41859 29900 51450 51229 64400 14584 35287 44401 22117 12002 2190 37428 33505 55444 29343 14036 19012 45707 40945 39762 37737 33691 46275 40173 27096 26382 2170 33683 7489 43220 37449 2710 38827 49371 24967 7839 48983 44676 6787 16100 8752 21032 8426 63370 64351 44994 62239 34555 57580 41410 23596 26860 36799 55248 34175 14613 52032 39218 44364 9044 35398 38077 27145 16106 50481 45479 63592 1737 27356 5436 52189 12143 21484 5393 24690 40756 472 4175 29163 34430 37887 56536 64396 38531 48371 62742 60021 61958 13215 9430 11195 3969 6055 44212 16720 60519 15330 62402 37277 54801 21068 36573 23390 942 25682 49330 12278 35853 57035 62796 49846 15316 13929 5656 33984 58047 53700 46561 16218 61503 5560 48159 40237 19423 9985 34280 47512 18738 34603 63934 40860 60710 1173 21463 2100 15625 15233 37058 24266 37194 48329 46658 54828 44047 63830 59371 14275 18374 22302 58253 62320 61835 38715 25573 55589 64270 13003 53045 18902 6091 3893 9911 49938 122 30913 42826 49236 24234 38821 20332 498 11308 30020 58316 62228 12269 47431 60420 1543 6811 11103 48906 60866 4344 741 48448 45868 57931 13646 49862 8685 5595 15974 61869 28708 27495 60156 24786 31674 10953 52631 60026 39298 52450 51567 21361 52321 19920 6266 4009 29302 24874 44150 16586 34824 15716 4308 8015 41381 45389 26352 43589 62219 4723 44817 59226 11606 59609 62128 2735 24351 13740 38122 56226 56345 39037 19039 39426 48205 26299 49042 3702 1352 63407 780 1493 3696 17284 21142 11899 3001 40644 18347 13524 48724 26588 54083 44742 3388 50720 6503 14512 1526 52461 64119 40106 8895 1668 16394 28050 40349 28424 40637 50374 64471 33824 6937 18427 24330 24822 48742 39515 60410 43684 21989 31692 40423 22158 51603 58032 23629 58817 34690 17422 48273 36294 24682 58114 41796 20337 33745 45118 53492 7990 53377 45705 26205 915 40440 33341 43916 29258 50795 43102 1899 26196 37473 56 8179 30120 60045 12272 58416 19206 33086 32904 15790 40660 30556 38623 53432 59201 63793 2564 7441 44541 49155 52266 59374 11253 24604 35511 35522 44358 40835 2443 36635 8649 34189 33995 63868 35667 34202 44778 7657 34387 61213 59894 30566 8404 48111 30510 11207 3893 58931 56122 30465 6637 63575 461 21601 8932 27730 3497 54096 49623 55539 0 1324321392 +1024 30622 46503 38507 10427 53951 11167 57806 6770 11015 48875 31044 50020 55461 47375 38045 45447 6227 35817 15629 10876 33598 59890 61923 40665 31131 39403 19656 14759 47290 56311 33482 13189 14447 1202 60745 49050 7966 3709 15445 28139 57216 35284 50097 7311 60512 6784 36532 17239 51037 56686 33886 16067 2098 55412 56891 13651 50734 617 14287 55751 38793 16199 7352 56819 14526 11118 44608 56647 15996 59998 45116 29101 64350 49580 52754 52172 36477 63475 14622 36509 28271 46776 19968 25622 13270 39146 62154 18425 12616 28115 28902 40223 49321 31063 11985 44486 45068 22876 18476 13790 1672 36116 42340 52634 11435 10554 21868 6758 20008 49451 13869 48304 9296 2211 28904 17436 46673 17122 4283 1076 33807 20956 45083 57962 59312 7687 62528 8870 37233 9937 21061 34857 62695 8803 6571 62523 54911 15653 62777 54900 38173 35060 60037 28946 33201 21937 47698 58125 26051 31134 11689 7036 52699 55623 20091 44712 4485 33264 60340 63988 63757 40848 27967 59359 54069 24427 50234 55135 25805 25834 48246 12034 49787 61445 9218 62290 17835 43059 56993 32973 28790 12270 11150 15154 23702 6777 56097 16280 36594 47521 2000 30429 63391 36527 53871 54920 33282 8745 32843 54623 39356 39336 55051 3901 9323 41897 44389 8044 5860 63544 5076 3107 58362 44757 27181 52116 16189 17370 35909 14390 27751 25304 58641 59356 10373 21522 40719 60114 11604 1497 4676 38401 34167 9839 39761 8241 8311 12654 46998 29629 57465 24120 11553 38307 37370 51739 22857 33961 43773 9171 30858 46992 1685 14208 12782 22879 41394 7039 19711 25244 9468 61440 57970 26020 61974 45384 9520 57748 42779 56373 49163 50665 23466 62312 32965 41445 41236 54643 53246 36612 30570 40426 2137 30222 15046 32824 2286 36132 45955 38797 22578 50890 37272 33238 62727 6896 28710 63980 60220 16312 13926 24455 53876 6315 36413 46302 28930 26694 12929 46208 54603 29457 19177 36894 26493 61226 37319 33309 35144 29521 36149 33228 50485 27862 33685 59998 38872 35025 10879 49327 10981 17672 44491 30267 4604 2731 61978 54166 8960 63157 60483 23527 18619 39789 51173 44185 6473 16736 29164 55173 17383 23038 2069 20445 64005 52841 39628 23715 21018 51903 47235 53099 60563 18246 63148 27220 27319 45943 2423 17120 27144 31302 57492 19823 58485 40865 20362 49090 30008 22823 23202 5057 51736 49534 42601 40307 49940 8282 43883 18011 21986 10779 1862 37146 27058 44023 16756 34184 44717 59602 48201 6035 14731 56355 64009 60336 12720 60429 42001 43712 6401 3709 47987 12128 24474 19326 42264 2110 28736 20314 58607 15875 62569 54121 37457 7584 29017 64035 20778 11452 51193 43969 20598 44960 35696 322 38182 13156 19689 5882 53732 60224 56907 19080 40036 12096 51327 8440 49939 4134 38317 5733 12027 60970 7888 618 12182 23103 19729 57446 49865 51544 17627 15782 49378 38792 35372 41286 24695 31524 50826 14829 10337 18976 58277 30602 31723 24799 37105 23151 55126 19879 62587 30879 56984 41906 60069 60795 30017 48098 46151 6240 31221 40849 28316 44761 40417 26519 34633 28886 28314 48472 37138 23367 22096 60453 62608 30194 33451 20614 24934 24617 15367 30748 41534 9652 52485 23875 61738 44542 57973 46275 13385 62898 47175 47333 58173 44286 53113 49640 58961 16700 14854 18683 53340 56217 47605 60663 33642 3520 25170 6080 19539 7105 27646 40220 23380 40066 60773 61247 41129 37784 22811 22093 8280 17002 17412 2226 6719 59790 3134 46047 45304 53763 44051 62614 19888 12266 39550 40527 57578 59913 51912 63098 46016 37726 1658 62557 63660 20332 2992 36559 25636 49123 25363 21753 11157 4601 27417 51381 56957 29906 7661 11668 50073 47393 46292 2042 49625 21567 42593 45013 19445 1761 14293 22573 3658 133 189 35319 15840 17717 27708 58651 53771 1278 43063 46877 52228 30299 25225 62884 34969 16491 55779 11779 49200 11044 40412 29815 54010 44610 22024 47997 30279 5230 27367 40203 55547 13450 45269 26245 50230 16974 56381 59968 53054 43372 18477 30206 36898 9059 828 34329 55300 30723 54004 51784 48539 33503 55439 56052 3840 41481 11213 16418 43459 23147 25734 37881 8856 26549 68 13321 21620 19979 6159 764 54054 49513 7235 64479 1636 57088 1186 44545 24373 45236 62727 27562 59346 34286 29254 14667 25490 50810 53561 42103 15545 27474 63977 29822 62999 38989 43866 64505 17659 61151 16677 50743 24533 11707 2734 25798 28741 16142 39114 47899 18721 3849 944 42237 47939 14398 31554 59131 46391 27823 53794 38422 41334 26377 6727 59253 26396 57814 56212 17676 43919 36847 49927 16066 39281 34106 44185 45843 59690 39222 26286 22009 6905 51091 41505 18679 19841 60471 49856 15672 24448 27618 17523 5083 63913 63687 50349 22351 24582 61882 45653 53281 45504 17054 42201 42562 61788 6173 51652 37677 26161 5417 53190 2785 4280 8328 36924 3045 62737 21590 16452 25547 52518 41319 51331 22724 52315 13742 35012 27567 38922 4214 2189 52805 63663 21495 35455 36439 17115 57232 57218 60054 1670 30531 28390 63132 23713 61780 35929 50048 3031 61093 2017 47698 12496 392 35095 12659 63326 7479 19126 37480 1981 42071 34189 45225 12919 24390 34025 64316 57003 25846 11792 28919 12795 4324 52344 24410 49749 45513 34820 36229 10569 11340 50387 11430 22466 52649 1583 13410 18524 2957 46679 10379 9844 42599 57946 57214 54462 34621 37085 34769 36691 27276 54737 60498 4102 33687 6089 16546 12116 59474 371 19578 34848 1641 37274 59672 49217 38187 45930 1730 49954 57065 56089 54142 43875 43125 10489 4795 60731 62767 3843 15023 47170 27842 7922 12195 41891 40997 700 22245 9055 39996 18096 18222 10408 11580 16210 9460 29650 27188 49101 19617 11188 29101 58134 22764 50903 2152 45086 50819 31411 55297 37421 58004 59818 44363 27727 44527 38230 5507 38072 43047 50204 62347 34534 60631 60098 53578 56697 45602 37122 43344 4645 24401 43715 48825 4566 57987 12270 13303 33406 18615 12217 3752 61036 37106 52845 1770 20734 25064 18709 35520 6151 18550 39686 12980 43863 60335 16537 36221 30723 60537 22327 60387 35603 1187 53291 6810 3228 16259 54989 15559 48006 36441 3983 14092 35650 9815 13622 7946 8671 41157 44790 57924 3883 48279 38693 25305 35686 13989 526 4528 14870 34929 61759 11204 44252 27656 21859 7308 22150 54822 311 21093 52331 30782 40856 55399 27869 43883 7675 37285 11053 54289 10272 17975 62170 951 48789 44752 52736 57710 37882 38444 11633 48941 6028 17806 33807 29726 56797 42810 46257 18017 7866 51324 23916 14370 39719 35917 7623 30407 30266 28951 43001 15172 52239 40438 4745 40983 22974 42777 49289 60178 1304 56150 62859 47100 52673 23933 16963 31089 39028 55724 39704 46183 3989 20637 56959 54746 49261 31199 45713 23112 7179 4066 34330 47158 40280 31340 45174 2722 30249 63937 19387 52834 20581 22235 33714 11901 17855 4636 60849 18764 23179 43521 26232 13983 44666 13438 33026 30591 38260 6760 46836 5646 40044 37113 21659 48916 5531 23146 36694 15282 46626 16187 23747 45308 43591 16553 38630 2884 61116 23484 21573 34642 36789 42616 52101 3433 38833 41875 17147 18864 51183 53224 3009 15145 17668 5083 28727 56748 4462 61116 23266 58186 42481 54000 38005 23086 14718 16009 56984 52360 5753 33075 8340 58224 14207 4195 15593 35177 45947 11093 30857 36890 376 42415 39638 28094 46284 2633 46883 24614 15615 40441 43808 10079 49237 56432 46786 51211 51266 420 22114 6563 27873 14343 59353 56240 62769 47630 2724 1494 44739 21792 44480 54618 36379 51496 27074 54660 48538 47482 57827 30212 44575 33312 59148 31521 58074 62231 5495 39148 27693 41528 25456 27037 31494 45252 26898 14178 29170 45449 23537 22332 52280 34546 33100 61879 30466 58515 8018 22681 20474 5465 45561 22378 53091 50295 1641 6463 2375 29575 44852 29613 45390 64142 58414 49477 46773 22081 54739 24075 41836 17593 29085 63891 22898 47331 29632 6616 11484 4194 24793 20431 56442 39600 38447 20354 18975 54914 24346 10680 4393 28730 14510 59431 23003 47085 29961 30604 8252 37560 53008 38467 11591 28037 21891 51621 53277 29479 49253 30850 29790 56783 61869 30825 3818 22830 45739 54961 51063 34889 64130 61837 2898 61258 19306 35133 31127 20629 26276 22007 1494 22923 2280 53862 4965 20715 3968 19388 45135 14940 33898 35321 44038 34150 40721 57395 9510 42800 7216 27908 6688 2300 36068 5458 1172 54037 24273 22975 8479 33103 48437 5993 28552 46144 21810 23538 14422 49220 33380 52177 22999 29562 25835 56802 47483 59871 50486 45239 61080 26301 40145 49241 18729 38276 3269 54390 28146 42436 4369 39425 33796 51706 27710 39736 22181 34372 11803 30557 2441 48601 61350 19727 5903 33374 15382 14817 58914 19293 13054 29866 14627 36983 42930 37126 6318 57447 56437 46335 18739 52479 20746 8361 12819 5230 25343 9251 63725 34567 15951 49091 49718 59842 22461 34903 30612 12548 25193 21069 35003 6813 56052 26143 27622 50965 15679 5903 51401 62386 36403 18370 14151 24353 29833 27311 59351 2351 8691 29784 16722 14145 5094 34176 37549 48609 11933 53128 44336 58574 31413 52210 12939 38650 64364 2737 58254 25072 1548 27916 3260 15069 21999 31234 32923 48352 34668 60697 41427 5922 39813 5031 63593 20763 33848 2477 58534 22197 55681 40581 59836 49544 28923 50952 60955 30413 8135 7717 11132 19825 35010 18030 1392 21474 55740 20974 29075 24480 20857 48150 57674 6956 59033 17136 31487 47098 58457 26139 23166 16646 15640 34497 5941 11992 4374 59316 27500 33575 23562 25035 46304 6645 36969 58849 25285 30445 42698 38021 43560 36112 11878 4000 43736 2096 12681 15248 27068 17007 11838 23884 54982 53892 7665 41725 24451 20199 52564 59077 30878 18376 47842 64178 46591 40930 33868 11461 57173 5927 37666 5389 17117 48374 49082 60818 60527 24061 4578 63973 5267 36276 5288 29535 35943 64466 43291 44956 61780 13501 49713 27795 37672 50958 37957 24725 13622 24945 44421 61438 36829 27374 55589 38184 16906 29925 45855 22227 52218 45323 43967 29346 52944 24734 50776 19818 43887 19557 42854 5939 38435 34529 43645 55134 60346 47673 24957 55301 56807 55312 29785 7783 3683 41451 54800 64490 7944 8443 52623 28686 59417 36534 25843 60172 56148 1413 24620 2843 39678 16605 48560 30484 59395 7676 17383 38307 6154 24894 62441 17065 49838 10946 12976 60293 62221 54419 39848 52126 18958 58143 57990 62280 7886 17921 62617 14165 18421 37771 53241 23884 27904 26338 5279 49067 45936 21902 49326 60251 40690 16891 27278 15724 35826 3638 12870 24261 3840 64229 872 41631 58221 56176 59946 48871 24264 41099 19364 51319 45086 25942 273 45407 46259 21582 13557 37597 9101 58942 45276 26462 58406 22422 1180 57427 33316 35856 19196 40459 6762 45460 47852 7019 47948 41984 45063 2007 21912 13784 24294 18707 59884 17364 20190 40390 29451 9417 1220 13474 4098 61525 6392 56154 29815 30628 44152 41499 45245 26329 60317 33772 43410 14099 56575 26450 25793 34533 29723 34736 61149 17470 36696 52366 43469 47716 57752 46118 30039 645 43934 62053 5620 29783 14994 55968 44870 9503 661 10051 51592 42868 63611 42580 50219 43389 30111 3384 59962 8796 6900 54562 55485 33899 48918 29196 33309 38745 8767 16618 58016 57926 59870 57324 38672 62973 2955 51638 18195 16518 10797 40497 28011 1214 4956 51799 57918 37962 35575 31538 50578 37030 33640 28562 21337 63852 46696 35264 7959 13236 38111 25433 19968 19639 37413 62150 49448 24590 15619 15544 49883 34542 26384 48812 53067 38255 28422 15384 41426 11473 52403 22300 5584 812 7320 55826 5847 47025 40062 50815 40821 25409 22737 21389 24637 40455 1430 40010 5558 8784 27436 35081 53375 4856 59772 44896 27691 30646 46873 8241 39931 8499 33948 28846 21867 34794 27747 13457 14436 8003 27354 54975 62526 53714 57437 44161 7921 6994 24664 41651 4550 2499 8107 5825 4790 14677 736 15569 32813 37837 34537 45156 15818 29964 45583 47035 62099 10417 57161 34881 27811 11345 43162 24039 59168 33295 50390 4767 21859 21127 23814 51098 40077 17771 6076 12821 9131 33469 15688 55858 30363 23888 4393 7595 26883 52255 7145 39906 29038 10972 16973 40208 27583 29530 22558 63635 46822 50007 49305 20839 54141 48540 49146 17554 5125 30771 18643 41015 31138 50327 24941 44595 6847 4786 44224 40656 36966 28366 43186 11257 38021 41555 14617 53121 25345 36299 36897 56776 1024 43664 5073 4973 15861 61293 28451 19630 36501 21878 63173 9433 15211 40934 55303 7926 34040 16891 51333 59154 34511 51583 30338 25274 22279 55158 29432 47993 2469 54685 28758 15043 53952 47217 63211 48249 27353 26683 20461 34425 33089 6911 0 1319476917 +1024 61177 2359 61843 10602 63777 60227 22640 15234 13253 62595 51675 64127 40944 30021 36283 8117 61217 44566 13109 4081 11850 56131 27730 3391 35429 52288 30279 20205 47853 16769 39332 53288 60987 44963 40839 47374 28842 20346 45731 3494 19440 35055 6110 47535 13874 46800 22752 679 44392 31066 20247 1330 41771 51787 20869 25560 52579 22913 59520 5765 59929 60883 28179 38631 21181 41737 8638 49452 16744 31106 60739 10650 36389 46737 24064 13303 26967 49005 8901 29222 50262 4115 55874 24561 431 27306 61682 7076 6494 8832 10275 13295 19050 58589 22376 9521 624 13675 8975 25968 110 48186 52300 6942 15242 9868 44784 48858 3781 14864 62127 1466 64194 6769 22787 17155 41326 4972 4728 20586 52145 52992 28350 29689 19380 22550 30921 11354 52441 54148 44414 2592 2235 45575 50802 25833 34042 61795 53876 1933 57552 44320 53690 7176 28271 9103 61345 19815 46354 46345 64340 9553 51789 40157 9928 45214 51678 7127 14020 19101 18503 38840 63697 23276 57549 18781 6378 20216 15564 14720 15933 46358 20859 17383 29474 13871 43847 63426 36561 11695 9725 23904 60497 30963 39388 2375 47951 52212 22622 48277 16566 50176 27912 14351 13263 29516 57177 33100 34017 43702 56857 20718 34324 30225 12979 27335 62656 18119 61261 4384 23884 51209 28954 45701 26137 62282 56306 21347 48711 37354 63551 42767 21058 9079 25427 57395 18642 59963 11929 23414 55753 53363 37247 23887 28873 50401 2169 53370 56805 11572 49733 35709 11874 29889 30694 12307 26320 49204 5698 5888 44603 33702 28444 5829 45054 7863 24758 3147 52333 27264 21075 38498 3013 2304 55602 2515 1872 46294 58536 4063 25945 10312 35034 62791 25799 7325 22165 45369 15593 50081 60327 48713 4256 48237 356 35684 42933 12657 33971 49573 1327 8958 4347 40218 53237 28283 41142 5191 53806 62121 8543 16074 5570 6686 16244 23518 9057 16102 35504 20327 31208 439 45003 50558 39773 25645 9830 2169 44693 57939 43359 403 52970 34026 5082 10095 21836 62716 35038 11120 28158 37397 16097 36973 15042 61688 45413 13303 55492 63800 64111 1376 63499 41169 26459 46167 47041 35060 1164 20922 55145 48981 22075 973 18910 23669 30490 56306 59256 5643 451 59024 48163 11983 31322 21398 25546 53168 40062 56353 8670 58770 14507 4898 46314 1511 9567 63800 46346 32991 63164 40091 64159 20497 9519 11959 15426 53584 47770 58395 17128 64375 54836 62719 54270 24847 43577 42522 60317 2791 40163 52108 43482 17526 29922 24182 3517 24178 48729 44900 54063 57673 14183 63363 7 122 43939 31259 29940 18141 47342 61201 5926 45823 11032 59048 34010 40622 53460 4729 42968 56794 5797 37533 23522 46838 32969 52978 28756 3185 6045 30786 56645 20728 34002 14027 29807 4503 14087 62840 22463 6201 17376 19346 46400 58206 40019 4071 46283 44961 14873 8124 42632 46697 46088 23517 54551 8728 15153 13898 54937 28449 9099 10116 8779 22039 58451 27885 20195 39934 3648 15872 63304 58038 4569 20452 20988 64084 13449 62381 19070 42192 14720 1731 44895 63039 44321 21483 14020 46696 51648 64428 11051 49349 2165 19267 36184 5605 57101 50098 57167 10951 13086 27552 51129 18944 12790 55987 53454 40991 44630 47460 29722 13007 33538 21172 11515 23568 23435 10862 40295 60689 29967 51454 45697 37450 58384 20249 27546 19277 23698 59851 42963 2561 50288 25989 14103 34481 60940 24549 33592 6491 4522 9911 56623 60332 45646 61037 30383 57485 47503 58400 41804 14493 19270 57382 16966 54086 30533 31267 60062 46522 30002 24230 25361 39698 57148 13108 30298 54427 10543 21337 22499 39817 38904 61938 13371 64033 19415 62327 47185 6178 53982 50797 7886 36788 51820 28055 19884 18662 32901 20796 49444 9174 50703 43093 43167 18906 62988 7873 37325 48147 62795 35145 40969 15772 35303 34032 13480 23930 16862 25192 52213 29701 9461 55704 56875 32841 25536 23548 62832 43673 4393 25161 60359 49940 21101 61283 49798 62004 55363 48931 54736 11626 51941 46566 49406 16242 23278 48028 51406 26590 3532 9368 50039 53965 62211 47623 3518 61948 8548 20340 4845 48269 14579 35609 16619 9196 4122 23045 27764 12589 37977 34552 34346 3514 62774 41673 43483 20286 8794 4778 18370 55630 19719 43767 4579 36259 15143 21532 18410 23457 29929 35406 29401 37490 30893 8824 59464 53302 55439 48983 59588 25382 7524 13784 2671 48782 56482 10879 15604 51753 47918 23709 20148 56073 11502 1060 23664 2188 58589 24593 13642 28699 28200 60907 48950 46550 7365 20275 21795 44510 28668 25832 3379 31400 61546 38569 4992 12123 39342 64029 36930 30935 23957 34977 56031 60264 17543 64099 34190 23378 18664 9622 62469 1235 48338 49793 55968 1746 20845 42732 4063 1835 22178 28208 18411 2031 46350 9240 1930 28699 63149 56646 21620 50136 388 3281 11980 84 808 56941 10798 49730 179 1098 45987 49428 42730 5108 19385 48957 36286 58292 37932 38897 16312 11962 25604 27047 48572 15255 53667 20367 34661 46301 43334 28320 54432 42210 34597 48515 4895 10953 51099 10007 1770 3105 8857 20522 30196 11856 14848 52853 59605 37850 21431 23026 8312 24934 39995 44959 28279 56674 12758 62844 57741 40812 17522 19599 54242 29865 43096 5943 33201 64459 3742 49179 23201 60193 34785 5260 30178 3602 24951 56304 30316 31343 35992 38285 10498 15322 38960 49105 17260 37004 22938 13129 1138 29035 3200 36042 38709 24010 36587 25408 12847 53205 24092 42618 15816 36044 59292 44088 10207 13370 15103 26477 63373 47421 49688 53341 61593 11910 21951 3447 29057 40043 22264 46587 5302 64390 33007 58542 49607 16606 50499 14077 16169 51317 14523 13130 60443 31328 7040 2685 24354 2128 14505 42298 17722 56073 30954 62244 32963 7681 34287 28145 45393 55502 37305 27966 19949 6508 13840 40160 45824 47315 43238 54130 26694 29724 3503 55692 9071 15450 58201 26425 1416 64443 9591 60100 45538 26210 61831 63943 20234 21062 7193 52119 23666 44622 38994 26241 11237 39913 27519 46828 9418 1434 35296 7029 2171 59075 50938 3156 17272 6985 61289 28587 19775 60823 46611 22005 57191 17251 39790 44915 59097 16896 1084 16318 1705 30228 26004 2368 43794 39466 60665 28048 35400 14033 33005 35841 24841 21628 19559 49129 28829 54518 21559 4863 1838 60529 34990 12454 26180 22904 55172 42344 42878 25263 54497 44231 2835 64421 171 54 50870 35182 15773 28430 15666 45928 59567 21937 4402 27385 28153 45560 49170 33506 45723 21188 5971 48467 31173 53797 52622 10638 64298 49647 64370 4316 8972 2403 54222 60508 52835 58258 844 48260 44821 19658 33749 29307 43987 1773 18158 18180 36759 43323 60266 25769 48119 2653 28197 18300 44621 61437 31517 52774 18144 42798 46956 36667 18167 31132 24944 46111 57078 45695 28201 50969 31468 43405 2063 1166 19911 1329 38502 60209 53340 674 43404 62395 21266 15308 51678 53196 59774 47958 62861 46818 56079 39914 60414 62745 61679 29847 31094 12238 20374 25735 57746 47825 25311 34291 37288 62012 16207 9418 59235 60957 12881 25692 58311 5678 19431 58447 45868 23825 10121 27707 31650 63327 57989 28378 53734 30797 1501 5932 2136 9178 25996 59402 11420 60892 19400 24484 53197 44325 13587 27322 3260 50787 42206 13155 64099 5824 3591 61358 61890 26449 61360 45379 61277 3348 10983 7595 10097 38774 14846 48988 51411 31310 47415 42448 55259 52450 44992 6308 55157 20339 46910 28290 20024 52875 45462 64100 55400 42866 40605 53709 58709 34954 47366 37595 38152 25088 26782 62659 55107 6464 44977 1768 44159 46973 52454 15379 10543 21954 8082 36503 55336 63178 50673 47582 4760 55043 29426 34722 39734 55615 47098 41043 14788 2200 50858 22686 4884 21442 41132 28093 38331 1690 24200 28879 18954 23539 62173 219 12792 56077 26608 47119 21446 51949 23071 43616 44370 25610 57252 47780 52346 42473 22538 3355 8099 7520 2606 1596 30808 15694 16023 11304 33470 61368 17882 24964 21274 12995 31472 58782 53273 18751 27374 57524 25959 11172 54313 27556 3723 2190 33311 54442 12380 9489 42874 50246 50485 2103 28032 18859 47755 25666 37719 56136 32806 40800 58329 38317 39889 7230 63882 1616 59537 2719 35998 15208 36352 28444 49339 5934 15561 62944 54814 23754 47412 45962 26213 14131 38521 7831 5945 16686 2839 37809 29477 11533 51075 3171 30261 34706 33782 2219 60297 22003 61619 22716 52859 33081 51824 10164 56354 10571 45374 11184 14135 35595 22623 28047 11751 1443 37333 41596 57253 37693 36717 33992 56114 988 33519 55127 4716 17052 25445 17609 37927 29806 4571 22210 27284 49993 54627 40510 16174 44092 13396 56323 59154 64268 49730 9391 12953 50487 27566 13288 2907 5860 52121 41949 28403 46156 54857 30939 26341 40789 59736 56295 58593 17273 22379 24151 10867 18293 55984 14285 59765 33048 27332 34398 29456 29193 61200 40853 36040 58838 41705 8966 5069 7749 57571 26874 28234 54704 19720 50156 22069 5839 11094 33524 6556 61904 26541 22535 37413 34311 36780 19575 54992 27729 45499 63479 3687 11422 22113 2714 35077 10383 1201 41757 5836 29357 50703 14195 63263 17622 47451 6528 64444 9653 49255 18384 14883 36861 55587 23602 54865 53835 50984 13558 27000 64266 62193 34570 45677 35829 58255 58335 33481 22099 27378 9380 50717 43879 24152 14983 59390 2469 19953 24074 57986 46578 22623 38847 13759 4680 60442 44490 48109 13712 20124 5586 1830 11590 52209 46904 35655 62503 7914 36694 56557 4167 47796 2737 45856 10267 33190 13945 7103 13489 16251 10469 17586 16030 40850 8867 45864 11820 38078 60840 22283 45422 60180 56260 352 4875 24204 51617 18771 29379 17326 57034 50838 23035 27518 64466 760 6001 15877 7097 5841 2321 63673 61248 29509 36397 33735 18308 18354 25321 43494 46126 43936 59698 49793 42200 29794 28241 45252 3345 52314 16931 62574 22489 37919 55468 37837 50018 28777 20950 62849 39520 26906 33026 4096 40344 60375 63660 63658 24035 5089 33763 13555 55115 25838 26558 45307 52538 63965 39889 8334 22187 46252 61875 42322 18954 51146 21402 22364 21852 29356 40210 63894 29757 55336 3912 47871 38903 55746 61890 6476 25440 28268 268 19039 53699 41630 55921 19371 23440 5968 2702 36895 58015 5040 56376 64289 52295 4552 31314 23121 37614 33297 34770 9174 24632 19 15435 29864 53792 44836 11747 19452 41774 46940 52453 13508 22130 22819 14066 28985 39196 18082 46121 15716 4762 46460 36045 52294 6792 3847 41936 7286 46886 40213 60718 42614 64341 14576 35879 21022 26448 29458 8209 26398 56401 13230 53569 34643 19554 14055 56488 9441 45210 64389 54254 54505 55413 4947 59855 53528 11586 6172 62953 22921 54950 45266 58812 17471 31211 13401 5415 58844 22396 19027 6829 38514 23167 24219 53387 39486 29134 61680 60364 39618 39292 12955 50214 11864 22979 42625 41151 21377 3807 7286 52528 15789 17556 44207 3609 41572 21529 60162 30815 47002 59875 54076 25861 27343 6794 17311 25900 30646 17818 61342 25714 10948 40879 30917 12944 55928 59525 50082 45379 8596 46118 33005 39664 35962 3870 29547 18445 49472 11215 13801 14601 38367 7095 41928 36731 26657 29759 25633 17210 27636 4332 22657 10897 45040 14942 31626 17259 56206 51521 5973 30421 44749 3902 60183 4406 54005 38048 31355 24908 19477 44399 56611 16684 37502 3667 21995 4788 53599 18512 5042 23478 60762 53415 38317 12787 24258 8399 4246 24928 36704 809 58835 60096 64161 62039 47990 35780 29631 26625 5359 11173 37839 30571 48074 30423 46140 50702 1985 9544 19648 14094 20480 21530 61346 24922 37424 11333 39121 46937 21515 20577 24323 27823 36954 45801 31106 35827 13334 34350 4043 43221 6838 45558 48648 22451 10629 22563 9611 8917 8472 12717 61097 33997 16621 44645 36809 48635 16585 16082 59360 54840 7039 51437 31593 61716 32883 35916 25691 61140 7645 64205 27423 39787 14795 19816 25572 62241 50833 16809 27768 55141 52942 14441 14033 22555 42026 24004 61028 30169 38244 20554 38934 23726 44495 63712 19867 16696 21084 42618 10780 28231 29726 20231 31002 1254 26645 34228 14978 20341 8052 21623 23868 5743 12375 35233 7722 26830 40006 18671 50715 35225 46536 46056 7788 21122 41749 26316 30196 5939 3203 35265 8014 61780 53686 51293 8106 14496 46704 28653 63130 57484 13514 22836 63314 31696 3324 14792 41550 34696 31514 15064 25094 20443 43065 31558 29683 33603 48088 22207 50403 3200 7243 7760 5651 13036 38924 64058 38481 60690 30895 38236 23474 62856 63606 60681 57149 28389 43645 8967 17915 16770 58090 60143 14752 60497 57399 49409 20742 40057 34528 26951 62605 48396 53440 62327 13389 54577 54795 59358 29140 51112 46820 26389 16296 9446 62031 2922 43834 45900 60024 57746 0 3480814419 +1024 41327 18814 54133 55587 12115 23673 47229 30737 58662 27046 39574 54353 40360 8160 7144 39527 34045 26133 29736 43655 42165 48585 5390 6309 40582 51564 44420 4976 4959 29768 547 36619 24350 24234 45663 32883 62611 8547 5417 61965 17136 17126 44946 61608 55978 5534 61819 34440 8224 19519 19540 41652 50180 63404 22631 54884 63336 31293 40821 10170 39920 18234 49778 48493 23322 36724 41044 20949 58397 54762 54998 63086 29480 14204 35971 31506 19784 42695 27053 22445 61803 10389 39493 21900 11181 35064 35233 59306 56345 776 47991 35391 53206 13910 33562 33069 54344 24046 57907 58914 37705 7028 55415 27545 9617 51468 10113 30315 36117 62092 50663 24709 13544 2320 11428 58214 61624 13614 46405 53284 55776 59758 14820 54778 11154 19582 26322 27832 33035 19600 61919 43082 16636 63236 28233 1909 44980 23138 14083 26929 16500 50033 47169 46341 48560 40548 28522 36802 55892 21517 11885 6825 63533 55499 35467 1073 46516 36937 11196 34757 39839 47265 4196 41891 40656 60357 13019 39721 6453 17934 37105 39363 36890 40881 14194 42595 12259 43524 46273 30552 19074 6789 59324 911 46128 46588 57006 30343 4500 18652 431 56129 58654 15274 9883 40738 36213 16537 26659 36156 52481 47522 60518 41207 38198 35783 33447 5961 33808 34786 61521 3795 11672 4925 9647 61579 5638 52645 12611 40546 15943 37807 24665 25689 48975 62442 35205 49226 28142 44867 38127 59427 24565 5182 41012 57954 36265 11391 255 24180 40387 56711 28478 1623 53662 54098 21856 26895 17813 22942 45771 57486 36741 36923 46651 21645 6593 47851 16813 39381 22469 26273 10554 54452 50338 48029 44921 6779 13552 27626 3702 42347 21492 5293 3598 35070 9316 8442 48609 21449 7530 10798 6421 47577 20468 51866 63020 41856 34446 63626 41532 61239 57808 30974 57453 54730 46072 12592 13493 19254 31003 36106 22332 52968 29312 45265 53065 49326 7027 38921 47544 60742 41810 37863 38724 35419 56807 36612 61444 60916 9151 25811 39117 62541 30355 33431 39750 62458 60405 10631 11904 36204 12833 19000 50615 24950 23518 3560 53852 7979 1712 39063 7271 45273 50725 24051 9188 37968 11127 1644 13578 5817 27638 11675 28058 44726 564 29913 43223 34070 57853 9335 63179 20658 41673 41304 9056 26947 19932 9871 15420 59407 27222 31723 17361 40740 39523 51430 15540 43768 17514 16434 56964 46785 44623 28829 936 20261 20974 9558 36788 39440 6478 4443 17720 56680 10254 33417 61246 15109 26471 28784 52994 47743 55400 13421 5588 24155 4488 45138 6298 45655 35022 30486 19739 48794 53741 33810 12107 60412 26777 5532 53269 61525 42043 16268 40721 876 22652 48578 16822 51148 53625 7631 11809 18317 61711 3428 48947 1937 30875 55477 21716 51460 57640 43836 46502 63615 8582 60470 60175 64072 33690 55576 16734 33758 53221 39907 36991 29673 18542 54085 30512 44766 8422 19941 56613 28678 55603 33263 38744 43624 25109 21898 35364 6423 55935 12791 19075 58751 33563 35965 17570 49417 50297 42676 28632 4796 9753 9385 57166 7841 38183 23658 39927 10014 12477 26176 48597 22500 57373 56716 30388 50987 48133 10900 16684 53656 19401 7368 19946 384 10304 3991 61384 25547 15928 58983 58068 10347 13633 21446 29414 55999 21019 55430 23263 24282 56080 14578 40802 42808 58949 43809 26329 4904 10935 18764 54281 57460 10821 40491 19393 25589 16883 21316 51007 8737 14829 19522 27201 51380 52546 11039 41168 29338 15789 46861 24350 13123 37150 24182 45321 10389 7932 3270 19082 24013 51453 24963 21371 63103 15008 34732 418 5971 57662 15354 3494 60004 39100 10948 4766 11533 50353 19055 33139 15381 31523 39654 43958 56377 4806 5234 38694 50623 2799 5027 4200 60092 30470 53034 44363 46994 27402 44592 45087 9150 51128 26498 54738 45589 20893 5357 30302 14076 5432 50943 60882 55385 18361 18515 24472 7911 24549 22198 63137 23814 25341 55598 52933 22291 44659 54861 7816 43435 15726 5507 10940 29629 43648 55215 33316 40072 2300 39327 37937 4216 4373 21375 29678 53283 37748 41127 8448 29949 49765 53755 3055 34390 10811 60021 22568 36380 2978 14212 17487 7623 27079 3456 40106 5084 6688 62521 47750 47225 37980 39706 1326 16702 59680 6152 1718 19989 54654 27047 16632 24550 42348 31665 26765 17890 24288 41721 37657 53452 43740 40011 20875 25618 9905 1295 34689 25063 12575 28529 25669 15309 53847 31628 56096 17780 33619 3923 20316 10392 17320 60882 64043 29906 44853 10649 403 30035 52095 5455 61275 54918 63429 48871 41883 41064 3340 23258 47541 51642 62014 38127 13459 55187 34887 57910 54665 64191 8868 54901 791 9013 53170 9910 1664 39810 38469 39910 4029 18216 15442 17302 57657 41828 5053 26509 20150 53472 59179 19300 23870 24728 59126 63449 51800 46884 63072 25804 3022 12056 58210 879 48268 9623 50973 59616 39068 27435 56155 58282 22571 23303 11620 31133 51925 32943 37130 63901 29875 58562 5164 4503 62134 6411 57193 3283 60639 17142 44889 36926 18981 48443 57124 51987 11470 1548 48976 36421 18424 24582 9968 21517 43963 43406 34197 51592 56824 23311 33414 43387 38015 6856 29366 1587 52483 1716 26941 57837 59307 37192 27895 5001 29707 42766 10660 14789 63166 26852 12329 28064 46821 62551 50168 2290 34061 50454 27428 56634 55867 63339 30404 51809 23789 50686 27160 17957 44647 18483 55985 27722 54481 29932 35206 33865 6346 58525 18730 5145 59195 14991 15138 43596 63475 10532 15935 45108 40759 16414 41099 61302 1068 56095 15267 21941 60980 27096 18699 46304 59251 10654 7896 64339 51513 40364 2713 913 57727 7657 30534 50461 37655 54919 6175 48072 62302 15487 52627 44034 49520 1634 45773 52692 38837 26804 53617 40248 17681 42046 46004 6210 61423 20594 56344 34397 35455 46299 52241 58113 25319 64220 40295 23112 17675 44392 12843 35922 29442 59573 43756 40232 36815 25276 9646 50214 61053 49609 48780 20401 25616 55291 40998 30669 12964 42961 55131 30251 24169 21989 64470 40268 7450 10520 22785 34454 10400 47223 13438 23691 63354 48318 20398 58615 46144 38122 48761 57586 40653 43116 3578 39547 31538 36943 25647 63252 40782 34090 7849 35926 48294 16335 52133 43976 36335 929 28318 16163 13996 39686 36215 10762 23331 47088 23737 46074 28217 33043 25112 18768 22265 16742 29503 48467 55516 326 45762 57759 14081 33487 2997 46411 26089 11356 48488 9253 52895 33897 16369 52723 2234 7894 23699 6501 26426 33387 9643 16459 63204 40989 57496 43331 40585 45797 46783 52173 39985 23791 49935 621 55888 31174 21417 35485 31541 37368 19589 50703 6870 15836 56611 24121 14919 41909 39922 29825 34139 39868 21143 13554 48062 10383 11024 14334 38197 37144 61775 16920 19335 5768 47472 33431 19295 37717 26304 62132 7264 56213 49829 19848 19021 26546 22326 63031 25650 12977 44976 1847 57455 48953 6404 22459 1641 26499 31343 30512 27610 44213 50204 34946 41649 39684 20641 45135 44440 58814 17597 45054 45748 6870 14582 15246 3818 7663 27568 45081 12852 52124 36854 19457 37361 39678 3501 4483 50362 50616 23878 41763 60984 56162 2013 50319 45298 40461 10125 40923 14532 53656 20571 14276 5880 55072 56510 38055 18859 61755 20095 15930 15004 58280 38858 59661 3498 10879 2103 4444 34286 4427 15890 56843 18065 53481 60043 35859 56282 60946 22166 43902 58074 29224 24327 29556 1926 26862 2823 24807 39112 33562 25028 54539 10713 16688 46237 52535 44328 8945 35843 28012 48065 46234 60279 1889 21370 54864 49546 50123 24101 64182 9816 41268 6288 27745 28600 34531 20040 39707 26691 6101 49560 7314 56486 32980 26248 36439 30762 43872 51436 3119 32897 33843 55942 22326 41077 10260 57579 30145 63615 53178 55163 4949 61575 50887 21085 51503 36657 434 22077 27099 60165 45242 21332 45245 39704 63639 31219 4511 56534 42051 37872 5727 37186 7206 42231 11130 2889 48733 23411 64424 43123 30483 64011 20188 49070 13693 59092 59375 61551 44951 9033 51684 52253 45198 50054 43737 30279 31280 61083 63145 22789 24467 18271 1737 33791 23871 29730 25271 25467 62293 22864 21177 55423 22276 49335 13750 47827 18614 3323 54503 36949 62085 16383 33441 24054 43010 11198 650 45155 41578 30340 54855 10216 216 11518 372 25505 50485 5577 53911 16972 56418 47265 4105 24782 1379 14190 30734 50746 41774 8395 60621 34221 55666 11201 7736 10909 13117 49765 44872 28400 59026 36833 23864 23192 40252 8484 45347 35576 37508 7723 62634 13146 35251 35042 54086 34186 18212 174 12809 27479 52554 42338 55453 42664 4393 9681 38117 25371 3382 42894 7833 16716 37599 12007 11817 6454 39679 58387 26920 36764 46557 21781 42829 19341 31145 55533 1825 46049 13614 16575 36486 29500 41065 24167 60680 7302 19699 63211 13311 5914 61945 38884 42722 43711 52069 33917 10150 44562 6737 19600 17016 9649 48968 62113 12219 60718 19143 24277 8711 49242 30494 30018 32900 6932 8833 61953 48460 15149 40152 55567 48969 38492 9211 249 29428 34592 42289 17199 55827 38053 41492 14308 40697 20688 8046 30640 37114 40562 29373 30501 44516 13856 29272 61971 43148 29589 58137 41892 45807 57628 44688 21089 14192 19713 30931 37362 53793 49246 47417 36877 44591 54171 32936 10785 50934 10866 44722 57262 18436 31036 48507 51905 6195 21089 280 61553 64262 38438 62191 10028 59294 37587 1997 46735 32869 42693 58094 41951 5305 35956 44831 48646 10533 51461 53210 52111 42897 26693 27310 43320 28154 8200 44263 64461 17985 21592 43395 55558 57826 22261 14013 40863 64120 59959 27435 43892 1470 42794 48481 8648 38512 3230 14547 25520 19581 10403 51686 60745 57228 21840 42622 20426 38807 41807 36342 10877 18481 44152 23047 26552 21983 45275 30702 34709 58120 44350 46742 50714 7337 16399 8662 43611 61372 48844 14768 38543 50985 50272 13563 1823 6436 23285 47373 26182 63125 8907 63775 45920 47649 23371 8045 37105 12086 21289 33314 63774 45956 2394 56383 8482 39052 29448 45228 49947 2152 12350 40348 12541 58705 21081 59764 51748 59689 33010 45292 2723 26527 45806 35320 12613 48935 26095 7487 39789 4625 37462 18558 29172 31624 43027 19687 53967 46495 28479 58147 22996 62275 43247 52295 54606 28325 16560 58015 57384 55011 57785 46538 53737 58987 50193 27642 31165 3650 52247 23873 13189 59427 22452 38671 3042 1367 44925 39088 63349 22680 5430 24181 42884 40854 7958 57076 27633 26589 63193 45360 51347 31173 49906 40794 10188 17773 14855 26264 51408 5705 11494 50525 61343 50243 17639 26096 43247 62948 10740 47877 27122 24132 50796 48544 28828 56796 49776 11295 55942 30156 61438 29129 26996 33550 10856 45591 42260 33864 13455 64058 51840 40727 63394 39810 62715 40229 57938 63357 35958 22586 4670 40305 45098 61146 26407 6730 9446 59127 53452 49259 56904 61518 58235 18094 29268 4928 15173 14739 3535 48648 38237 8693 19982 6662 54116 49534 39305 4556 39994 30861 14424 42777 64065 41205 8438 7978 38954 35819 57421 62895 14744 37896 11211 49898 45722 41891 1241 7266 3137 37244 30208 59972 13613 33558 61666 23817 26878 22562 48986 19042 16971 46914 26590 19547 714 24947 49022 39002 19486 44194 36322 39637 27193 41149 64370 18002 56490 42876 27058 21044 55826 58027 18535 40155 6082 51172 63819 27224 19948 36969 19930 16010 30567 41348 26063 57347 10338 57838 36403 56709 19998 60239 4631 4766 202 11520 55445 7352 61088 39872 28374 39810 6209 63832 13992 17441 40686 61583 23620 49143 42375 7034 34410 8892 27102 60366 29377 27453 40073 60923 17195 19052 56678 26944 49300 53411 31658 60203 49704 43850 45524 20176 12056 1150 37045 1978 20772 23778 9713 20744 5961 7190 6863 26242 44673 63787 48612 31445 42213 27210 61506 29687 19271 55313 38028 39656 37551 21075 35246 21557 3152 55277 2719 39363 19638 49831 61994 22739 53893 49962 53338 26935 52924 51927 55581 50433 28152 16194 17243 58044 35529 1552 39084 17065 11388 36387 42931 4701 54702 52240 56841 2574 23281 25454 63363 29209 36373 62331 4929 27736 22175 52880 7394 28848 39655 11454 19838 34931 17475 837 13236 53871 4580 56048 40652 38307 12141 46631 47665 59131 39948 7042 16442 33437 34040 40044 24966 5222 31379 47572 37809 45102 6773 43520 1701 10916 719 26805 22306 11276 54204 24565 23478 9754 12722 34968 48269 241 57828 1484 54719 28299 58482 36792 55355 13282 19786 35348 41321 4611 39494 26669 64129 4142 41854 16818 60786 34435 11766 55070 55856 22053 40747 5576 64498 51119 15734 56620 2952 40807 56789 38556 53921 45612 41503 56512 18977 1032 43407 58067 50671 913 15850 11468 8437 31277 58815 39378 3421 55441 34173 48227 9785 36950 37397 3898 61812 3090 51143 55303 0 1327826577 +1024 16723 50814 38158 52509 38895 15430 13457 64486 59709 39700 5108 47007 11506 7486 58832 7347 59616 14508 6253 57354 22073 14586 58205 51003 28736 56858 60004 46205 39064 39324 58472 59519 183 42458 12003 60524 30014 30576 44933 25765 54850 27721 10042 34920 40762 53933 3879 50547 7444 529 1237 34392 30612 62882 43291 8388 59896 35232 47218 7336 6013 36872 53195 686 16103 13786 61758 14720 55501 6818 17468 27568 39006 24375 6120 17648 14659 7619 55176 11836 8252 13687 14868 47151 3176 46435 2428 6923 58828 54586 5534 12943 26123 19234 55417 23334 16691 24983 46789 58517 6028 7669 57116 24810 51777 52550 30431 50458 29490 6077 3336 64032 43111 40619 60559 54233 49772 56219 1713 55276 61804 9516 50063 34377 27540 20124 57420 47951 40063 11211 20739 54083 59843 189 54547 25162 19123 26636 54697 30552 63542 19535 30427 3150 42069 5926 21803 5434 56727 1226 8204 562 15212 59566 38820 48706 55298 19713 6844 5746 55065 4614 63618 38842 17756 28820 52598 27628 25833 12392 39054 46902 37643 42964 59319 14487 54499 51474 37656 9641 11107 2428 29937 57187 52194 38664 12126 23644 28186 8260 7018 22820 870 60529 58591 6300 41488 33205 19603 165 401 56713 2605 17837 52389 39632 27880 50064 61034 50322 43488 29622 48912 37387 19661 61773 857 39027 62002 23439 26956 17059 21555 31309 24716 4864 47940 12519 11018 11611 10451 11925 32772 48631 977 39040 34848 9524 663 13557 1621 15377 19975 41106 35737 62552 63237 54986 59389 28058 19029 13598 64136 7500 31339 11983 11707 62639 58406 51436 31051 27854 44886 25585 42835 57962 11825 24952 60531 9269 3514 18538 2780 8306 56189 60363 40472 43978 4781 23078 25758 17841 57925 21868 52063 43808 56692 49036 5659 27555 46328 34718 35220 20391 18830 24509 49590 4994 1177 22898 40073 17433 21454 63392 14430 14023 26186 47205 42192 37317 5731 39092 49230 54424 22098 40261 16808 4005 42544 1006 57488 3774 35639 52083 25731 28783 48707 44558 28385 18628 63628 48834 63729 19402 50720 11370 47320 46896 58239 3540 56334 21149 15820 12641 9152 4688 59643 57119 49831 49373 34823 1679 30023 33567 59754 1973 5002 435 6695 53645 26952 57617 13033 23164 618 3888 7843 56489 14378 56573 11024 48047 19892 31696 22150 6299 42464 8899 21018 9050 13974 14415 6533 21402 13350 43211 20087 25250 48280 23031 45685 21712 9991 22793 19013 21667 56566 29400 55717 37615 1112 42285 41869 33095 52128 28159 48807 35405 19709 9910 33165 42299 25715 28346 43356 53322 63531 56483 15317 5692 61488 38389 2822 58082 63030 10895 63975 26118 45437 49223 20400 25281 37802 44729 62920 50981 17019 15959 3170 33156 56643 22334 51126 12414 62346 64099 54127 20051 19138 40688 13256 3408 33259 50363 21666 53857 39907 46678 4367 24104 47286 15313 3187 62142 44299 3517 44976 46540 42126 11487 22782 43441 23135 4415 59946 43682 21246 38434 36704 33550 12691 4821 48793 12339 14615 62973 36848 40884 54194 33466 25288 61661 30955 39826 60067 1847 2047 20299 4633 23798 18078 59211 18435 44638 19629 38161 29384 36344 35373 47649 61348 13575 14240 31139 60597 44445 58200 28595 26830 50967 4652 31359 56713 486 61534 45733 30308 17156 37201 52867 7229 940 4484 51325 18671 59258 31413 28637 56012 41557 407 44152 43549 7795 22211 21702 62695 31137 11797 47854 16839 8478 33380 18525 23279 61723 27714 22941 12028 62747 51056 30171 60285 3450 59595 33129 61537 47219 47096 62838 29688 37700 44562 12915 6034 8588 27237 63465 12887 47289 62354 30269 51905 58942 48313 11639 22746 19456 13739 47201 5982 21253 41065 7503 38821 6089 53241 64401 43600 28425 2512 48392 59707 943 49843 36313 56140 11674 37999 49525 25980 28718 26647 58233 26043 52662 27579 25822 1987 52544 47820 5994 55392 3665 45653 24375 6750 40083 52601 55324 46347 48250 53432 60532 53131 63750 22698 13188 43937 20538 44767 12293 51832 7012 32875 22485 2518 21338 16308 85 36124 17254 24472 48500 45752 19866 24015 30175 27486 28130 62157 38241 25019 48922 29735 8043 12481 21613 9719 13609 22270 4207 59900 61777 21072 54892 46574 33053 11027 62678 2904 11640 33575 25929 60561 53731 51924 40759 26644 18921 40531 13139 6150 37871 63616 58292 44257 27079 23326 6017 9347 26762 53804 1655 4695 7134 8109 4751 59647 49596 14807 30012 15501 62304 23729 14326 52397 9751 6747 61375 20358 7928 57591 23354 48142 58881 40760 34813 62904 5047 6343 9400 41442 34233 35666 34681 22272 34480 53200 38977 59553 29236 59645 19272 21901 9010 34570 31187 41882 22083 63723 26500 6317 26119 25205 55953 38135 11134 15886 19005 51428 2667 53283 53865 32885 34670 53472 64381 23732 17521 57678 6604 2260 43897 7637 44224 46251 55279 14514 25881 20749 13653 3220 18209 18433 7181 29020 47384 44367 53789 36946 40840 12257 18879 2809 29696 4854 24484 39602 1260 48523 18785 9759 42514 51176 30755 36261 25583 16237 1052 45067 60339 21303 56604 55919 28614 32907 56256 26628 47138 59868 61454 31180 38914 14542 15305 53013 50979 34222 32921 53416 59826 33212 19197 11011 11403 40311 47461 37900 12866 53075 27175 8612 63780 36052 9423 33874 19409 7162 62169 61846 29794 24076 5886 1042 4867 18142 61979 42047 25552 35974 22590 5972 40818 40656 49322 52431 15907 8948 40323 16334 12854 50957 10837 55490 11685 24262 13571 5767 23430 58170 16794 57963 57851 24863 18517 17297 43584 56201 9026 37724 13090 22310 33589 56943 6252 33437 22565 13667 62534 3655 2712 4980 29048 24436 34517 5965 2368 37534 15800 26881 48033 58003 7490 35604 5176 7656 5542 45189 39876 6697 37786 9369 63891 15343 19880 35522 23478 63550 22658 8376 38252 33913 10558 21867 64187 22671 36024 34808 19772 9808 11208 11036 40118 9283 40466 52350 3433 19346 26378 59591 19138 22277 53823 46200 27775 27284 8854 342 22997 723 45802 46103 5867 7135 39882 24761 29559 24825 56106 23874 17466 42872 12525 42984 37305 16884 36376 11716 15228 38535 47278 31423 58600 59624 11028 4414 56341 33719 55061 5567 2944 20702 45886 39789 33836 28135 30921 34726 50177 46617 16345 44679 8204 7402 14219 50138 51430 56834 27099 23994 7036 8840 54127 28950 3240 10832 24463 30313 34533 56969 9221 24618 18756 50436 48239 51173 10371 61230 42916 52662 55857 10550 25176 1020 51107 11902 55605 52650 42698 41555 19474 37026 60998 16837 60602 50811 11744 8212 37120 59091 19268 686 27991 19415 17196 26921 46455 18575 24937 26172 20605 53707 37312 20701 2983 30449 4882 3997 31519 38013 13261 59690 4980 52890 8298 7528 4122 56641 59432 64447 62574 13614 44826 64144 12497 14764 46659 40801 4188 28581 7540 40573 33118 2073 41427 17035 58828 35103 47600 64004 40142 17530 16021 6545 12649 22997 7984 30795 20773 16943 51408 45010 51870 41120 34993 67 34211 33689 23212 28351 43026 22262 61686 25531 26726 53911 5095 54146 64504 29435 63876 24711 37669 34082 42329 41994 36267 34514 26851 9029 19612 13606 61930 16549 7397 42165 11465 59306 22961 10626 52607 55344 45175 14584 33063 11975 46640 41684 41359 46103 55210 50600 5527 60332 55857 1017 60756 8745 57810 51751 13489 11833 56674 52334 55180 58805 34173 54410 39043 42231 57121 45029 2009 1699 35286 56021 15348 2297 49296 55353 36796 49898 63613 28788 45691 23159 2217 21232 61416 58777 14869 38640 63778 56861 49220 26676 18654 51454 44866 23340 57741 26987 4516 36723 8503 9428 59692 30933 29874 6203 56696 54416 58060 28013 21017 11219 48596 38221 30850 63234 3503 7649 24869 34682 28278 1728 1400 48718 61350 40865 15582 57546 21999 44224 41527 18746 48219 58056 29290 29526 43080 12123 40585 62731 53554 41435 37995 3167 24032 45387 43062 24527 22529 33285 41299 20797 31224 23312 13245 63372 19412 45523 8370 6292 18870 15386 5704 4140 64218 5716 13238 23504 21669 15111 63115 9879 47201 42264 2209 20583 106 8114 52603 55448 57117 30344 47975 51238 58060 43341 7852 37119 31070 9443 64007 27208 10327 6252 26065 37813 20866 41354 60300 34514 48575 11719 299 18997 28724 39169 37837 41426 50226 40294 19521 39306 48823 57606 63503 19131 43629 18027 21914 24246 12272 24313 1443 42809 31550 63825 59024 51722 52436 14639 25409 35571 42447 6223 38540 7855 25280 19128 24584 61854 42609 37405 53500 2256 58635 19284 15793 54033 40150 61489 57167 24276 61265 21579 25446 2691 5284 48396 7639 55311 11556 28689 21488 14103 28759 50940 18586 4620 37697 64126 44329 49145 24576 28295 31719 22015 14058 51529 3599 10323 24337 37986 23452 39823 24822 62275 51895 46087 28408 60419 22908 52837 40433 47390 13794 37240 17541 64411 18486 53614 34326 41392 17059 20833 58447 27417 17780 53163 51123 2194 13234 5995 18830 46641 10178 31308 35944 35492 33639 62851 57532 35645 26981 60624 1740 49087 33650 16989 23174 7482 22632 62647 19334 7900 14725 30738 2392 29380 60293 42110 54008 46034 52082 56405 2366 57764 30910 54364 52943 46920 21162 11447 17050 59586 40696 23121 32814 48504 9509 38065 15015 26503 35549 19936 45299 20162 19129 21242 60701 62540 23954 1324 60880 48147 14824 42736 40282 26407 47419 34376 26490 10865 24297 21180 15246 58076 57348 55119 64214 990 30720 21608 47729 45982 44650 158 885 49303 2467 48538 14721 22529 15724 56469 43123 24808 25883 9608 43294 40286 49644 23913 19759 16446 4124 52796 2855 6914 49639 47706 55835 49620 42551 49546 58466 55520 22800 44394 52220 19167 54474 53301 24815 26897 12802 33940 14908 63020 20307 19378 47157 25166 49621 63702 21263 37529 63934 46068 5921 13251 28970 51358 7966 25694 6276 17180 58880 18617 17071 52105 36081 64323 58368 13135 59194 8566 24235 15998 59816 5942 48743 25643 10799 50295 44329 25632 50988 19904 23386 26893 10557 19948 25158 54262 48094 31352 63183 20605 44113 10737 41429 18253 61725 54672 52755 23349 59769 2473 15073 41422 21930 9333 52167 26722 46207 44904 28623 48846 37874 52564 41760 54121 61858 42680 46159 41379 12514 37128 28153 981 6857 13912 40559 29489 35745 1940 7391 6490 44459 48180 15555 2215 44548 36726 14795 46715 36599 1650 25264 43156 26829 13200 61629 21523 26776 54993 12668 55300 50520 50451 10715 9549 41883 50126 16974 17888 40513 27537 19971 54425 62478 11511 44435 3774 11660 43527 38830 47267 50959 28413 58983 30438 46241 55935 3420 28253 52247 41768 46035 44338 16619 56909 58623 18829 31684 52673 8775 29661 44931 14904 14728 39197 23670 22416 25050 56280 59896 53732 62608 63452 51033 10609 13736 3371 1354 26591 4766 58856 64245 33217 42827 48913 50486 5247 59081 64264 50075 13912 30320 22161 12374 64154 2230 57495 45220 37379 2066 27148 63263 62073 37615 13930 28749 3088 22467 1911 3108 23835 11253 5635 51761 43113 4536 2462 51480 59036 43433 58552 36358 15993 3708 29213 51536 45023 15058 9533 34218 45176 18244 61462 1398 7153 59515 19302 52017 23411 30689 22411 20266 62522 39018 19823 16257 61131 48781 45654 33634 337 7216 10456 58619 6654 2857 15798 39718 19124 39151 33109 54548 53606 39587 38268 3831 35968 1373 4898 28896 57880 17152 2358 29972 8608 40523 23812 40992 42998 47445 41595 44657 41255 26940 29953 33850 58066 15786 22072 37999 46453 47942 19744 43312 24806 53222 59117 47986 12559 39770 55051 55461 44552 5575 36314 5050 31200 60142 48678 2473 49201 52405 42922 39968 48022 3287 37512 44916 50185 19194 60610 40256 22224 34452 57611 39110 16482 15481 52870 19478 40127 34371 57540 24360 31436 45601 36944 56140 2397 23081 8327 39903 52246 61122 20628 17983 11604 4242 19599 22840 5938 8859 13743 55736 54348 902 53900 50432 52957 16613 444 56728 43903 34077 57940 25909 33801 1114 28586 6169 45181 28273 53130 51964 33443 6639 46949 55885 6930 25262 63193 60962 37624 5323 41601 4753 22880 46824 61293 33601 35001 4646 17092 936 48746 18776 19630 6447 63323 57215 15743 58712 56405 28396 57106 63907 36314 45010 14966 1274 35394 14058 27972 40316 42539 8391 38512 54287 36808 8026 8667 6614 58097 60143 23427 4821 6930 62918 5181 6732 54321 12794 16903 58961 2791 13772 38600 24862 971 58473 314 12415 7425 28700 41866 5031 64424 9893 6701 7853 21062 35185 49914 39956 19206 5361 60622 11973 18113 30401 46463 27266 27570 54003 48477 64240 26097 21464 9009 13316 2343 35104 53982 2438 48288 2324 52879 38561 24510 52103 44001 7619 61262 55870 15935 45290 54406 14050 47745 53878 1363 51906 40019 43007 43492 60179 39937 9437 19724 34963 62331 18533 39579 48393 59595 54305 0 1329285489 +1024 7056 36566 31554 43269 45204 49590 778 6237 24724 47287 36871 43439 15287 12171 12472 50648 63362 7067 30619 20019 55096 36964 61403 36874 37355 46063 45833 17672 63112 38126 31380 57593 14443 49532 30005 20654 20544 61938 28575 57733 44055 10699 36928 8224 2958 19980 55248 7271 35073 14792 36278 16968 40134 7740 48507 62129 55051 41557 17187 4428 48559 17523 15614 34104 57323 55811 13880 52427 44143 41577 30260 15169 31372 26752 12550 28347 23374 7815 11561 60997 11304 13820 43468 52810 42042 55454 54924 16290 37704 42818 22228 6026 61900 7857 21565 11735 8006 54177 12118 6283 25398 35124 3019 61068 62592 55285 60314 4604 16961 34111 32995 21789 27380 52076 48322 59720 44010 53980 46582 46944 63834 22183 55581 25608 51544 39984 36556 24700 57302 8571 58948 51691 26786 13418 16621 22874 15691 7134 13321 2405 26232 21975 31091 14603 55453 8840 1008 46740 10683 8041 58328 7089 45544 31618 53477 3933 51926 64228 57533 53607 14684 45701 48394 34314 62647 26287 4147 56966 12965 8885 45875 4844 50384 26239 6613 7235 7015 48861 17965 23104 37869 33407 50102 41357 49909 19256 49264 27748 33878 37502 34173 39536 35379 7790 2426 33857 18872 48015 20986 49527 9816 12982 49627 40675 24811 51023 51837 51174 57630 43275 62264 60476 27254 22321 35769 62274 34560 35729 43221 58621 23391 53452 53490 58967 54112 4469 35308 61991 16391 30940 62501 2911 28330 19689 31294 46266 13891 28110 40316 20756 31534 50373 61162 10627 28389 674 15420 34816 2292 44292 51178 12538 33133 44654 45103 57142 44474 56207 36952 36092 40867 35948 27849 28675 40294 41903 25196 640 44635 33170 5274 152 22667 21153 24008 52596 5740 1372 54564 48042 61132 38246 59623 38770 27685 44896 19115 6104 22232 3335 23354 20629 29596 57142 3384 30035 46873 39821 37953 8152 57072 59084 56581 3599 2112 21397 15704 55245 54081 54217 28412 41287 63823 14229 46503 40638 24297 5391 63188 7018 47892 61892 15172 29502 58490 53272 33287 29132 49221 16674 13057 50038 49749 50442 56432 2235 37397 53698 45856 39068 52269 45791 57301 6952 42364 45504 57352 54822 8574 23881 31492 9576 34137 38217 25629 13280 12058 26167 15090 4548 35508 20048 10566 28287 19550 59320 36841 42968 8508 22593 5615 37579 26113 37781 62559 47301 63060 54621 57091 29353 37062 55574 3416 27422 27856 10992 50893 62536 38059 29449 50024 23525 10916 1604 8334 60275 52907 40456 21549 22208 53106 13149 47250 21449 11642 31078 54121 46765 58941 51792 9295 41160 38200 29948 56785 64504 42053 61706 49503 5263 54723 57973 1297 49637 31364 46734 7577 61080 11832 57627 16554 59395 39002 34559 51914 17616 48519 12024 22081 41008 51118 23043 25276 46533 47211 20991 62287 61298 8642 62130 37679 5688 42552 14577 52185 5227 13750 19821 60641 59416 62048 4141 43377 41090 43683 57645 43202 55159 19589 25357 36823 53827 31433 60143 14213 16738 53516 41623 55581 13660 3223 60676 21531 11517 54541 4727 27709 39863 56402 62861 11878 53367 62948 234 57103 40325 13919 51878 15975 62582 24726 52556 20936 10806 10335 5436 18874 8381 37887 34647 29162 53730 29084 51463 2243 61681 35935 709 60038 20666 4624 8108 21404 23846 57736 6222 35935 33757 25025 50724 61081 57839 46418 23139 22702 35128 44501 57920 17590 54012 10849 54057 59351 59239 42728 3839 59375 7472 55871 59769 46570 27552 64354 42648 24819 6664 3919 15261 12607 16777 23154 9994 16476 34673 46960 23728 13363 10100 27773 52026 16980 48 24737 62949 14096 54287 49035 18608 38033 21236 20310 34002 7974 2349 41879 14443 54049 17712 10375 887 43503 30169 40608 11810 55631 60743 16535 57906 14322 7578 20479 35684 4263 8692 55416 5203 34664 63568 49157 20507 2700 18838 22691 1527 37066 16852 49593 56631 53573 282 55659 41505 27350 51492 13188 13910 52670 18308 19143 271 47765 47376 6348 59496 55607 56444 39014 45871 5539 16432 31410 18614 8444 44206 48834 24343 36478 61357 14466 41810 35451 11046 38595 63912 54642 37023 833 35377 21427 58811 5646 2441 29698 284 56361 21732 19406 16597 28481 62653 49288 33238 45191 37601 33369 53855 45616 31655 29247 34712 25774 51592 64038 45007 52500 47102 45985 33241 20940 38015 39890 31015 17532 62269 41997 25392 14106 52403 41232 38729 51001 48010 46223 56132 57769 49139 60955 11883 8349 15631 21583 9088 45367 53096 21431 38135 61297 40008 62028 8384 46747 21157 52747 14377 15263 40050 49430 43678 25309 54499 57408 35537 30404 20222 23823 49369 5591 14084 16093 14635 17791 40443 10425 30511 101 62225 35154 15597 49495 60608 25126 4594 25481 42199 44539 35025 10316 35854 7666 20884 9191 55878 51292 11683 12349 45606 36669 42852 22118 35965 62132 12138 14441 48062 7405 31366 14659 15448 2487 28425 31542 55216 57925 56975 33923 4448 59485 55543 35614 40954 50913 29834 35985 49585 41005 7323 53718 20013 17261 26046 44469 29312 3899 43960 16899 18510 47292 27443 42765 22374 55926 7942 57792 57163 56069 4398 39944 33689 52793 21290 54312 25823 38502 57545 11063 57257 2135 48701 27278 54053 13735 32998 12767 45740 26521 38862 9524 64237 37934 16157 53483 3636 35452 7550 58425 26830 13258 34408 43731 55357 16435 17059 23847 22657 56440 1753 36745 28470 24522 58799 63474 11347 64336 21891 55287 15728 12510 57335 17473 52996 61510 63016 38370 11611 55896 34783 57070 26861 27022 22869 59957 26845 35341 15086 49297 41689 14723 41968 27480 49600 7542 4894 41914 54845 12841 29678 30229 23074 25949 427 53771 40589 10208 5242 18279 60233 15698 33086 41278 12911 13370 32880 64400 52239 10000 62090 16895 41173 17431 10535 18540 52914 53825 56428 56045 7506 38472 31669 40444 45491 8225 54041 38548 35486 49209 6021 20616 26317 3249 45839 7505 34694 49947 38851 46832 14614 1462 38403 46263 24247 38935 19062 6456 645 19287 43545 25882 12243 52982 35638 27867 20012 17600 37952 2037 59438 47701 59923 34983 16176 51002 51646 20764 11001 57581 12131 14300 60622 17112 32931 48232 10116 29037 26237 24494 63582 63016 61111 56310 993 40633 50183 47537 5341 5635 28979 58695 7310 13515 60095 19960 35071 3820 8116 818 36786 28027 6654 44485 15184 28881 6357 19245 2975 40374 63850 36743 57545 5688 62296 50018 12774 63196 7560 62749 2413 31619 42455 6418 28135 29786 23611 40356 29859 61371 52073 13348 5758 7601 24067 29491 5638 37092 15083 19947 55346 8105 35479 50308 52029 49458 6583 13087 40870 50516 23541 9346 52277 8827 17792 54715 63776 5487 50980 58636 3989 39 1162 34850 46933 47217 60183 27258 33830 37123 16925 6873 29675 44046 17969 3011 31358 9040 159 24526 56684 43622 64404 61056 25011 62098 9258 51843 30031 21722 45740 6236 46366 37025 26302 24488 15334 27467 14281 41887 19303 33334 43021 30488 25278 51349 7827 6496 4313 40898 39537 60898 51180 15725 24929 53659 43302 9824 45340 47981 5087 963 3746 14575 2673 22506 20732 50648 63468 46232 13987 34070 7603 15574 19302 29764 36525 35794 34598 6379 35260 63096 63800 47947 12170 35562 59055 36610 38374 46268 11375 41200 49774 21020 50107 7065 5541 62411 34795 49048 61556 42117 27841 12045 56224 4590 37852 42647 52369 57296 20835 10078 14093 28225 25938 6348 35111 14799 62447 14174 30367 63448 11042 6333 13705 19017 42758 42401 30837 7841 45412 19592 3993 9311 3654 25980 10328 42877 47535 35443 2198 33910 28553 33088 22432 33589 48053 31431 30055 44018 27502 56951 49836 19836 31440 35408 28141 16724 43697 7763 58865 5478 46909 22200 45576 29850 4582 10938 23856 26103 54036 45511 64477 60160 47317 26836 43693 30579 59004 12788 63056 47334 5851 24300 17212 53560 22378 44472 17370 58014 49126 17468 57396 34096 63972 18114 2881 24958 4707 15470 25469 46879 626 25945 33654 3319 50647 55491 7355 12078 6374 8210 398 34359 22972 16175 40781 58380 8224 50795 447 56712 33229 33916 2584 20380 18041 31528 22906 40911 4463 35327 12347 672 64181 4865 27968 59410 9799 47011 23603 26298 16495 43269 43328 41559 21696 23327 32888 27055 58017 50727 25488 56322 44916 37255 53076 4282 30132 60699 4754 35647 46594 385 38932 56774 19905 50492 43979 44538 45704 46132 16863 21125 37110 63586 45882 27114 36300 602 47093 20404 32790 33613 24765 47064 23162 34538 58915 12582 60872 50149 9950 53787 1859 17205 42661 25397 41657 15074 53286 27490 4559 56549 34059 13202 29424 5572 5713 14640 34619 48205 9827 9417 42788 34338 27597 2115 6953 36519 42500 44053 42726 2002 48586 56204 31057 21425 7542 190 62568 29228 33296 27953 19221 2574 47674 25875 37184 52034 8133 22052 55091 11756 10728 31357 30737 58614 14940 3423 36826 39907 43813 43900 8820 49677 4779 62399 28150 15652 39072 4844 20096 12711 3455 22439 49272 57797 40682 1007 33593 43150 1680 63467 47590 47956 8496 33869 55664 59656 53403 42370 63126 35417 17580 54024 37262 43692 1125 52242 42659 44893 10538 59993 21661 33185 24589 24218 28330 11331 18677 43985 20815 5641 19122 3952 12098 28366 28088 6329 8940 45700 63443 57774 20327 58620 30437 63714 18069 5286 2678 42652 16227 20370 25501 59534 29821 1779 50886 4336 13757 6509 53462 36670 61700 45230 380 20097 37391 5639 50501 2173 34240 25349 43386 11564 56118 59945 49349 46239 11514 59114 20048 62606 13783 56262 7972 59938 37203 26037 8981 59830 10724 57875 13806 37672 24762 37860 2366 61613 38521 53035 39402 45849 23052 36332 60364 22002 15894 63643 8919 50149 13468 16749 25033 62061 4474 41854 30838 17568 28923 27085 53046 28682 38158 42182 58144 26313 44023 23263 56662 25217 55086 45013 33975 38623 34735 22080 50714 31543 20151 38893 2892 22125 53766 12757 62386 36168 58020 11138 23591 7218 1847 46431 8857 59078 44162 62340 14500 27008 54394 0 39387 29636 41983 59169 4997 3352 63208 19165 49943 1267 34778 46541 61571 1793 3569 20611 41558 10999 18445 46358 34779 35316 20295 11121 3452 34606 6890 24412 33669 56056 13347 20100 37666 12885 6471 6891 30392 25948 52944 44359 4463 51663 1744 47423 29697 1293 47667 7245 41606 9261 62011 54240 11937 60022 2131 57871 21977 45423 44206 26730 24399 13783 29810 24429 44828 51887 14152 10049 6409 9161 57697 31558 52609 35866 9507 26029 28816 10463 63653 63094 50455 24084 36371 45730 14796 37138 19366 23007 6177 694 4760 3295 22358 17039 28196 50023 51883 52583 58403 1083 29628 49343 31703 4978 36614 57671 21027 59039 12287 53598 35815 6213 30716 48422 19883 59585 7410 36157 40814 5118 20518 348 20682 6568 51416 25784 63446 55034 41227 36902 26911 41227 52552 52887 39786 31608 14544 52962 2025 43239 22347 22991 55429 57529 12598 64183 60882 14448 20986 33520 53243 55044 33589 57459 41013 9989 6239 14690 8955 45612 4087 18742 17818 48863 17496 58374 39419 17964 19998 27266 38950 26385 43220 15017 3829 15697 5814 62908 45231 13371 50802 2965 13858 35442 57950 15907 21152 51029 46463 9641 25181 54316 61609 62453 82 10811 33522 28526 60384 50659 41651 61138 41517 16147 54797 27172 14684 5643 22953 19706 16076 21495 36818 33688 24333 15803 23805 9041 44931 20743 3945 58807 30106 26035 34000 33394 38130 62021 41418 62214 22234 16584 45801 1670 62452 22892 54615 15104 17056 60676 40763 27154 14394 20852 4528 8556 15265 57131 59087 61192 5517 63583 43364 60841 57545 45790 49150 11124 46336 19959 46965 17511 3053 63204 7158 43252 33276 57710 36954 27850 21878 62909 1077 27659 2756 34013 39992 54316 18841 13961 63244 56175 23538 63839 39879 64404 16031 36532 64442 37576 998 49597 13756 4363 10060 54206 49198 31380 53390 37957 10998 35824 3974 34824 6626 63075 38165 38686 4953 25623 56562 38555 29872 49657 48069 45596 37317 19353 61106 5093 48327 44539 7885 51059 13647 6344 32795 248 5199 42374 57883 62690 198 33127 21894 43953 32796 26569 31305 62779 57375 22185 52460 33220 2107 14781 2643 27708 52653 48796 63125 58507 23541 43303 39806 47042 41130 27068 247 45251 35588 12147 38938 15272 38094 15882 23835 14007 14326 54331 20858 14538 8236 17850 62291 61306 55984 46696 54752 49783 8493 27939 33337 2670 29515 4425 39796 3498 42785 61430 8703 28632 22836 22870 35919 50340 979 27353 16141 18260 16562 11166 43157 26746 5528 49727 60273 24234 1185 36883 38287 51067 4864 7698 5284 41050 22206 22026 2867 5814 49925 47453 28512 57564 62012 1081 61058 48040 19056 42685 18048 11312 17367 13153 57024 19498 50623 48004 53506 37184 60412 11691 19978 33643 30726 29947 5326 12163 9140 1511 57925 0 1333911104 +1024 58800 37992 1288 59403 35592 37371 4529 56461 17387 51274 46702 4837 1543 42311 46689 53636 41985 41109 7180 60854 28163 34628 30801 7846 25539 5829 23320 53968 16955 11443 35497 51809 790 23499 2399 55 60567 42390 40476 29482 13810 6261 40646 56005 52833 25575 16043 56956 4728 51239 16242 36299 40368 37753 56092 40669 43085 55489 48754 22430 37339 58951 46836 49635 42542 10609 7146 63899 41808 46400 5073 43986 44222 21094 18341 31600 6410 52414 33983 29197 58593 40039 60682 34140 6750 55176 37693 18887 13156 25807 39165 9105 60437 60469 37856 27125 12365 2325 43192 47413 7531 41929 39781 58479 28581 18387 7537 53371 29128 45972 50520 9034 50873 15832 45596 59539 44792 2525 16563 47337 38531 14021 16143 55833 25680 11287 4390 38819 60044 56317 21238 6213 28367 5531 41136 45789 55334 34669 50048 20601 11934 37326 15316 34644 61793 37572 3845 26500 33067 47658 48428 2710 27313 15736 56571 25680 33482 48023 19816 21992 34594 61547 13840 3581 44860 44565 59533 13645 11712 34302 6637 62827 7778 64133 37007 42588 56344 12391 23359 40829 28065 51430 25709 50938 46884 37783 24751 39664 53480 63032 1594 31182 15364 33393 53806 30525 938 56447 27860 48797 26381 19734 50557 48379 34919 10002 63915 52219 55927 28968 57314 31509 36116 30719 31466 57539 22411 43396 10449 30644 53173 33525 47841 42054 9990 24600 7935 40816 52357 35603 29376 45709 57948 11605 19873 44750 11993 17246 42387 892 18592 25442 23908 54972 57668 51943 26027 37180 50788 18315 40089 34055 49794 42970 10914 4121 59814 29982 41053 34054 182 59476 27599 1250 39678 63423 8000 58656 1213 44204 54137 36826 34491 55610 63828 54189 51429 38034 19097 36618 30849 27506 41974 57994 2279 25690 61227 2523 6137 43247 26628 26951 58551 13996 10625 62343 8651 51137 4048 38895 29231 33285 36911 26291 60166 26965 37171 15090 260 30762 50634 14646 25837 59265 35479 61993 46607 30081 59726 5915 43055 29289 9164 62688 61811 59934 47243 63866 52093 48393 3817 21025 5258 51633 64138 11579 60890 44033 8379 47054 30943 54286 37012 24532 42168 48021 64356 14160 28999 33734 41170 15295 54427 7605 28341 11537 8404 60584 57555 52994 5209 57696 11153 30761 2958 9995 39489 48150 24060 42840 63876 8777 11720 59475 17262 13150 61211 45789 25368 9146 60314 50311 60383 64357 33111 29851 29488 38086 6223 54362 48949 18159 50519 48040 4019 44197 18433 3127 2911 62684 50909 9854 54528 42170 44131 26800 63632 41986 14315 45925 7394 58535 42905 22907 10048 14799 17327 25064 34215 33390 29575 34567 291 48218 52740 5991 22142 28030 14359 34542 21330 40876 41612 23560 34330 10531 4160 9649 51385 54228 11736 13832 6234 2575 36688 13941 62048 3392 61558 50856 43659 40538 20049 38296 31519 38492 11201 21216 6072 17784 45956 9585 24403 49596 16655 52042 18003 21112 53932 3699 54485 17300 29411 26186 5399 5172 4391 47312 10375 42393 14972 23703 51849 23534 13229 61083 5438 13552 20251 4994 4682 18999 35149 6504 60511 44323 30085 13261 60113 12651 5093 3979 38319 22213 62981 30775 53259 32917 13421 52371 56529 10159 54239 47557 48348 29953 57028 1669 19234 60057 38205 49869 57520 36222 54725 19687 39004 24973 24372 20729 28857 45629 26360 27940 34527 18235 60621 15677 42065 2042 15113 34598 31403 25200 53031 34218 15456 44864 45047 38391 7981 49548 13315 64405 26692 55817 45879 44759 46676 11175 42450 48741 38692 45431 52811 22184 22194 34387 53911 37818 49824 4617 54446 64249 9215 45003 57158 11111 61298 49562 3922 27455 38289 24765 45617 33799 60872 41727 1253 42609 59114 43955 28092 36695 19618 34149 53117 27024 29876 43264 51537 12285 51070 721 3023 42863 11698 45447 33865 43224 1886 7304 54952 64167 41597 28426 5617 64224 39051 11349 7819 51450 25757 43224 16727 17134 20252 33986 55140 7382 28770 2167 2664 53483 49130 26319 7715 51552 5475 5529 51632 39528 17899 8263 60515 42571 58862 24713 50068 15514 47076 28543 63608 43126 16906 2731 4634 43928 54489 41240 63887 13952 616 55144 40643 34276 38555 54694 12051 26598 60485 39131 36212 63832 28995 57523 23249 12360 63140 3093 6400 39355 18299 15026 28955 46893 19700 43969 37320 8139 62816 3006 51394 11913 36197 56234 28392 15263 4564 48126 50900 54808 42235 26259 60937 50188 44535 38574 40517 21765 61176 11141 63457 6432 49528 60794 38510 47810 11318 2440 39195 26458 27234 63817 47890 7444 50930 43993 20825 13704 15302 43912 32909 27320 12640 13853 15512 30765 41856 45604 52605 17328 64471 22780 45 54230 52507 8881 11565 55542 10710 32939 37028 35300 54096 39480 47844 13694 21222 38779 35301 34281 37259 47058 34398 16850 24724 12433 39985 56642 58698 54767 54890 19758 31556 44504 62217 61761 7927 38754 62586 46202 58781 24263 44069 23047 35691 38302 46028 14888 41679 35539 63463 44143 39996 916 61499 54301 35956 50343 24895 52393 14703 60330 18997 21319 31463 32803 37307 45128 24534 59333 30164 54513 7538 36874 30792 27452 22722 38309 36048 44469 5740 36822 26687 24580 44622 45313 37790 7324 59804 48182 22918 26396 4889 11858 23977 28766 30626 55691 15495 25960 11676 19195 1879 37294 50231 19116 6615 40734 50805 50677 15425 58504 29697 31644 61010 10301 62843 5062 14829 4994 42097 51580 52409 38266 53285 36290 42594 34977 40596 58189 38299 39956 33522 7265 26967 43835 1767 11477 32891 17260 29848 34950 42744 50322 49559 12711 34907 27800 1548 1670 61131 44840 43571 15211 40593 22766 57508 17897 21723 27751 51532 34223 12296 54020 39217 45781 64437 20823 52621 15614 36281 36324 46551 18206 52697 58964 44009 3502 52964 33509 22886 26676 61266 14642 2426 45736 63607 37996 51698 42216 13451 3346 50126 58526 16452 43201 34704 26751 31655 18488 46718 16834 56509 52597 17513 32972 20445 16487 51332 14819 59954 59250 15128 24547 57583 54725 43725 1890 10345 1592 54571 17081 24482 12728 5601 40829 5041 3322 50845 40922 21305 6202 22334 36343 36505 52792 4770 6643 24841 40257 47257 37811 34301 49341 7639 52470 22477 40575 37476 63302 57772 55879 37666 26251 48116 46121 35085 24261 31024 53490 48794 21924 21589 60901 45160 22350 23821 21670 6872 5442 1402 26633 1484 63363 62687 12770 4595 52422 34242 48400 48809 50810 3209 2877 15863 48657 17868 60179 50017 8465 14197 8508 39294 44925 29030 40110 57230 36347 3537 26398 49836 38353 56004 47023 20158 16754 14452 36754 26241 18335 29356 15265 34990 14696 34098 63284 34908 13379 41144 19430 1278 27033 792 51826 1505 31700 4398 64133 61887 20980 27348 12290 22564 42000 18687 21836 46040 21968 36306 52841 60704 11715 40501 41654 55873 29445 9831 4703 10634 30544 35149 10200 48697 25522 26511 47430 57956 19658 16200 10657 58515 28402 53432 9504 2092 25229 11724 17553 6061 36428 27883 57905 35843 29733 35018 21779 63521 23632 54482 8872 24988 20588 15055 25858 36859 1959 25841 44280 34005 7460 506 60057 58960 50632 11988 61185 14026 36463 34819 13787 52004 23639 25853 28832 34599 8887 44358 60454 45186 28781 2742 33294 15302 24177 20173 60641 21986 50428 18717 43203 27757 26868 60648 53915 40032 27848 41656 53027 35026 231 28304 60878 4829 28090 6786 40617 44527 14784 61886 14018 1922 47297 45144 50361 54841 49541 35555 54107 59100 31626 39297 993 10183 21166 12231 28290 18659 10228 23713 36071 10121 18867 62393 45886 9066 6819 62820 23248 31150 2414 47283 63727 16064 52526 43747 30344 165 16876 22618 22904 11315 40059 61391 17822 52530 42793 27540 45746 54543 8383 10452 54043 10847 49875 59521 9798 54657 38332 22032 58627 56396 6697 50864 38115 7581 54173 33318 51989 51669 34168 17807 7652 1029 6029 6470 28178 6112 17312 28108 19915 61687 5672 11577 20021 9273 62600 31104 59832 26112 11731 12827 39273 28344 18545 29593 43315 47839 46306 38566 38466 57016 24362 48183 39052 19385 19919 43075 56715 4234 27220 19280 16681 17707 17720 33960 7679 53807 27534 49772 4404 34784 9717 51097 40286 21063 47711 45286 43023 9709 16737 19702 36205 44547 51644 52087 60268 44362 60141 62597 21081 2377 56858 19149 42179 3092 16216 6413 25577 42100 64422 44566 24323 24126 26830 30823 18582 33197 10436 20197 17651 25698 10227 30039 6430 44061 39003 47443 26102 23401 5076 63649 63970 60339 4091 25393 38551 35720 29691 27642 51889 35646 53543 2379 14459 12168 23666 59364 17720 25352 7363 7218 41166 42916 63067 27465 23188 7226 47498 54849 7419 318 49432 27845 36019 44856 33361 49318 6361 19926 13752 19383 26180 38013 44340 786 41015 1441 57955 39587 1519 56357 63252 53087 40535 54853 33828 25720 2730 38887 50468 49255 42690 50940 3526 46243 49876 19211 17160 2366 6940 11925 42065 4639 16488 36425 16123 36350 33079 51874 61902 15952 59183 36598 5159 39750 51337 38879 16057 38030 25018 39437 5110 1217 20302 7226 840 14531 51195 42752 37882 48638 1609 33804 60304 19115 26145 53047 59749 38588 9148 2728 4441 38416 33098 39255 49539 17772 52055 60027 10799 44053 61382 31368 55760 57434 33864 31429 39845 41562 20395 6013 46246 9250 30682 50619 53385 38416 43784 27836 54715 9427 5190 48901 27379 25657 16471 20814 4491 30576 18533 34768 54663 29494 36469 16802 167 22112 48325 21862 24568 37072 60954 31386 5085 22499 15975 62973 17591 12457 43953 26944 5070 57620 35844 5858 45871 52142 61491 22283 21813 41367 39877 1673 7648 59206 28566 39232 30437 61891 46489 10872 30126 64416 63173 33874 36103 23059 25950 48838 48354 11339 11616 48983 41237 25501 54658 6151 35235 54467 1617 46819 61245 679 49379 44297 1200 5748 56522 44097 40844 27843 61853 28900 49635 35816 11422 57532 38873 27872 45182 33615 2516 18425 62831 60239 50631 59109 45533 56686 24611 317 59833 54303 48326 39451 51146 28620 55370 42080 34837 28101 4785 1442 8544 62848 53132 19081 16930 22013 35950 21434 33475 31269 39231 31314 17914 62829 43001 19333 11255 24861 22661 45942 47762 40048 3751 44156 53325 47936 2311 44444 4003 34574 11859 25105 17584 10378 50942 27976 44601 19154 58005 32843 35178 7045 33344 63849 40621 48675 43730 26690 4907 27564 34385 55042 29925 52798 6638 61032 25509 20160 29658 59099 9189 44488 10208 26346 57029 51573 29098 24974 24940 59518 18365 61713 40032 35477 59694 40814 43958 17188 50489 50676 27251 28637 4667 59776 40109 27979 24646 20864 34898 52876 20322 16432 55808 11334 3681 27852 46904 10177 14850 47338 62032 52123 34129 63256 15817 41675 40314 37938 51773 19318 44743 40014 34169 53845 54201 57370 17918 53744 16175 51425 60439 44144 871 10706 35722 47996 52811 19884 30158 20764 26305 213 21692 51571 15999 6916 60693 39035 42082 56368 62204 13944 61155 62313 40380 175 41502 54560 51031 23468 18225 54040 12323 2722 47514 27752 26036 56417 59830 574 43225 51121 17002 25115 50003 38355 57403 59253 63094 12097 48923 20899 37905 60564 45636 17949 46604 23726 22624 39105 45708 55712 49124 30576 2466 2642 43707 31734 50149 22838 28882 13618 44285 41982 49391 748 4508 817 9835 48741 36114 7308 54269 50624 17887 50590 41776 58730 16300 30396 35567 15072 58053 15992 47619 16421 24387 59407 50072 47572 44704 59796 42428 8143 26568 19615 61674 38553 61542 40342 24566 12161 52159 34932 4233 11579 40891 6011 11599 7773 5842 40414 26388 5208 61990 25710 46020 3518 42853 28587 30074 36923 27770 17135 18236 40423 13726 1139 8746 20272 38698 16778 1880 45708 25688 54894 48457 4356 64153 56998 673 22708 50400 36822 15431 56928 23836 15594 48769 36478 57911 6381 35315 30663 50583 54144 27281 21247 17491 14447 57314 32792 25953 42276 4490 5173 22742 24492 19095 45927 39594 55174 22946 42516 33640 50912 24481 13185 33700 445 14029 9488 38613 34732 11321 43478 61368 41069 13936 34721 40580 40919 33953 61248 57156 18134 15845 62153 43095 12208 49436 51190 30315 21122 6745 7529 6053 2404 42881 34078 56477 53369 22290 3541 21712 47989 47820 11918 41223 42577 49413 41580 14207 43604 56614 22553 616 13337 18789 59770 19071 9288 6219 22221 56759 58024 15233 64350 24812 23787 207 37259 35276 18776 30432 31615 14441 34667 45689 25046 42328 39183 41922 24048 5586 58302 5054 58062 26794 56747 13864 48526 41806 48560 62283 41724 2951 6722 33317 29206 42639 19467 43707 30101 17394 24238 50314 51959 7451 58846 10746 9215 55073 3068 5686 50279 1621 35198 24071 25476 12903 58081 34995 29642 11887 3682 24377 35023 16445 56763 49594 56105 38447 31055 15656 3713 5026 28534 6792 26793 64014 14055 44212 0 1333578933 +1024 60040 37503 61108 30904 55448 21544 2396 15361 63810 50657 5462 1354 512 13638 2217 9155 28989 21374 3501 11804 56573 34786 23813 18738 41955 8703 6753 60260 36614 27448 41276 38712 10209 5161 63825 28886 26913 27772 48919 53780 45291 39930 5354 51273 2219 55261 10657 19587 224 14043 48814 16119 33708 5936 26749 21831 31312 49024 18546 26801 37287 22339 15908 27282 50647 17768 39564 9330 9325 40808 11989 60320 30721 62865 31571 49403 24212 7972 60113 31716 14289 28013 28639 55978 1443 2736 10261 23608 45532 31194 39837 47633 3574 30566 58894 56329 23699 3238 2447 29147 43250 6673 47234 50765 40265 53977 1540 35306 35464 36567 25774 1041 52755 585 17384 53504 58658 15714 58665 16602 18526 61168 15656 27636 12676 17876 45863 23089 29682 37424 37903 10247 27641 23158 45833 51609 24535 44546 26624 60344 47956 45508 23648 49671 8744 28378 52267 19224 60827 22000 31164 27208 1941 28150 12442 25327 38322 48346 13018 33505 13295 1314 56577 29357 37068 16935 27200 61222 7926 51386 7899 20349 12575 19956 2417 24067 23587 42840 55740 44146 12634 24494 19185 46533 6677 57568 39221 56865 57010 20067 10936 60123 13357 48115 540 50391 39190 793 11809 33527 25695 31388 42024 62346 54555 36420 18532 36311 20710 38567 23103 8591 17701 4676 5555 60006 16673 35725 43732 61497 22215 53180 50887 12919 15328 7507 39690 1167 42269 60945 34751 5090 29101 59007 12150 45077 60161 59599 8736 37483 30228 36427 4281 43715 1765 14704 31582 61515 21537 60881 8073 46986 52252 6519 60481 15590 56563 8351 53218 23308 18483 33940 37926 6346 50627 31228 53042 8733 33789 9434 28523 197 34310 51353 21162 9065 37259 7278 25252 23302 56984 7860 27290 47366 28443 28812 17054 2036 57836 58949 35018 3356 63515 40816 58300 33231 7604 4912 17336 40776 57088 31320 59997 63460 35776 55492 25628 3121 39288 9773 15630 29578 9986 8443 4055 25397 20027 12806 11142 16086 34186 41185 53367 33581 45520 10984 23042 31261 43682 27621 61757 40636 30072 20491 38466 54265 14749 43430 29609 14906 62297 656 60829 41953 21933 45147 824 26686 4450 40490 743 23847 49921 44691 59991 17424 19683 50483 29844 57403 30532 19052 34524 50710 21027 2681 10159 18177 44813 53422 19286 36750 4282 56629 57147 56873 59941 37598 52075 56724 38611 4675 56694 20992 638 53473 22592 56794 21333 14915 48803 28273 24606 24096 17699 52150 56145 18353 61930 46767 10071 54731 46192 54478 39643 30944 46883 34303 28022 24746 39929 63072 58723 20298 50798 2604 33350 27402 7915 258 57753 29363 24158 58202 5925 20735 58708 28125 50473 48565 2489 30409 20865 42988 35116 21527 44212 20015 49603 61173 5948 53838 10042 15799 51702 56204 62400 29569 59710 50600 51475 10740 53736 58040 62323 49727 5521 63368 29047 56182 35433 56868 17673 51725 8778 1976 9064 31142 39007 49074 45364 38680 22233 39933 39281 27243 10929 43177 22856 47196 10632 58459 40212 519 45497 15539 40162 55571 3993 4383 32956 22741 9026 3469 54197 62045 4465 19044 6779 26167 14533 43756 12646 11041 50779 1009 16589 56858 38590 5256 2772 20735 59081 13300 18242 18955 20692 22021 46715 35476 1383 57507 51850 4534 10525 42958 59173 12885 4681 34350 29871 10767 16872 25329 58109 4680 42635 57240 5088 58289 48564 45785 57372 19984 37265 46681 46558 64057 41243 19637 15368 53754 5961 51846 46858 36291 10578 48646 20175 55956 168 2560 25676 17716 11242 54505 52267 16296 61379 1323 44879 16157 44455 10737 57664 19133 31010 37112 9145 44534 29167 33120 60715 41984 37050 1051 63694 1050 62919 10091 56531 37631 43964 25796 62597 1126 1919 33830 37368 39657 55736 39294 60492 12091 21209 52876 11919 27422 48054 20560 51708 7880 52320 25592 51923 24987 60504 24524 38944 55318 60025 52198 44 20751 20583 25237 27707 56612 29549 61885 29960 42902 19216 6302 37900 35406 47369 27602 56563 47024 11426 38185 62348 51055 8445 23729 22807 10893 25710 6176 52286 39508 51150 58156 20082 15456 25448 9154 24340 64297 36763 15453 47798 54307 46182 38046 46150 51382 13399 1858 22476 25820 48586 40114 36818 27563 60679 25709 34395 33461 4418 22635 25350 29233 37572 46112 53715 36941 50810 54381 28850 27328 31603 56634 28402 50348 45817 9541 57886 8653 45840 46476 21139 30339 10392 47695 18812 40689 14261 16764 25690 23758 305 7648 42415 35883 24400 25202 13494 2841 6252 51464 14083 27419 62701 4918 43071 46383 13290 23854 44991 22083 58166 22832 42661 22555 41545 8238 17631 43360 36196 46832 3288 52299 11125 51884 22095 31701 2071 21423 63540 17470 40902 43885 3509 39273 20927 13414 25759 45755 26457 3573 881 859 50991 27465 63804 17543 45355 46155 23213 37217 61793 45317 48822 19296 26437 34413 21196 14109 41707 41831 57010 51662 50853 33012 47351 5638 51000 34318 314 62075 45790 34984 42378 35839 11363 18206 53225 33469 63105 56786 54601 22033 56932 45227 23790 7080 60944 18372 832 51750 27661 4102 53217 96 54392 33664 54908 23337 39139 48543 47030 59240 33549 4177 11304 21504 58510 38895 10059 14433 33824 22990 4808 34463 61703 53684 15858 6306 4642 16695 55231 63049 20437 37658 30450 7677 53217 10029 7502 31391 27159 24765 7334 15550 34173 19894 61057 44844 36744 6627 59454 3391 28981 37961 30544 2628 21027 60596 38240 11945 29408 44988 33533 55127 33442 54190 17717 13327 14134 14240 37785 59804 7246 44130 57938 19137 37046 11640 57252 56068 43966 27190 36711 27054 12481 39493 30359 33369 45809 44691 33920 38343 35476 38008 2812 2615 40227 35478 16135 24342 40987 36371 38675 59491 48272 60472 10683 55315 51643 58960 15202 6839 43861 22967 44133 10202 42685 30731 41321 26278 55695 56716 49588 5479 13415 45053 63211 4116 37496 30221 28233 7132 38509 50354 23943 7048 1094 39765 26062 29329 9869 4441 563 23877 28153 40616 36725 22786 39371 15330 51458 46535 12172 6824 42111 17057 35277 30358 33733 19843 58429 34914 14656 29422 2955 9897 3384 22580 9149 22453 44690 42102 19313 7873 16348 26159 53370 4380 15287 6598 15326 53722 63594 24073 47460 249 60122 963 43629 17123 54368 3397 3324 8199 31077 61958 25011 39695 61476 801 27742 51124 28662 27181 34673 40093 62698 57777 14672 48950 54716 55410 6358 35029 17684 60702 38112 45225 9445 17726 13809 62334 51447 10235 5305 49095 5750 52041 41594 50026 55255 12771 4877 31535 3965 31574 42820 46388 7638 7589 43668 29312 2719 17425 21472 55513 49326 19887 48641 26034 27356 58278 253 38156 42283 43619 43545 41938 153 53479 53284 20016 9758 20065 33145 24059 9341 43494 30589 690 18043 40309 881 41178 10742 31520 25260 49336 39872 25466 50608 14780 47891 43127 25489 62667 33398 25782 57735 40724 12233 40901 44823 13805 19178 10240 5263 11495 26467 9685 51947 57037 43781 40967 55848 38275 9670 46318 27392 27931 38041 40660 51923 11535 23289 15372 10599 51881 53064 60959 48432 20615 39553 4317 36804 41849 55966 56884 54692 30861 12850 20075 62754 21190 25695 29368 12912 44693 2192 18481 4070 18199 23338 30744 42742 24354 41288 24918 11515 2450 47109 35471 33961 2629 52 41396 21982 27169 40030 24141 50934 43370 15188 41388 4945 44958 32829 57426 44340 53747 2585 59166 19892 34654 30382 21241 48491 50181 18426 57339 7559 56844 2167 58979 63357 43415 29129 29093 20781 4058 28855 3608 58509 35111 49469 12800 59816 21727 5720 15589 30161 702 28780 5648 19198 57781 60104 29598 43159 19295 36968 62658 7617 15736 16827 16107 4749 22181 5994 6454 53907 39509 4515 52041 33388 4527 49003 38708 25414 18783 26992 46700 30605 10997 17304 7355 56736 61853 30575 39032 47247 62283 59 39686 5005 63171 56210 15048 19881 42466 44405 18665 63588 62579 3 17985 45903 25525 56581 23107 14757 43569 11650 46406 20015 12126 38459 11423 54849 64321 57722 10363 30178 50939 23699 36240 525 34817 33625 10398 42543 36760 8205 28248 34542 42652 60725 20942 52160 43812 39930 26134 16305 23797 18872 1761 20449 49652 37 1984 801 36130 25692 57789 56047 59753 18189 7469 24242 55433 59360 42362 53864 14336 28478 780 35774 57859 43059 33238 22270 57750 35196 41933 37488 44388 39803 10262 55628 35961 38830 62917 59116 34274 48947 62886 36452 63134 11033 36258 12535 28053 34176 40913 58183 6188 38436 57833 47980 7359 23394 54240 10471 1707 56480 19198 34104 6304 21015 48897 34252 62939 54600 9235 38014 5726 41251 11415 29668 33163 60441 19099 8589 50302 8277 29657 14213 12966 9934 13599 49529 35358 14447 7625 18384 19456 10561 56459 63779 38766 37940 38199 26692 8937 60695 217 30961 34760 47882 20882 7455 33017 52216 31096 62468 34882 60666 61192 31399 62940 22124 47969 56321 14683 51085 18228 13642 25677 52603 17266 50447 21644 23745 6237 14669 46971 14710 30021 2836 33625 40689 2375 39342 29744 3294 33990 10762 51295 39467 63031 63336 34439 37551 27303 48367 54003 33076 22453 30350 57041 26913 26477 46504 35171 40367 36043 23172 29329 6427 58140 22957 27476 13066 62198 28060 55774 35479 14363 40745 5563 19107 24043 4759 40649 6376 49097 28039 62619 24011 64456 19230 19430 11642 48218 35175 24444 7553 28209 53442 20581 33985 11182 14018 3716 1215 23294 33798 15328 8781 58879 21747 3331 49293 25821 25370 37892 27663 814 62485 9399 46364 4501 15533 23496 58376 20312 24049 2586 52362 43614 634 17951 11802 64357 52227 45534 17430 36750 24769 8391 801 5371 811 30613 62174 55638 14551 9796 22662 47407 59793 33382 335 25965 61902 5179 28886 58403 12972 51682 34519 61462 30185 6407 33064 26725 12538 34758 34058 50589 29528 47594 53648 29489 34344 45470 46643 5561 22410 19956 4694 1906 31729 41402 38372 42414 62996 23777 23755 24138 5366 492 61700 3882 56727 15840 31715 59217 30849 43821 39484 50398 39654 45596 33888 5598 20916 36822 8472 28624 59561 28497 24169 24988 39741 3035 8818 26957 6070 45596 51412 46865 37647 41014 24529 7058 16463 19594 60585 38330 2893 29813 55631 2503 17715 36191 45799 23866 1943 17820 63657 26317 33648 2361 43585 43390 39252 29439 7903 16557 4632 22530 22130 3629 59264 1247 35600 61574 52185 55887 64165 53204 992 3172 4486 16766 14681 11222 52120 61221 41708 9558 53771 48664 30298 49925 14047 35091 33004 44690 11659 48449 40637 47238 22003 49574 9835 19167 13621 55 43105 1716 35362 34893 33148 30406 28379 62327 5545 113 15221 46526 19805 21953 64318 7920 19461 41838 2265 44484 33360 46697 4265 17370 24021 20787 52510 6095 4691 51735 1213 58097 33616 62109 59239 8996 14121 29602 52042 46189 51772 50350 18687 29255 48773 74 17685 14543 48875 3446 39904 51485 10879 35859 50192 19642 62289 44742 44578 60101 43703 13124 50973 12408 29662 25226 56028 9890 23389 42498 43743 32931 15073 19696 59719 57610 9000 8947 41281 41205 5821 49115 16261 55614 36427 11535 22232 5742 11652 22723 49783 12736 63472 40600 6828 28467 48428 61854 5930 6866 10659 28794 7944 17891 1913 64051 37559 19750 56853 61421 42618 49415 52948 60173 24632 59027 55879 10177 32881 19672 31161 45500 2217 9417 12816 15456 36299 33883 5626 3848 13662 41073 53416 28122 63354 10939 47502 13210 2859 12695 25317 35546 56615 50625 51781 49744 25451 46344 64420 42804 62730 59674 38440 45884 51845 56982 6422 62986 61525 43982 59939 60940 22550 24886 40321 36294 13299 16585 53769 30125 34348 295 39892 60103 16829 5063 20692 12279 55526 35110 63573 18673 25061 18807 6213 48182 51314 24077 58693 27589 20870 25262 62743 28572 2500 900 42784 35324 38752 43467 51264 54896 43420 17832 16921 14134 1105 37489 28124 50754 17857 26193 60297 1365 9253 19070 44939 9480 49585 59133 11432 10688 14870 59173 59434 17797 46870 61905 23492 10854 56757 45701 25043 44862 30796 29983 32877 62534 14053 11718 19542 23281 17475 38214 38466 30676 7512 2490 8266 10038 19077 28879 9717 16935 34581 512 58250 64055 36148 48217 58806 45363 28759 14929 17627 58633 53161 28592 26288 16589 7395 46110 64108 26634 59893 63359 54594 1402 46358 22980 17259 59649 20389 48464 25109 15000 62199 43948 25742 23361 18814 26468 8992 31061 30263 25401 61657 839 47769 22428 49214 942 2025 45815 39952 39311 37842 17659 12415 17531 42775 8084 8188 33347 10312 7558 49628 57395 44024 12909 61506 60400 25322 4004 61344 25286 56704 19190 35150 36099 48888 38243 34806 3335 44636 9308 47785 56636 15741 17877 47274 55668 2959 50311 48650 56756 47645 27018 47205 16862 6864 212 62269 41418 54700 38380 0 1310294039 +64 605 32898 33567 33472 717 32887 33670 33410 32985 33472 785 32869 79 254 77 32795 514 231 33568 405 33702 33576 33068 33791 886 573 32933 541 1018 32887 33693 33666 33108 33786 33042 33023 33266 33533 33189 770 32787 33612 33026 325 523 424 33249 297 33024 349 778 595 842 33238 33462 33526 974 33427 17 33577 186 699 485 33626 41808 25229 19468 40304 41755 59102 52253 889 13438 42361 732 39955 953 61 419 353 709 33071 47276 34 33350 58773 2422 441 43195 32902 38663 39163 32943 524 506 33586 55644 50049 32934 32941 4157 33603 59934 53255 33054 52096 641 32872 33383 60547 33254 27088 33115 50080 32901 26585 33456 46451 56799 15173 34821 47137 11610 35213 33033 54024 45698 240 0 1043662159 +64 33241 680 33435 405 33664 713 32954 33427 33355 33373 33428 33527 33459 33321 431 128 519 32801 38 33428 59 210 398 910 587 196 33529 306 635 39 811 494 918 33045 734 276 653 197 33380 558 33430 32968 32896 33321 33030 501 33485 400 33674 33444 778 308 614 33431 33200 33775 33185 33773 32929 50 33550 33065 33268 31 359 32795 33418 33669 43024 62800 33586 57728 33149 14833 33437 33097 677 309 347 32951 33745 40907 62739 39045 943 47293 35620 33709 44406 57943 37323 979 46640 22773 888 44812 33462 55235 63760 494 883 33305 33047 33791 30776 54661 32974 65 43622 16124 966 48202 31341 33706 24748 701 14402 1012 50911 27664 625 415 33753 662 894 33319 33093 48 0 3236309668 +256 523 33778 596 895 434 33612 32769 33567 140 664 33722 32808 555 33451 32783 33191 779 972 33202 32786 777 629 33688 33632 33343 110 33247 33387 679 33174 32863 32801 611 573 226 567 570 84 572 412 33022 33093 592 32797 934 815 160 908 70 33205 192 366 202 350 32886 113 487 867 33534 825 33399 33639 590 33262 318 66 907 32994 33580 33605 398 903 33144 33588 700 546 32984 33514 33314 33092 32793 439 566 882 703 800 33458 954 33443 33618 203 33125 33759 32964 181 32933 33331 32900 33368 810 33286 33653 12 42 33431 87 32862 33654 33226 517 70 33481 32901 32902 232 32975 37 33453 737 32793 33356 33379 33058 33764 878 33770 87 33679 528 33539 171 166 33463 501 316 33066 708 161 33214 33354 33252 33600 249 69 104 33766 33674 91 33160 805 213 33075 32810 596 79 937 33614 33499 33225 45 33214 424 596 255 33509 33387 33070 33226 33687 583 33165 407 33117 457 105 33258 33521 33537 1009 32975 33378 187 33036 32895 12 379 33296 33005 198 32853 33447 33492 146 811 978 33740 591 33064 315 33003 33600 33702 920 33301 762 33660 33632 155 784 184 32880 858 493 33427 319 791 342 32947 329 426 33168 33499 594 468 33602 126 33261 33235 179 283 32892 32977 719 808 33390 33354 235 568 692 33405 395 831 70 774 551 450 33581 553 79 33717 33371 143 932 890 33137 84 522 18588 54667 50953 101 525 62039 33316 15028 33620 149 50765 18396 362 27245 19 10514 32932 32816 6501 794 33242 33755 393 33289 388 813 866 522 50315 31510 33193 476 32860 33178 1493 33213 368 42415 924 10376 33277 875 56619 55194 41530 26194 33324 17504 49573 33244 494 32787 45968 731 791 47318 61 214 35388 33642 36242 107 33418 27661 184 5299 11483 23266 61078 39915 536 26199 22852 570 718 246 33401 17424 17 32834 695 579 5360 2409 33002 53593 50386 638 32782 28601 60907 32778 331 32849 10058 35457 3057 13909 14438 23075 559 52738 8908 143 33186 33163 868 26169 48966 14933 23877 45787 56719 267 35443 852 32852 27662 33518 4289 12658 33250 19967 33121 462 37664 33364 634 33103 33439 42704 48052 34255 27039 41917 33238 33340 87 33487 55790 38597 256 274 33671 33626 33537 33774 52966 630 33295 24219 33315 58643 33559 7848 726 21649 47887 792 675 36035 526 359 20098 22210 518 967 3337 18072 22851 33442 29899 33050 7598 40121 46438 33358 316 13098 818 444 30885 68 32920 56220 39382 25176 59442 297 975 39134 48641 90 30143 15211 8567 139 32942 33141 49701 993 63179 12 33267 33204 33672 2722 46481 8329 43695 33553 379 122 5850 59738 32897 32785 33655 33320 33199 33468 32956 30082 33246 39842 33423 4462 33581 981 42174 42481 39946 637 32901 35779 32772 16502 38577 936 61752 26588 45934 46259 32864 55474 32927 15939 33006 33731 764 22880 20767 33372 33298 177 0 3204091443 +64 33147 33756 33667 926 452 285 211 915 32953 33178 33267 33008 32785 109 33432 243 32801 32833 256 195 33360 998 747 32814 264 127 102 356 32960 999 32823 33411 184 889 194 33384 33276 491 33454 32940 33078 37 448 183 500 41 870 803 33775 33713 33227 32943 254 934 32962 33137 33123 727 473 469 43 603 32773 33255 14803 33042 33328 471 48091 48252 675 250 34659 239 453 33642 33080 15329 32814 37330 20504 4843 33198 33148 427 17548 33523 261 54465 32955 40308 98 33288 822 33610 32927 613 45971 920 21568 49349 871 523 28765 7156 737 486 120 8433 46003 9789 661 34453 24215 33020 24136 798 10636 43357 33522 28491 33347 28214 54 29221 621 10607 33081 0 3180222008 +64 33369 421 778 32817 32963 29 33646 33170 33773 33287 355 331 535 33637 898 609 33390 439 33171 33099 46 549 33272 505 901 33435 33738 939 890 50 33129 33526 33276 33040 32879 500 730 33202 91 33175 133 38 33602 33775 33723 33003 33728 886 33737 477 33024 133 32824 33725 71 140 869 33618 33336 213 237 33475 1002 33281 22510 686 1019 683 33747 56900 14047 1013 18272 955 916 33230 201 39420 48168 33144 33026 32831 833 36424 266 47859 767 33771 48124 33519 649 41655 304 21549 22514 61 663 44749 49973 54110 273 33167 44748 33653 33530 2321 33690 46919 553 341 450 483 23928 853 2745 62511 563 35812 15410 425 74 9064 32783 345 39013 21987 33394 32830 0 3190698025 +1024 237 32825 32800 668 485 803 32916 394 222 970 685 810 33275 32937 33751 33493 908 407 33769 33302 576 33414 32832 32892 33685 33332 33020 33361 33059 575 33760 847 836 33443 33547 33767 22 33351 33147 33299 33052 56 33201 805 881 33263 33362 33514 456 33729 33135 33023 86 33675 298 103 717 831 33460 873 92 976 33646 213 33267 32836 314 385 32811 33694 33385 804 33596 889 141 996 476 33313 208 33764 33258 764 825 32959 33573 710 33772 33264 32903 624 915 6 776 290 32907 33253 32871 33333 33687 33568 32974 33071 32862 818 266 120 720 37 1 33551 33750 32783 539 33657 33572 33582 33234 325 33060 7 33391 33391 32847 713 33250 33631 33429 33065 1003 33460 32842 33211 33072 599 33373 33131 32904 33039 33741 167 33159 33450 32786 748 33361 33026 33329 33746 32977 33570 389 931 33782 92 32787 32822 233 33498 33157 32866 843 33464 33178 33395 49 33696 620 32983 250 33203 541 33071 657 177 33683 32889 991 177 33489 32919 33199 629 753 33718 33572 249 32796 820 32939 226 103 33380 146 619 33283 716 33528 33453 561 384 142 501 33623 189 891 263 33313 33503 625 33491 33001 842 33316 709 32967 614 33727 33449 235 964 891 37 861 33426 821 721 33572 33782 33341 432 33710 33766 33111 33779 155 994 977 33007 33252 816 32968 680 33647 32858 32832 489 33752 681 158 929 33212 33180 32964 606 33022 33333 32 471 880 32787 33248 33224 32912 33412 33645 628 267 88 1023 105 32855 33346 33134 113 32854 776 33523 33617 33630 32964 312 133 490 51 681 994 151 627 32952 779 33388 33248 33060 705 32890 499 33588 532 33318 33084 936 384 33780 33472 518 32877 32799 426 9 395 503 33611 33394 682 32873 219 32812 32835 942 598 33369 442 33388 33444 33265 39 33724 33300 33035 33235 801 40 803 33258 304 349 485 32814 33162 53 33758 32814 699 33042 33500 33631 814 33256 33675 815 33771 599 33791 299 33631 33041 33378 490 33703 33392 827 358 33117 33723 959 33660 33640 795 389 554 930 32968 765 33093 33644 445 367 229 1003 579 33129 33713 741 33578 33625 33567 33629 33012 32792 33040 33228 518 33416 33604 33637 33087 33785 32848 3 66 33747 662 32928 176 33098 404 865 33381 13 789 32975 773 493 33738 33616 289 33660 385 33770 33066 33455 32873 924 455 634 33232 33790 33513 167 33440 33575 416 772 557 646 33387 33173 829 54 128 711 33708 134 33782 654 33066 45 141 33788 32945 559 33144 33524 335 33208 33608 499 33770 33769 33775 33270 33607 33775 360 803 33117 33064 585 730 182 442 32981 784 539 152 33703 328 33779 33077 289 613 538 952 33602 33462 33255 525 555 10 33105 979 33725 607 346 32865 753 33000 730 78 33780 521 33218 449 33340 33185 756 4 1006 32831 859 32961 33251 33564 510 33209 111 33165 1 33148 33445 553 33113 33782 644 33086 33606 33196 33493 311 32808 33531 191 601 48 33214 778 486 187 590 833 438 742 32903 33371 33478 126 33148 33451 295 698 607 33790 970 32976 32915 32828 33193 32968 33045 32819 32847 33453 33067 32826 1002 33763 859 33558 466 137 491 728 433 22 483 404 33440 33547 33499 65 33666 612 527 33283 33411 32964 601 412 73 1007 33570 255 32833 33727 33719 354 506 33171 33728 32930 741 180 472 32774 33329 666 33471 726 925 33308 33093 204 189 511 1003 32865 33691 32910 33429 32984 973 33719 33276 918 33488 312 221 297 33303 590 33007 872 642 33483 560 33062 33261 131 33263 889 33159 32892 33665 33780 33504 33399 33683 102 32822 32836 231 645 33612 33074 33430 33026 833 32950 257 32848 33423 33791 33174 33580 884 32997 712 998 33173 32990 33654 32881 938 322 827 33281 32861 33265 33247 817 887 33222 702 931 33750 33116 32833 604 33718 32934 732 33617 383 769 305 32 33448 810 615 278 1014 201 32917 33463 33413 52 835 585 33642 33659 33254 33317 22 33781 208 33684 480 32843 33468 880 782 33446 32790 33742 33346 33015 32924 33563 33008 33643 956 266 33200 798 32856 33091 660 33455 32921 856 33279 33332 483 64 815 32928 33602 29 1000 231 528 33146 681 221 32842 1016 32838 33523 33501 475 32772 453 573 138 32775 197 99 213 360 33592 32887 33424 28 351 216 620 33186 33542 1005 919 139 941 294 609 811 980 411 33277 33662 33177 79 542 33343 33396 32794 798 136 153 33482 32840 32807 335 33230 376 550 938 953 33466 33680 33253 33482 654 33162 922 551 33681 740 33050 33432 33568 592 32885 813 611 965 33443 33722 33049 33072 410 85 33027 33429 33578 33338 33255 33345 33222 673 241 942 33482 32874 33631 33064 32857 141 33750 604 33601 1006 607 972 33232 33438 440 32878 32851 20 33624 33184 33238 304 46 32882 32820 33422 529 833 620 33134 33728 33657 388 32829 409 32909 33251 328 378 33673 101 33555 33155 32887 953 926 172 20 33304 87 110 33492 37 33362 32777 259 145 330 558 32840 812 33215 33377 379 1014 33660 864 32871 945 762 33448 33197 6 58 33035 540 1002 33109 32886 589 565 630 293 33311 33381 33015 33681 367 33470 33204 32891 33438 412 45 618 403 673 460 103 125 534 33208 33137 32958 259 33760 33380 322 555 32941 32837 1013 91 938 33526 33215 152 33222 393 33341 894 750 45 285 33293 33649 557 841 33180 33693 587 174 33107 33685 9 216 33426 857 676 699 33488 33628 301 33212 589 32956 33124 294 966 32812 215 33716 33211 32989 576 32799 673 30 33107 912 32837 285 33531 374 573 65 33014 33788 345 467 33230 391 33454 33029 291 998 704 33595 670 281 133 33294 161 51677 850 33011 58763 33271 33547 968 33393 29878 10926 6418 42477 887 756 32823 43828 834 40326 44495 21498 60599 8909 16817 16725 698 135 847 33515 33763 224 697 718 592 33357 618 383 7995 33057 288 143 5842 7780 13977 161 28365 33382 33351 33462 935 10305 41318 55860 33407 33334 33606 10924 33653 3394 33687 36243 744 54793 950 50 556 24991 33570 22562 21958 10013 35932 5901 33033 545 854 427 63882 32792 989 806 32896 43025 32882 42478 33124 53022 61746 33586 165 322 42827 33190 52 440 33739 32775 27397 19081 3791 32953 33037 58663 12683 944 1023 38667 26594 52753 50884 105 58015 46019 18337 32773 32 33170 539 37426 56212 828 48143 42630 33668 670 33258 45647 23248 891 27179 25883 33132 853 33279 21832 12 974 36782 33423 97 3782 32965 33396 32827 13023 33536 50162 8624 33736 56840 33627 26666 35853 32813 28317 22 11379 47 32845 58823 1011 61862 56273 914 33703 33009 33636 56532 26539 53985 33352 33115 58703 33576 33468 595 776 247 555 6539 851 690 17554 34700 33216 32948 519 33231 32830 33535 33712 49205 940 474 36969 18303 37932 33571 33277 34959 33181 268 33324 30154 240 60299 33242 954 33554 109 33120 33531 303 57721 33089 33330 6452 559 37406 32975 59356 62829 837 6001 29112 32969 33378 963 702 877 870 33662 38282 80 14656 4809 724 30005 25677 602 33642 32809 46084 289 37025 28689 328 96 33661 423 8361 668 60010 32893 24179 19011 685 42987 829 27180 32988 17066 33111 873 32769 32817 1514 843 44090 37229 4445 63762 53016 33586 33159 928 56006 15277 236 10149 9006 16 33282 33517 49375 638 445 32830 52745 61562 63486 7974 55619 40996 62840 24822 33657 47753 494 49339 33193 888 542 48450 12884 51295 39824 60 190 19003 199 33223 711 33620 9375 33404 26126 31119 567 63665 33264 35856 33220 829 41372 33663 684 280 56593 40468 40871 33032 996 33665 43063 34243 56996 50883 29198 6119 33015 896 17374 11371 33168 34957 46160 13245 17121 54080 10338 33124 435 33089 1104 286 28450 43800 35974 33644 50504 33170 33022 8814 56126 742 28636 12560 576 4105 542 64166 7243 33263 64086 900 961 33770 49426 446 33598 33089 28132 10848 82 33409 8154 46979 144 2265 414 51760 56286 41247 836 33013 33102 17810 462 54376 36812 33335 57458 44700 146 48440 512 25552 48529 61272 33172 432 61577 18769 33500 429 3128 33231 1257 11813 37148 33014 468 52374 29357 50480 47187 33716 11919 2629 30661 23 14288 33456 39798 39030 33789 61017 41551 4683 32926 390 39127 32796 33481 237 55217 550 491 45096 32813 33169 5496 32997 877 613 44353 33400 8829 8439 596 58537 33122 46713 18222 46767 53846 655 11190 33374 41899 2036 33061 33570 25 1202 26267 153 24533 744 741 21817 3976 31 33767 1768 46216 18548 585 53234 12019 359 47 33178 103 36013 74 43677 37527 60127 54855 644 40196 42694 261 63797 25088 33647 8829 15967 135 33675 33271 13492 45498 21247 31412 57173 24644 33114 83 33748 40383 33531 175 30963 8862 746 231 43288 40 83 33697 33384 44956 7806 1005 8349 20176 33006 929 121 15331 54439 33307 8964 861 40888 32910 33668 32987 33332 509 31527 363 33542 33165 39496 32956 57097 37617 8978 24962 39830 63885 47745 4424 64092 33214 10779 32992 834 16099 32991 10271 866 834 11443 33741 43973 32827 9567 53982 30698 866 9085 58203 24039 953 32849 61210 58759 32970 27805 33012 115 30626 48652 2065 29409 283 32846 9919 3122 16034 22717 33070 33342 329 493 32924 673 32910 31579 46535 54892 33389 33429 33341 8555 29102 33451 3473 5427 24699 912 32972 832 55368 359 33529 72 47476 7834 30601 31402 5959 11997 31 57557 33245 51880 105 59813 41824 585 33747 33079 49728 32788 32878 32942 27779 32900 41 33460 33592 52517 905 33233 14074 171 52292 12118 1237 18478 1006 26224 33503 51552 141 294 804 32828 64055 33178 634 27139 33379 22207 33437 53672 33365 54738 33286 32831 499 23270 509 33005 280 27057 33142 33322 842 365 271 12423 48077 62744 49219 592 61633 33514 33609 33784 33521 699 49042 14294 734 23727 37 53462 968 19141 165 52838 43818 32845 25764 10 17517 33312 35429 141 50620 36465 32884 45011 299 36907 30507 21219 7 54994 4439 3528 832 6011 11143 32861 79 32825 27034 32899 28319 33025 513 33227 57883 45720 33662 785 866 20203 985 24724 33870 18973 53793 387 712 33521 48072 130 578 398 40445 32850 57963 620 53244 105 33309 21606 12422 62596 630 41093 744 127 33497 2832 43072 731 13480 33360 42854 52627 28459 62872 56896 33009 36861 33368 33345 17033 60123 3309 14322 891 246 25035 631 20607 52869 32968 33647 17610 7721 1465 33595 33705 33535 36235 39468 76 61888 33499 374 55647 63737 6698 40775 18495 19556 33422 50842 24687 519 54981 16527 35 14266 34560 42918 640 40212 33578 33205 47840 48744 33448 23888 33329 33414 33745 33084 24974 33345 8766 883 33083 36869 327 812 27419 381 10664 51291 33392 18134 36305 134 33604 32913 835 33732 45 16874 757 16566 35794 33081 8282 53007 31610 118 18547 38105 2994 671 5042 20934 1228 36107 33217 33380 54 63007 596 49022 33722 33596 51110 33609 7115 46274 41325 962 44373 701 485 83 219 44610 32945 49333 45265 30387 53754 118 10431 66 33575 519 33745 28622 581 1385 60375 13193 591 10926 61229 33640 33370 631 32819 7080 33516 33368 33335 32968 76 46855 7537 44284 57727 364 9499 32814 33487 7519 33516 63283 38116 33232 40205 49205 32892 19724 23126 70 50015 968 458 64153 61649 531 32931 174 32897 66 5584 33141 33031 46773 6214 61737 32784 15911 21014 27640 36882 33214 12211 138 49912 14413 14818 41682 3879 806 50355 33185 212 303 32980 16497 33156 55671 33488 133 33253 898 40097 32842 478 33572 10789 38 33220 33558 295 36898 6819 938 48186 159 29973 51111 58876 39364 5779 49495 33032 52004 17275 23639 61467 47398 7648 60070 0 3232998153 +256 85 33561 33687 33709 33110 354 33730 825 117 237 33271 732 32830 33748 224 33511 909 1009 33450 33396 33358 33359 616 33575 428 33392 33434 831 962 523 33 912 514 33767 33697 370 170 53 834 305 66 33633 33353 33037 697 33005 33566 347 33637 56 33511 33436 33578 32835 45 517 32848 33145 33770 598 9 33075 349 406 33574 321 24 861 33065 32845 33732 133 336 257 33295 707 589 180 781 5 33774 414 33756 35 5 459 33027 106 33262 33264 699 32922 265 33335 33681 244 586 33158 33045 678 33502 33640 36 33588 32933 33533 536 893 33463 421 33617 32784 23 473 524 33590 33667 33504 33766 40 33049 32851 33785 33313 1006 613 612 459 761 683 242 33350 33041 33282 769 33497 281 519 33125 33062 33262 528 33153 33239 33042 33573 717 33472 33172 32802 508 33501 32889 33191 33655 154 873 796 940 33734 33133 403 33362 298 33265 33103 33384 33359 859 33198 496 33452 580 32929 33394 33574 33744 358 33106 33369 32785 670 345 33210 33777 33492 483 32893 33287 741 540 518 33163 134 32808 32859 320 641 694 33490 32868 293 941 32852 572 690 449 10 32946 33371 33322 381 1008 33456 625 33635 33345 33535 783 288 33246 33700 674 32835 33766 364 425 32778 32896 33115 93 633 33021 945 33729 33532 769 32922 772 33161 33326 33315 33316 982 33112 33117 33678 32914 33328 646 353 33785 32863 32844 33359 576 62077 40235 348 27958 54924 455 32827 50452 33764 521 582 33341 671 23775 32820 768 20894 870 50248 25966 29449 47 17240 842 41892 44951 74 32780 880 329 277 459 33471 49981 33457 32807 32842 29418 33434 20052 33402 508 447 404 895 854 584 12661 23169 899 33090 638 5190 852 8110 1503 19585 29074 30289 213 68 33270 38524 953 409 6 1955 33159 28239 399 301 32921 9960 283 47259 607 55330 166 125 60838 51239 321 190 272 885 122 52104 58617 851 49412 643 19362 644 57342 253 64323 41260 32849 17128 33430 33547 1398 40782 24399 9817 32788 33170 6002 433 49940 35641 33220 33295 57605 144 609 33714 33609 378 30083 885 33445 33608 737 54110 33549 33267 32826 525 504 31037 526 3238 37710 435 784 33562 33124 7307 52805 42636 499 51254 53241 33286 32839 2420 946 54889 24855 529 32902 36412 33319 35435 356 5121 43416 62878 50537 7710 29030 35033 62720 33160 32959 759 44251 954 15250 49885 33407 23857 250 47186 58704 803 32890 27133 55229 32992 56951 25265 27046 33277 181 29416 20614 33705 52129 34802 39057 787 38305 63158 748 33056 32911 33201 60779 16392 54235 30527 836 615 33505 15154 24892 363 213 19151 891 10479 441 593 32776 981 33451 33684 39904 838 276 5818 62943 56871 26828 201 59342 404 626 27367 33789 23076 849 60237 33345 57305 33306 25386 26057 53241 275 23709 41042 33727 944 58384 18101 13733 187 708 14486 58629 92 33036 32998 0 3218503072 +1024 33064 33550 33398 33284 149 32969 710 32820 934 91 741 33710 264 33198 33590 33507 33111 33166 648 935 779 33116 749 803 330 473 58 33110 516 32780 33673 938 925 33709 33660 100 33604 856 485 802 33277 33209 500 295 425 587 32964 33228 955 33402 377 688 33729 113 33724 33034 737 33120 862 33260 32959 283 32980 33573 760 125 757 221 33039 33598 522 972 44 705 33479 33516 258 9 151 444 590 33420 33416 33413 32903 32971 524 738 33253 33076 32771 33708 33552 33582 802 367 33077 195 33409 1022 1022 40 430 32838 33769 315 901 32929 32862 33537 411 33349 33701 33450 33723 33320 33486 33585 244 32770 937 33042 445 33316 882 33037 789 32793 33685 944 794 12 798 38 33079 33329 674 33754 879 492 384 219 396 33655 726 841 33367 39 712 957 33371 11 33023 308 33490 33596 73 33013 33354 33628 577 658 33009 80 477 530 33707 93 32888 673 452 33204 221 32854 521 313 33559 33010 242 33404 144 863 33422 33564 32889 907 404 921 33224 916 32927 33443 953 33615 578 32891 32946 771 33621 1022 32821 921 585 33408 33479 33106 947 32887 33053 334 33085 438 740 33119 33599 32937 978 33625 644 33570 32781 461 729 33717 884 57 296 894 61 685 33478 33216 33424 33571 33175 32832 33039 554 33400 33625 818 97 496 33770 33152 32930 504 164 33541 33156 570 934 384 32793 32901 33312 33085 33755 33660 305 33504 411 580 33770 647 33289 32922 224 32958 874 33296 32850 33319 776 977 33765 460 33581 390 509 481 945 33176 32879 33771 642 916 937 33301 575 33464 12 33249 33542 430 86 33 32845 313 33323 414 33581 238 33307 33708 33467 224 33472 970 957 33537 33767 33462 33394 363 33164 516 607 29 343 33388 33732 33515 963 33357 388 263 177 344 32959 33490 1 33457 32844 990 218 33085 884 33772 234 33106 474 33045 670 211 33612 27 33728 32778 106 726 574 627 165 33559 32878 33764 627 443 139 888 964 33377 33690 33608 726 33360 84 403 32997 33348 381 563 33615 171 533 709 662 389 601 35 140 33434 33323 32980 32803 33427 33067 386 152 32975 1013 33556 33078 32821 425 33615 33322 573 33714 33169 658 70 619 802 33107 815 199 349 259 33345 33715 226 33397 495 188 33741 488 33374 668 33143 311 33517 33041 403 721 665 99 33243 3 116 33320 33602 393 910 705 281 36 33221 33791 294 437 33212 32848 32966 503 313 300 32886 426 33404 594 410 33270 33452 33041 33020 473 33093 33450 33128 694 344 274 112 33321 477 320 214 33392 33267 995 88 558 33040 32867 472 680 20 32909 33755 33654 530 33652 33553 33050 33511 32965 33086 414 33657 59 33307 33349 33008 250 551 33370 33001 33447 33358 777 248 33173 33025 169 33244 33603 33287 397 146 783 33685 577 318 33223 33304 937 676 804 32872 970 485 33397 32907 645 912 128 324 33051 571 881 32790 634 627 880 33239 577 1013 33194 703 939 659 33722 33713 730 33512 742 593 222 33627 33421 33562 32929 33715 888 32988 975 986 33539 557 33601 33742 1012 19 546 394 327 32850 33074 932 33173 33654 154 130 33647 33134 244 866 33045 33025 32 563 33208 33040 33219 33425 33040 494 32854 33184 33385 33418 33174 33087 1011 785 88 914 977 33435 33415 281 33181 1014 33775 478 33776 834 33233 33714 33505 33143 33600 33015 33142 628 32955 607 33283 31 193 33380 939 33522 33593 361 33568 33297 969 101 33495 33675 32859 887 453 33748 32943 821 211 33477 79 33180 245 385 190 33094 33554 33632 33466 276 33306 33213 743 967 658 788 21 774 33740 808 564 410 33482 41 33306 414 33263 760 719 841 815 4 855 32921 697 32816 33239 32939 306 806 33007 33308 352 33170 33082 32919 33360 33182 33771 33689 837 992 32985 371 235 603 33495 121 1000 901 32782 53 33057 912 33483 33749 836 33638 33659 229 33090 33699 33490 32837 613 658 33266 317 139 33396 468 222 394 33253 945 78 32990 335 839 32905 429 227 33552 33686 83 33560 33164 886 174 33550 671 380 33709 24 33780 33162 32830 200 561 33330 33086 817 721 843 32941 32870 659 33188 909 180 348 430 44 664 33220 33493 218 55 33302 33350 1014 32814 33105 946 32922 377 33531 449 425 152 851 33742 435 33195 33604 268 33639 33279 447 32922 771 619 32825 33183 33056 33349 689 693 288 952 33099 33123 32855 33114 579 33216 33545 505 46 825 33350 33626 470 453 33258 33565 926 294 596 32833 153 183 32884 891 475 32930 33277 33717 145 33734 33658 555 33062 334 16 1008 33550 346 364 630 418 33096 33057 32815 637 33491 438 33473 452 875 862 33477 474 536 32983 753 33545 246 33713 515 33056 183 933 32820 33067 573 33115 655 33557 300 32978 32805 33584 32926 915 33582 33093 391 586 33045 773 879 33057 737 33070 95 393 452 306 503 577 33055 32791 33478 32858 222 980 975 33464 833 33667 33790 33049 768 182 778 33270 64 33317 539 33124 302 33684 32860 10 33691 32992 33534 33277 33059 67 522 523 33358 32796 33226 408 32996 958 33451 32879 690 33696 33150 33316 313 32873 32961 511 897 573 33371 33019 390 33392 33742 33296 772 32809 33023 67 33705 684 33579 130 33211 33573 963 149 130 32918 122 33634 33340 32842 33202 1016 33018 33106 136 554 502 32817 33348 32946 33065 842 469 309 33282 33404 972 33058 168 658 271 33643 1022 33172 29 271 214 577 33280 247 33411 867 94 33342 33767 574 33498 33428 32889 33162 200 33188 32843 286 48 49 824 33690 806 33715 33570 33510 160 32824 904 33228 33178 33505 36459 12033 6198 47310 45439 36909 40841 32911 33107 32883 333 21736 33664 23555 40292 154 37922 302 33349 33125 33535 760 700 47585 25591 18269 33539 33730 781 33073 33294 38609 164 103 61563 33332 59347 33656 663 67 15541 46023 32993 35291 33670 36415 39795 26914 33493 240 54921 59291 939 40438 56072 55283 125 6647 370 33457 499 33324 33606 709 33158 61426 47546 21114 589 33607 32816 33409 37826 29981 33120 538 29523 416 60190 24794 46019 23511 392 14172 5567 47 15398 25521 698 46715 33332 930 38960 45676 33185 44949 956 33367 33605 33699 32885 387 33746 780 53146 29138 6877 20142 29143 32877 935 12067 62 270 33533 33323 33521 466 33232 24393 54168 14875 33566 62037 33541 1250 33096 33684 11690 430 2191 829 32980 63521 392 59731 32797 31476 342 18364 12126 39209 521 61411 688 32816 740 59884 33655 1011 233 62078 32881 230 513 33436 49643 32852 62016 57963 787 23549 32816 45975 35143 709 12527 25793 32803 51154 2166 247 530 55385 33426 33857 42707 711 31130 208 33853 1008 33436 32839 160 33723 436 617 40254 46661 166 29121 936 32807 33178 24129 639 33411 2325 62670 300 295 916 329 702 589 33214 64508 35530 32802 40857 33409 33179 19516 33382 16001 43596 6581 891 33135 37525 34066 33116 61020 37088 35540 59425 10261 471 32784 32902 97 15230 781 280 12839 864 55142 142 42283 702 135 41034 33484 714 32828 36123 80 32981 10559 41637 40397 14175 55300 233 130 809 54359 32864 157 33075 39152 33191 27491 55632 524 946 36215 33364 3883 58166 33381 39432 41169 796 59637 33631 32933 41299 914 33456 11028 44370 536 36753 60494 33224 33250 31441 43765 56982 332 24857 60778 403 2744 56815 54 5974 27930 32952 32917 33674 33189 449 33635 33215 33092 33647 33221 62 438 9132 892 10770 230 52659 811 40063 54675 33742 32897 33677 33745 44580 33688 1731 52039 33422 29817 42864 26041 215 41104 33001 36676 57071 137 358 59909 33367 9111 6260 1700 33778 46577 33131 19139 694 448 33265 64006 17860 49450 202 142 15481 33726 33107 7181 33333 48171 167 698 33456 3608 628 22209 34016 31671 9923 500 2673 33406 37389 614 33791 871 57068 338 32827 807 149 53697 33775 64478 3749 209 3255 61096 782 736 53989 13358 33760 33548 33716 33552 194 33114 1940 16074 717 33437 781 33628 37458 32812 10684 47728 771 307 15810 509 40067 22339 33774 18891 12925 121 12173 33481 669 204 33524 41196 46388 158 31343 256 304 53088 46468 12576 33127 36634 501 446 8904 958 33678 6494 34091 32826 32990 33194 33676 32989 6385 40581 33151 33660 36790 32812 33556 35757 32799 33322 58521 28969 12184 61227 28219 32957 33469 48156 57559 867 33753 57622 995 38109 34002 899 38414 511 316 42217 17523 62019 33002 142 53 704 621 33667 871 32964 33392 33265 11595 306 49637 29488 17411 44103 46340 826 35010 59549 34789 36323 4958 20805 32973 491 32906 859 18906 31377 262 10 951 294 705 4339 62308 23257 33690 33198 699 20023 14923 663 32887 46201 4143 49574 33615 317 42581 271 32811 33666 40140 7401 19899 593 33177 31360 32855 799 57913 22625 11899 27076 63240 33440 5530 753 62096 59703 233 43727 5677 33069 45370 56130 33045 33655 15909 94 24898 346 40727 32781 3518 12675 1093 33757 38599 37702 16 464 33065 33214 51178 13603 27192 146 47 33110 62136 14198 33312 186 1559 35074 33130 31449 61004 36644 45369 33153 32816 33561 28754 828 150 8225 547 32894 36683 746 136 33538 10277 34959 17981 33610 444 30450 17520 33638 33518 7564 49963 33050 18758 955 576 33380 33561 42336 54075 32870 2669 32901 47849 711 254 43793 853 32824 503 35309 33733 53597 446 324 49112 33248 45 33383 14137 37748 622 24486 1009 33662 33411 35948 892 1908 830 33113 32773 19 53510 30875 33493 785 2003 558 460 25602 32876 37500 39613 47716 637 7394 22166 33766 460 33129 768 27313 51163 772 20995 26947 73 33016 33195 243 27190 722 885 946 582 49994 32944 46611 19068 6117 597 33269 13641 37747 52709 54 935 62363 39319 481 33224 21448 32905 61303 33232 10572 10137 44232 8746 41249 23949 6997 705 192 33228 32923 32831 33537 69 182 33366 33685 38254 32878 17747 54781 417 164 42637 26095 33364 50150 2019 13287 243 34641 74 53053 32937 58732 678 33315 33648 58617 33166 63136 59203 33507 386 18128 33221 33156 50874 23670 361 264 63423 967 33425 51130 436 33685 579 23545 33235 33455 38547 688 33769 52700 931 32805 853 38735 17692 33385 370 4 351 812 33496 797 600 18887 81 51523 4853 46346 339 33035 2218 37660 3927 38658 32784 33715 58404 915 63969 826 50438 33393 33603 761 21774 33488 33711 61767 497 76 47563 771 18398 33069 445 87 33477 33273 32858 33543 33504 877 55855 35215 3637 62544 33241 33752 22157 585 3485 15107 16036 36348 53469 33075 34249 32902 23382 42680 33160 33455 20277 24354 822 24183 43196 12156 33335 49758 20185 33129 27 33460 356 704 62694 33076 27213 41804 32841 33194 55530 40325 22 24700 32918 33248 33445 33772 33221 33424 258 32959 33675 33313 43757 288 64093 539 32884 21117 60768 46747 951 39 28297 47138 17244 27635 32881 33259 829 33424 45373 19650 16144 450 31690 46676 621 337 36473 38982 45987 32802 24626 21402 995 33766 63428 58555 743 19248 33720 4483 33177 33550 16336 25065 32947 33543 173 477 17429 61091 33310 33596 61434 56355 17801 49039 34 33153 310 33421 30013 32783 32940 218 2791 6500 23225 33339 33107 512 154 57870 33621 804 32941 41054 14717 847 849 29085 295 33300 2643 33068 51225 155 18814 33568 438 27011 61746 215 58936 40261 59783 30546 1016 11422 61121 683 46606 48969 46152 61433 15107 194 8806 789 31442 990 34896 428 58 48917 33372 33004 221 61867 37443 60234 33060 56548 145 32769 32954 10607 55175 39325 44972 32965 16370 169 56493 949 58878 4168 610 124 33523 44169 33296 23397 0 3228375657 +256 882 33164 146 33137 920 552 33592 653 32987 772 33560 416 32917 927 594 986 33265 33776 915 32803 992 33107 33250 33342 892 33094 33547 347 113 502 57 71 897 33624 33691 161 33334 33013 866 33392 33326 33465 676 642 33265 362 764 33109 806 665 235 33103 32958 33480 33467 623 789 865 958 76 33628 527 33443 104 33343 33311 72 573 33384 33096 857 32776 528 746 293 32981 33271 33301 147 646 468 629 33324 738 33159 986 773 33690 33500 984 520 33158 298 357 349 33656 33019 1007 744 622 33088 33232 32816 306 33178 621 327 32978 33487 25 33564 33143 32957 326 33121 730 722 653 577 271 32840 746 33544 677 33724 33467 33580 33339 18 299 809 924 121 33365 33530 535 33625 523 33682 642 365 32908 33471 247 146 33757 720 746 521 793 33600 748 201 289 593 38 32915 33134 795 271 431 33329 951 825 706 1009 33541 33013 33161 645 32932 33462 619 33117 33076 318 32953 33103 32977 362 930 32844 677 95 33194 819 483 394 33641 33518 186 704 33471 33659 405 283 242 64 634 33406 17 32927 33205 33295 483 118 928 455 876 747 33576 32819 454 33572 932 455 575 329 33184 33762 793 33635 33371 33060 33406 33027 304 137 33301 546 32907 85 33615 810 379 632 32959 597 783 158 311 915 568 33648 32854 918 874 188 33108 707 173 496 33158 32784 33279 33383 37777 845 55569 359 823 33103 11722 33430 62121 33453 10669 19777 9627 54476 7703 33641 57271 26199 13313 34890 674 33090 949 10147 30895 2759 324 50717 188 26240 505 32832 33161 32851 7976 627 25360 25378 705 39823 792 5311 38352 685 32859 33368 44260 414 55534 29817 23853 32806 48392 59 33780 33310 649 33642 26328 33593 748 534 203 33404 377 10060 33390 12312 32872 35660 26557 32893 33235 26777 12 45302 33477 56614 33307 32955 33325 33234 46068 57714 1015 55091 61617 172 36473 31338 250 1549 33174 56153 845 610 14321 653 33029 7800 9 748 615 49490 33220 48850 946 32983 32769 33696 33079 36559 37687 958 31692 21919 30072 33032 783 9695 33134 19073 52313 33742 37572 55382 24682 173 59788 24853 729 8011 56119 23089 548 9841 33742 59859 417 309 32824 399 32825 867 32843 328 44745 8 33099 19378 41 30475 21845 54744 33509 3525 33134 33260 33288 21351 33530 33733 53412 12799 6360 47360 34321 205 468 919 319 432 17081 60365 32900 552 62318 30174 32770 895 14274 237 43521 11576 32905 33057 757 145 24673 32923 773 10094 456 207 8793 12307 49274 664 15223 32873 477 26094 33590 43245 32999 32869 58469 20359 33142 33071 59822 1012 63036 375 47835 32865 53803 797 38079 579 4150 43 328 15566 23470 33485 33700 39379 527 23380 284 60010 748 18599 23330 316 43994 701 746 40013 35088 397 15872 33200 1 33349 4961 909 64232 37445 19602 32866 23249 604 26970 50454 0 1087849174 +256 33065 159 33059 960 33013 33478 32824 33615 311 33044 33239 270 33267 33568 32806 33015 33219 32797 215 33568 33463 33771 662 800 33451 33759 33200 33181 1000 457 113 33316 32957 647 32914 250 831 33182 32775 33488 750 33339 485 684 512 856 33652 33723 32988 104 33765 243 902 687 422 355 32857 151 33717 33191 33583 225 33 284 33400 33749 33213 33310 33296 33545 33336 32801 148 989 33720 970 207 924 272 33630 506 33469 33476 907 33086 4 33081 89 276 137 33585 33479 32829 926 32784 33659 674 349 33011 32788 33075 551 247 32872 793 33478 33506 657 33605 396 33224 32958 652 33176 145 33754 33213 634 142 33131 947 32964 33592 32792 32985 1011 32846 510 760 663 995 33136 741 347 33184 948 33174 998 32974 33286 33124 87 33222 33197 33019 670 130 291 778 33280 692 32805 872 703 33036 33031 601 269 32988 33581 39 371 395 406 890 23 33711 715 80 33457 33383 31 33274 666 33605 849 31 752 33096 769 316 33226 33310 32983 33561 33222 657 1014 995 33457 33279 33227 493 32859 681 162 641 759 552 33482 853 33241 32779 260 33548 785 33412 38 33724 566 332 32882 761 33499 58 33066 269 32880 32907 692 763 32910 248 33031 33452 301 33692 32923 32793 33781 538 33623 33582 1020 33772 33403 33563 581 33769 32922 32843 56 557 986 539 1017 269 32902 78 33405 33249 33685 653 33243 181 33259 56773 39630 63547 33319 32986 33198 827 33774 62098 33382 33428 257 449 808 250 16111 53273 7253 53668 482 222 278 48736 244 33541 33708 13 17880 146 12053 33606 54755 43429 47831 32894 32998 8708 50479 32862 189 36502 32797 33356 6510 42438 114 462 33070 41699 728 33404 346 33124 33132 36620 215 26534 839 33771 956 33340 990 767 303 40605 98 32828 33376 53665 8308 60826 950 16915 257 33566 63169 64185 32974 17999 47747 42292 33669 38165 40609 33648 33663 60518 61128 38212 26243 218 61832 128 33592 41912 25369 14219 37893 33536 21653 33789 32983 55819 50738 62570 43647 667 357 33003 887 447 32771 28455 45543 26357 33158 19 5621 33667 8653 27210 51123 806 33257 15803 223 33471 29973 203 14206 33264 608 1018 18563 826 58004 815 31325 63495 8476 32841 50643 15463 716 41478 956 33624 59 858 935 32897 14426 33265 33143 16731 62532 54304 569 15038 18322 34464 57401 8146 38540 35970 9976 28138 61162 33557 9270 989 33724 52927 34127 837 7491 992 73 44639 33438 87 33545 13 33036 33105 33382 33211 60693 33626 232 33652 33168 1009 50328 60099 210 17460 51633 502 49707 33195 144 51951 61744 32886 56314 33371 28339 23804 21992 49563 58733 979 62573 919 56206 456 192 32938 46826 33600 41376 18817 33023 40371 491 604 33608 33618 58867 149 39073 33685 39994 48315 33244 32864 40628 20863 32894 33338 49792 26075 23239 33346 768 238 9833 39228 32987 53172 24407 7975 455 33088 280 0 1075392701 +256 33206 708 33402 33416 586 33465 33219 232 430 645 417 33456 252 32983 748 975 33315 33400 33066 599 154 33168 581 344 133 539 835 33223 33535 858 33290 32785 32976 33473 33663 284 32802 33748 32941 527 12 32908 426 146 22 33452 33742 29 33275 420 32912 844 241 33310 33438 32902 690 556 32882 32797 33279 33582 403 33688 267 824 417 683 33059 996 237 33235 243 33318 678 524 33540 33503 33589 33602 33039 33557 33306 408 33447 670 210 33244 410 33712 32880 32873 969 552 379 33100 33024 33185 33454 976 33724 242 898 510 36 293 33498 32802 33473 33120 7 32983 33577 33403 32917 33677 32849 627 128 33270 33720 33551 33343 32885 33622 33765 1007 33438 4 72 793 772 33430 447 32945 294 33268 33617 540 33479 33414 981 668 33225 246 50 989 32884 32912 530 33704 196 401 33484 15 33211 1011 122 33572 3 899 136 527 33515 33735 28 33649 33756 33145 33184 33591 918 1004 160 878 33556 71 32989 82 32945 599 32833 33163 117 33230 33229 116 33482 720 277 32912 568 592 33575 808 33339 33143 683 676 822 33552 230 33579 33437 369 211 752 33047 33362 116 33686 33690 207 730 704 33517 33328 33553 32866 33363 386 461 33126 33022 32799 1023 96 33583 603 1021 33536 480 33326 33136 33665 167 33544 310 33169 32897 637 32828 91 32867 32827 1001 797 748 33261 33737 33052 611 33513 33582 33305 33626 21587 33403 33575 157 984 22201 25852 11690 36377 20624 48634 37897 318 334 42127 5000 4836 56087 35899 498 666 8229 56180 831 26905 57113 605 34517 45495 36654 420 41419 32904 33183 32775 1082 7836 13699 287 33525 3508 34687 52783 33172 740 59522 12 52529 835 1016 35219 33172 6330 33264 36136 16430 242 32868 27387 46145 26439 330 41690 838 6910 32872 773 34365 14082 125 32950 53626 34759 710 20105 33307 23151 50806 1711 47314 5801 60 346 33179 36 1016 33184 1009 32919 54181 33613 547 49884 32961 33608 64062 11243 131 62101 18247 50417 33688 33303 33454 27637 135 50993 33214 60582 53656 32992 51531 32778 2279 57961 33611 32935 33477 32837 704 369 60140 23823 33384 3647 21513 16330 746 163 43157 42365 33286 23473 12376 50559 455 42823 633 21 59089 60752 325 243 33388 55813 33474 33776 38788 800 48254 52306 60005 42612 33001 36139 38129 2123 58762 10904 33456 33446 363 33191 62662 41507 32775 33065 33785 322 26142 33193 33149 30343 38033 12805 118 748 1015 890 5680 38168 37930 33657 20485 375 53863 32943 454 7946 1926 10401 779 40512 51537 687 51465 18052 32857 15308 33345 913 33067 518 33506 33315 360 33 33365 366 33550 281 27602 214 789 571 20506 943 1008 33186 33469 2647 12237 673 815 126 30670 257 34903 27551 34387 58301 52125 49672 572 33694 2875 2825 64448 57411 33016 32880 961 145 54666 32838 488 30823 85 7323 687 31236 56510 33685 49408 684 33785 0 1086716204 +64 817 33246 680 33147 121 33561 33589 35 850 33686 32784 109 32904 471 33091 449 327 966 82 197 125 51 420 817 888 32867 174 33681 244 373 33232 126 833 552 33127 33163 28 33729 33672 8 32842 191 33705 33417 327 640 33299 533 137 538 271 862 517 33151 33333 205 33778 951 33743 229 95 124 33158 33745 35268 12033 32926 17960 36333 61905 54099 4999 49385 15464 21428 33633 31139 32943 33359 33183 37228 78 634 11063 33738 55605 33456 32835 598 36796 43987 256 27766 435 33152 100 13633 728 62147 33071 46853 59918 254 33009 32802 32815 14490 606 58739 7149 18941 560 600 20889 28293 28951 33706 30287 809 33457 33107 941 33323 5156 2498 51850 718 32942 0 1061298179 +1024 33350 265 33326 614 33050 33273 737 33194 949 33736 33203 666 33506 20 33644 69 33769 33399 52 33445 391 32883 531 427 868 228 33456 33041 358 33294 32819 140 33719 123 883 32861 518 215 181 206 33712 831 761 33006 33152 559 248 684 752 33482 213 33326 33388 33327 982 859 587 207 336 33682 33082 33592 371 395 33479 33233 536 207 76 6 33206 668 233 32982 654 33521 32997 429 630 32829 33546 33316 32891 33204 810 899 33718 33719 254 33029 33068 593 123 14 33788 33087 758 829 721 275 390 32854 33728 33158 780 32978 33647 33526 141 33706 32904 875 998 33148 115 33243 32847 584 993 33321 33106 33773 360 488 33127 33522 33179 32965 33119 220 515 997 33597 33388 933 33568 33484 32932 33200 804 264 32988 27 607 979 284 33374 768 746 32967 33462 603 675 663 969 620 32956 33661 33358 262 32972 281 833 33337 32909 468 754 553 948 222 788 86 33607 240 206 33661 32963 33051 953 33337 33105 33377 33130 33037 101 185 33337 113 33232 172 367 33357 1013 561 245 33130 33692 115 170 917 32988 32792 32850 604 433 33642 32788 766 719 33468 716 33005 833 326 1011 60 731 703 449 452 33031 202 33185 999 107 393 341 33771 32777 352 594 33386 31 33231 596 250 33218 811 33360 740 155 32955 32872 32994 736 33770 298 33099 33305 33748 33709 33487 792 996 911 33386 33001 33156 33521 33342 33082 370 32781 700 541 33397 33090 262 901 104 33027 32804 657 189 32818 33776 33103 423 216 457 33455 300 50 33463 33739 33428 46 33315 660 33355 628 195 398 499 961 32857 32931 33644 33287 33746 625 500 62 45 741 228 102 32965 33121 819 33178 33218 33100 33206 33481 32886 33473 33201 768 893 33515 867 356 32964 33643 605 33371 717 33169 32819 33131 186 77 938 838 33233 33265 966 294 143 637 33357 685 633 992 33451 33347 32903 33719 145 33389 33399 578 33587 467 725 32906 33152 1020 604 32885 33119 925 33654 33628 527 33131 1016 333 491 108 73 572 612 33614 32973 993 755 717 243 33479 769 33537 33709 33365 33665 17 16 742 33744 33661 33119 176 602 32995 33661 310 33279 990 860 33253 318 169 142 212 33391 32847 54 345 33330 626 33272 33080 33008 883 150 32781 33749 493 491 545 33775 33652 33438 33245 710 32988 292 530 32934 543 33645 33691 33765 97 33371 197 145 770 33536 32828 33701 898 769 33652 33781 374 191 657 820 33130 33179 33273 33748 669 360 675 33051 33619 33600 33523 32867 33340 33751 484 25 32821 385 33260 55 275 989 32801 251 33353 33062 33594 33258 33420 33481 58 618 33534 33103 33159 33684 696 33226 441 441 147 33510 32957 696 32971 33086 33448 862 32978 33075 844 573 957 33116 942 33454 33476 32839 33053 33384 972 802 770 231 849 709 95 159 32849 98 585 32883 731 975 894 33522 33154 398 415 33117 33139 268 583 530 153 33197 47 33791 564 33587 409 33463 249 141 33466 334 32808 33454 33126 806 612 32962 32790 381 882 20 94 399 33493 705 33502 33268 33569 32862 363 33139 33346 33259 93 33 959 33563 635 33035 213 581 33096 33693 66 138 33626 798 887 383 273 81 652 33086 501 639 32829 33736 661 422 32861 728 33671 110 352 111 25 33610 568 32866 783 162 360 149 530 503 33721 1022 61 756 33040 33371 555 95 33371 33474 682 277 32867 33322 267 205 33584 487 33724 33698 33675 33666 33292 33697 32855 210 185 33766 33390 889 1003 615 33489 33519 71 698 852 57 33355 33533 33104 33038 163 977 78 32792 759 25 33659 33326 503 33379 33327 33104 395 69 33041 33480 221 32883 403 372 33006 33770 33450 670 33699 32773 232 33501 65 295 33572 765 33330 33204 263 220 33013 32856 32964 754 32813 33444 411 100 1014 674 33254 156 341 998 32867 33260 33726 89 942 842 18 766 320 33457 32956 33551 555 33783 33065 32934 614 641 400 423 994 816 469 286 32896 33359 32891 33091 12 33454 33565 698 983 769 279 794 255 33146 694 33397 33645 846 32837 56 32977 317 33164 175 32810 32885 931 33206 982 363 33226 33466 45 33666 33425 436 33242 935 33787 657 391 312 681 600 80 519 904 709 452 127 33594 10 480 595 800 402 33768 866 33148 607 33372 33327 32925 485 89 33143 33730 676 32903 326 33788 32936 33327 33372 33790 917 300 965 33370 699 225 534 825 33568 242 32994 817 950 33502 33382 791 890 33620 32776 202 33517 33176 33423 33340 245 33121 32785 67 32886 593 75 775 33788 292 804 242 33068 356 33161 529 33710 33724 603 33375 218 1022 26 33425 203 927 32871 32920 447 33544 543 340 10 33135 33567 33489 32883 934 33527 195 33455 470 33205 737 8 700 227 124 704 174 143 556 283 33763 951 33460 33263 33316 792 33782 405 33250 754 238 636 33036 33107 19 32892 33343 32815 328 33428 33504 33735 542 33465 32975 33545 828 352 32814 33386 33170 21 679 33150 32820 973 116 33752 33301 33209 342 700 33418 33791 33529 33423 32902 33069 33689 536 33043 33250 33667 32894 519 33586 118 33647 33279 33474 33752 138 33425 33142 396 96 16 33551 218 990 33451 295 33197 1005 492 368 32926 584 32953 155 107 1011 644 445 47 33403 33337 959 809 33399 33790 33712 203 33570 32843 364 33543 649 33671 558 540 33561 33588 33600 155 33626 33636 445 409 424 32892 33162 33102 329 32989 540 33331 33064 32942 32 722 733 33487 32898 33180 623 271 33323 33171 33494 838 33299 33448 33535 865 33656 718 32968 800 33177 918 20 773 33180 401 32770 27641 182 10430 45474 273 50820 33630 33265 965 799 33726 61650 33650 33084 33748 32967 31359 21475 33607 35839 33363 32 310 569 794 58338 65 33777 53605 44794 20398 602 33593 33154 33762 249 33163 36975 495 62721 33224 20672 9700 33088 40768 33111 23312 31429 12249 43444 33431 33451 713 32871 29249 17367 117 32975 11258 33433 19234 44139 33506 29085 61078 49089 33564 33020 36400 9888 154 35991 905 4588 24119 213 35076 33734 16877 1862 33591 48796 415 973 38727 52504 1003 58772 5079 55759 33295 3967 33035 1006 33552 588 8133 894 786 31064 59493 24724 8271 7926 52503 33748 145 33758 52193 62268 33162 13340 32859 33485 33228 13694 27829 22489 48854 48666 44 57060 32946 60315 33153 36400 28746 59996 32901 33426 32978 293 35536 18430 58976 244 33193 940 33650 766 771 2868 33215 33543 33170 48504 63347 33078 32915 85 5621 979 32879 17073 32838 4232 33292 47807 39480 33651 19223 38870 6567 49030 37100 63366 35335 33603 47693 32858 10451 43019 261 38747 111 44850 30037 33276 32835 33113 4202 54192 33478 342 49003 32853 33217 30472 33732 33600 27847 33716 17228 61310 61175 46 48123 57246 346 45280 33689 49276 33324 504 45250 33341 41316 43497 58772 51726 32971 60215 8765 520 14178 2501 33709 32888 49 33612 214 130 4513 891 61168 33646 424 28526 2850 33011 773 63205 32923 33530 33762 32999 33378 33299 29772 33095 761 782 1714 16170 62206 33377 1772 52902 1500 33026 36 33240 525 696 53297 60027 59760 528 44029 32954 33118 32868 33574 49465 882 494 664 54591 15904 41503 48332 33652 53353 63735 38310 3388 63562 424 573 10109 23829 20888 33059 32899 25467 45989 49479 21370 53063 524 149 20890 33373 32814 348 45811 309 765 13133 33447 32965 619 62834 870 12737 1003 20042 878 597 242 589 39869 160 313 62583 28319 459 22963 55165 18728 32828 476 106 17283 57402 43749 412 817 7167 39384 37083 1076 607 29332 47993 33641 37550 430 25578 23480 58703 64327 42128 424 58198 32965 9147 29690 33246 464 287 154 552 823 24985 4325 163 958 13105 10010 33396 51528 55352 64018 33780 22657 33232 449 41854 34329 57747 588 32970 33079 26075 325 432 56828 13678 34 32890 499 9015 41968 383 32769 633 396 57464 7642 139 4705 54621 32887 17049 592 50911 33068 25784 33649 4280 60308 693 269 21324 49153 33212 33568 28227 34996 15148 2410 15509 874 15159 371 33422 370 33233 33458 771 33090 8372 438 33222 8 129 33259 18 352 33353 42378 33405 33456 630 5939 21491 183 5698 53360 33172 7934 2353 3459 32952 80 33191 32956 1011 72 13222 31522 481 45351 32775 54079 33271 32955 30242 812 41538 41571 17500 33637 60103 665 33290 61738 45432 39732 45618 52819 55075 33259 26859 47011 21759 32991 619 63845 33644 884 679 52453 43 31164 33567 51377 32786 32944 32841 12734 686 33541 33320 61698 62781 21708 33006 33218 41087 20933 756 760 33406 722 52532 57892 55317 983 33580 33020 22045 25239 445 33471 32898 33628 46586 6621 11340 43157 32855 11525 62369 15316 8442 33343 33013 51692 32964 61590 16453 50785 33407 33303 32846 40645 59662 535 509 23009 32850 14075 44001 902 373 55886 22188 33674 55468 33063 10 23143 698 33771 36798 32899 193 24089 33119 25816 60358 33158 19855 33270 604 46395 9413 10256 335 33529 19179 12688 394 47913 46665 51631 33157 33417 33195 33367 55182 268 515 47337 150 36565 57170 34848 54519 124 559 9463 30669 59523 43227 2694 33660 37279 24307 33681 35342 33535 5984 33493 33595 21200 32990 32855 24642 33001 48233 19006 34051 3339 25471 11907 27467 32812 60511 33172 26911 203 33507 33341 185 10509 51245 48663 47679 27620 32887 37092 431 3620 33759 36382 270 1357 41226 14627 33014 33338 33450 33225 20686 807 359 36559 33439 144 3225 477 63719 13 474 46043 13894 752 34511 26096 705 164 26966 32894 22131 399 29355 13655 7633 13679 978 63929 18495 384 33141 218 32968 53001 3694 25211 56320 15785 29385 8642 497 63075 548 18281 32921 33210 32913 19 36013 39142 53599 26383 64316 57503 12184 34224 16615 33508 20341 518 3049 44657 10338 219 7875 34945 33325 44956 120 127 45064 62361 20954 56112 20535 8653 8475 1014 49987 757 305 63375 4589 32969 33428 56893 33259 162 32788 32853 2647 3 643 22028 720 611 21975 33285 33705 33570 41239 33428 23597 255 788 349 61 42422 826 57677 23126 33053 427 33713 33552 48514 33189 527 43273 311 453 15698 17181 33335 28932 29463 33427 37669 193 281 32953 60394 35695 34939 169 33492 931 576 36429 33488 24109 56632 16434 5 37924 32970 7062 32841 57860 53727 290 33560 477 647 47889 33094 100 1234 725 10494 61574 41140 35197 40438 33499 47460 42083 58685 64001 33305 783 13038 33473 35018 10920 19204 12689 32980 30022 33777 25139 45440 33831 33287 533 46829 63473 526 33393 179 41 33311 33583 36053 7634 8870 382 22531 8334 33618 604 32788 33384 33365 18717 33351 32912 30822 939 33324 33365 820 33662 16253 4237 33510 67 450 57431 28564 249 40072 41805 166 568 11896 33533 49978 32921 2732 33007 923 56574 2283 473 36655 55152 5135 33684 43 11922 1817 32834 18302 33689 10946 868 840 63203 51528 36600 507 13551 33720 29539 33087 54080 862 59734 33401 21068 46224 30584 814 39928 960 33645 16539 513 33784 30304 225 32992 235 36041 64107 240 33203 30644 19675 33660 33135 5260 37078 33452 32981 32854 33001 14586 57560 37549 33211 25270 33615 49020 61647 672 5169 33267 15657 33441 1019 313 32826 46843 36082 205 19797 26204 76 36480 13816 713 987 33695 138 13553 32980 33547 50231 33322 780 714 8930 32828 655 57031 33430 12358 132 41295 26977 33501 52158 20373 188 778 48839 33531 648 32977 37372 33318 202 33035 20891 54274 860 59478 33666 696 54566 62010 2554 23561 33648 22501 25654 349 498 830 25689 28978 44124 1000 53746 107 63126 61623 33518 15136 43330 83 57440 22101 692 56734 16862 0 1094435712 +64 33113 76 33742 33052 715 896 32917 570 33755 33534 160 914 32854 612 719 33380 32929 33681 33384 33363 33516 578 283 716 250 839 341 945 570 450 33447 869 33603 498 32776 33338 32805 33006 518 661 559 33566 33621 110 33147 938 33698 33665 41 33586 970 28 111 953 78 33216 33419 884 820 32862 888 33469 461 32976 44167 29319 756 33555 950 60301 38394 3 25066 40936 401 134 421 26234 970 33698 370 304 33447 20991 589 813 52522 11067 12424 33485 19168 113 408 17801 13207 29784 279 33777 16696 28718 14268 1584 325 33765 867 880 263 532 33569 57398 34194 32824 33384 32815 12125 438 33218 247 28919 820 33129 30299 251 41002 34106 37323 228 39810 0 1072801726 +64 32879 282 33551 536 32841 36 32972 952 831 234 33143 33491 585 372 173 33144 722 33076 33534 30 409 489 33220 33114 32900 32919 33652 33212 124 33249 322 32908 33408 246 1 33125 33185 726 33362 33409 32777 33136 3 340 33646 457 254 936 313 438 310 32847 33615 737 33430 81 606 842 33249 102 33619 32946 606 33557 21299 38020 33344 53584 42820 15564 62210 33676 31 26602 57461 27374 45040 824 96 33138 33033 32980 33317 27700 26156 15670 11149 53826 62448 37820 30691 33463 56891 3507 33400 25827 33434 42142 60782 33678 529 33015 33219 24395 7005 12975 350 3787 44359 32938 33450 33320 22628 776 8720 21673 321 32803 32869 32967 32887 419 33600 46736 316 17506 190 37216 0 3216992414 +64 289 32955 468 330 33515 905 32935 237 899 33052 32846 926 346 372 893 267 33032 33107 33003 940 188 33772 33593 614 33580 385 187 33257 784 742 33326 808 33024 450 33108 33565 33432 32999 594 370 977 33110 33602 123 33035 1016 54 232 368 32999 33022 309 697 33788 178 33280 33223 33664 824 926 33069 259 33631 32988 32830 33504 874 32810 1609 13676 44241 59409 18495 34505 33057 30456 3130 33083 33782 33241 59708 6501 859 28932 42354 33663 33550 33477 16395 949 56991 32853 44249 34841 23672 43112 26834 44032 48267 34777 62868 33596 33540 54146 7293 670 22083 2331 846 19609 51556 25621 11 12494 438 20412 37259 8736 33771 56422 37215 909 21043 33459 603 33748 37384 32997 0 1078092666 +256 408 33610 32937 32922 552 32856 406 373 33286 33336 1019 299 32964 259 33044 922 976 33727 249 32991 493 712 32906 238 846 392 750 33342 830 33790 64 797 33265 32880 483 280 33083 32825 122 33000 33645 33158 241 631 599 32800 568 802 926 309 891 566 854 33525 33620 454 33662 33308 948 132 495 33334 615 372 33376 32816 67 744 33208 843 33160 33293 817 33292 328 33334 33221 33163 512 33153 674 33236 267 689 157 33674 626 868 206 474 33210 33605 33294 33121 33019 893 32877 33325 424 33464 33094 33486 438 649 694 33205 33555 436 32950 311 787 33023 33304 32769 698 856 531 998 33130 742 513 33543 33129 384 101 32904 33212 429 408 141 290 766 112 816 33762 604 33372 33146 467 291 32878 1009 33610 812 32809 33406 33170 456 631 33171 412 32870 1001 33418 893 33508 33502 984 33082 32938 117 85 33063 32847 33778 19 33389 313 32812 32912 33732 32869 33464 33592 33059 987 33090 33489 33211 754 956 886 32813 144 33759 33202 1000 33281 33050 607 33225 33008 33663 33635 33782 33318 33725 33004 33089 32845 643 33117 33703 132 717 33507 878 403 520 581 33618 33422 780 61 287 511 33138 33291 208 605 550 33517 450 33737 33312 261 33528 33108 33764 33169 746 33375 33466 33058 33064 32924 33305 32871 707 33596 33747 32892 33471 153 33684 33149 33508 508 246 33753 929 33791 186 33682 33600 306 33170 33185 58481 33536 63201 33617 560 22817 26059 32918 49678 33112 42291 33476 39160 997 2363 277 38412 4354 32993 56299 218 13816 965 8089 244 33536 63654 32878 28903 280 393 59407 60997 1370 18504 479 267 5295 17769 886 20526 34371 33731 33570 57450 32955 47753 702 20825 33300 1464 58913 34594 58058 14876 258 33332 33269 51350 33656 51981 26 39992 29664 60510 61752 29087 39719 755 33640 33216 31405 12181 347 694 35149 143 25916 420 48402 52852 25156 33442 50445 33619 904 47602 344 832 33640 11529 845 33728 33564 179 166 33671 369 33238 197 21007 33241 33534 33397 32787 18786 34980 6634 60549 18361 518 254 874 37997 866 44662 33137 849 419 27988 777 33088 58426 32894 61687 20389 19718 33450 364 3988 9696 33015 111 60280 37768 181 32921 823 553 28051 62553 51997 43759 669 33120 22896 467 28 33106 688 28666 291 39712 33268 30812 60216 382 2218 59708 62809 984 313 43828 18642 58315 33710 32806 474 402 32850 33179 33024 63712 547 952 33198 33303 312 32887 52310 33511 170 31340 37943 7178 31513 33730 57341 61162 33537 49613 57784 33355 33127 2705 32834 613 57928 33248 33514 657 535 6366 3641 48782 38855 4 906 32896 14 6162 3920 16791 32965 32899 52207 12276 33129 62633 39820 443 81 22882 12289 33554 26669 218 46407 52230 33370 30965 32850 33047 964 60623 43005 55061 37877 54685 33779 893 16861 59213 33686 959 26612 33100 43782 64017 33753 44577 56742 49485 584 0 3245068624 +1024 32883 32770 1007 622 43 351 33700 312 33529 33363 33126 33198 33086 33330 33418 849 168 939 32863 139 32775 477 412 320 799 32790 799 33067 755 33144 33749 404 33183 32826 33200 703 32851 493 32894 479 782 117 1020 32942 33726 105 33673 102 33269 313 33141 664 32983 240 33654 22 766 115 297 33150 33633 672 32917 32871 99 985 33456 563 33486 33668 732 33384 383 104 91 33769 330 491 32887 33537 65 32991 33664 32905 664 33312 33070 39 33416 33107 188 32859 378 942 32983 920 364 33718 534 435 33728 806 32773 33740 829 22 32903 202 739 259 334 976 492 962 33249 33643 33533 730 673 918 335 32999 863 768 32905 33697 859 33047 33213 37 33015 80 33667 33766 33314 33249 32928 32885 89 1017 33684 361 305 373 33472 250 33096 740 622 33565 33693 33424 162 114 33343 835 595 785 547 772 162 516 33218 32886 470 878 785 563 963 33720 33410 33763 960 33421 33126 33637 33195 33688 803 658 921 33346 685 32925 139 33351 33234 33542 563 723 33049 33112 33457 1010 487 467 33375 437 1 33603 249 33101 500 33197 146 33482 33332 642 33403 664 28 33012 32892 423 978 32778 33221 771 410 323 33691 33638 32947 32823 33255 777 33589 33184 33422 416 560 941 32897 973 615 32853 393 171 850 111 33104 33662 175 658 273 624 33073 32968 33074 33272 33104 32793 33410 226 245 33132 465 444 33287 33745 33498 951 466 33394 737 32936 37 32846 33432 33650 33007 652 32949 779 538 596 33014 836 33043 892 414 33377 33666 33767 33542 33575 33531 828 149 32981 518 566 836 33322 33031 561 32841 33384 575 33066 33235 185 509 109 32856 33200 32839 860 32819 382 33594 260 619 33242 523 379 33583 32974 1012 33505 33456 246 235 33026 415 33779 224 33791 32864 33287 706 33386 33627 33469 44 328 33766 33638 1000 329 480 461 32991 33762 727 474 33216 748 31 33048 181 297 843 32809 463 33184 33215 715 272 720 149 32835 33192 589 33196 742 370 66 132 33228 32856 547 32958 821 33491 804 33434 254 32992 833 33690 461 342 32907 32793 33224 766 781 33437 33447 477 60 800 32961 862 33328 33459 198 494 709 439 406 32800 907 32855 456 33123 150 32968 797 943 641 33581 622 33379 32813 648 468 33630 33311 220 1001 33217 35 1001 33420 928 484 897 214 236 592 724 32990 33643 33667 33674 32931 927 51 33249 33205 33012 639 31 770 609 33184 49 225 514 33128 322 32812 33447 33634 939 33435 458 33578 33714 32904 636 588 275 57 33298 815 33710 33575 417 818 33354 33239 33779 980 33353 742 33202 169 522 33136 526 33788 33403 33605 33421 290 33297 32836 33292 33722 931 33567 461 340 370 479 382 32937 32966 638 237 657 33085 33458 33273 32 33476 32903 33646 33059 171 33319 32972 33658 33589 32895 33682 33238 313 21 33696 33051 649 973 32844 927 176 278 943 451 568 33661 33168 443 585 261 983 33776 940 33390 24 33039 175 33365 33213 380 63 33514 33120 760 33484 33252 33638 1015 360 33724 112 33109 33623 33476 33380 307 941 33123 33033 438 32960 109 32881 232 812 842 33719 33049 33491 428 33367 80 736 32816 162 33510 386 33221 33104 32902 33427 33384 33691 33654 33440 33447 981 33253 32821 514 33057 33111 602 33190 105 33537 32892 841 739 903 684 33336 749 33032 507 778 33504 100 33482 885 33504 33789 336 33250 58 33268 882 536 33525 33010 168 33594 1015 408 210 755 33623 721 33597 33653 1000 33661 897 284 33225 33467 523 278 33196 33703 750 32791 647 33077 33150 40 242 32933 33489 320 603 745 22 33631 355 32939 542 130 203 753 41 32790 33572 551 33151 33677 33134 672 33157 69 37 667 33263 33054 760 33390 143 33472 375 32773 32935 33318 33670 32775 33152 33134 32898 290 33694 199 33134 33164 934 264 33405 33568 33627 33502 604 73 1000 290 340 465 33593 32917 33207 33428 33506 33240 33698 657 261 33511 33107 467 33474 273 33486 527 33495 33332 33576 869 33121 32901 974 32777 33127 123 33620 58 33226 33369 67 33531 636 800 397 547 32962 869 742 33491 33527 238 779 33550 800 543 33781 32868 58 260 33525 33447 32950 537 243 507 459 32918 704 33536 33007 950 970 454 32829 33461 404 311 33090 560 32780 33038 201 553 33358 33258 33002 706 33362 33587 17 311 980 33636 32952 33678 33232 33200 204 32808 573 33498 33646 368 538 33175 33557 139 33456 330 33132 614 33040 795 33397 327 64 1015 33675 708 236 755 413 418 33724 33202 32784 33221 997 33598 33401 33039 827 597 33319 93 669 33762 32803 65 33544 33275 19 32925 845 938 204 432 258 33610 409 33440 33089 33381 794 33295 33073 33381 690 33711 32817 988 33314 32885 31 33761 552 33163 453 33414 1023 696 32892 900 147 192 244 96 33159 33295 43 779 32789 454 33454 598 33246 481 432 32856 651 856 773 637 33373 360 546 32915 33652 267 33260 249 959 180 531 32948 33679 33545 924 33532 33181 313 580 552 33025 936 451 33074 33597 425 521 33248 997 32923 33526 32977 33472 33784 32925 32983 33463 33700 32996 33482 33590 390 413 33403 189 462 32829 33290 983 33049 33127 33351 33293 310 33488 668 33700 33488 33264 102 485 244 33037 33759 1020 342 33291 33115 33502 172 690 33299 33700 598 32932 917 769 568 33013 956 33757 32930 680 33443 33168 33488 774 33360 33772 33234 33516 33396 33596 33358 33620 33217 929 33682 500 748 33178 33277 68 33744 647 876 654 343 33017 32897 33468 11 33276 33592 494 434 33132 180 33215 405 32842 33472 75 32932 598 635 33618 660 30754 547 36358 1011 1650 32954 33067 11842 61678 740 64287 17900 28444 33780 552 32838 33660 287 83 33128 33658 20803 28544 33445 33784 594 4473 16224 33483 57049 33137 17584 861 29996 37382 55878 13760 16075 629 971 14472 746 20613 27188 46219 62667 10157 61633 36274 33208 529 7 21307 6070 3228 921 53266 33539 61426 496 889 42325 41964 33662 2867 731 33717 52819 735 16216 53382 441 50004 48578 1378 51744 30317 38392 33527 48997 45515 44540 20579 37212 519 869 35893 6022 516 652 46389 695 46381 3374 750 190 63814 2736 418 933 39 1736 112 44491 473 33748 58171 180 41775 11949 36024 63168 546 39032 953 33419 29510 30205 7568 32846 33754 33040 981 30098 32949 33435 46605 33641 8305 49079 33053 374 33606 15793 35420 33047 16491 55148 650 22855 32946 33464 10063 28371 6117 15983 31412 245 33673 22537 33729 8321 59819 33562 865 402 33722 33505 57339 33719 33006 20649 33163 57541 62482 871 33671 32988 39921 668 1731 62379 587 16997 33631 62092 48117 33714 36350 32909 46407 52839 129 645 33567 52714 38376 49062 37168 46205 33676 43196 44340 37520 738 27718 811 535 12291 3963 60797 33075 33619 6986 465 32876 58414 41873 32882 791 32776 33062 33752 50323 48623 34210 33448 276 348 29968 56217 33703 33742 33725 451 12526 158 52360 5778 33069 32955 52229 201 926 39262 24565 99 23640 52157 761 33198 10822 32855 725 1122 32911 336 7557 34395 33148 981 54395 10047 733 33779 41081 62257 584 33466 32918 33135 30838 338 7937 48057 52692 39613 33733 889 57667 61566 33757 15290 33352 57736 493 33119 50002 57853 630 54647 42080 669 96 53934 60188 525 48750 33542 158 9590 22226 43087 179 61253 10845 33220 53512 48690 461 910 33107 48608 684 48349 13365 28865 33513 197 33665 20179 28510 56919 736 33167 40496 300 17202 756 45920 732 32838 8102 33248 42453 840 1007 33157 16203 83 14772 54758 32812 779 5466 45629 32871 33193 32854 33029 63518 16873 34635 33052 16516 23549 945 450 18623 830 33764 32808 2080 61402 32849 21156 33483 49509 33416 355 265 33010 27991 16041 56162 227 33651 423 10193 987 33153 32894 31049 32940 33048 21 33297 11474 39449 937 28055 882 51851 1016 25204 61383 33378 40543 428 5058 33230 45631 565 27097 39878 47474 882 5089 33065 494 39605 38023 10590 905 27180 33029 58523 33709 766 2025 62913 814 44630 272 59435 33284 6227 561 33335 819 23303 62961 33038 42227 29454 58292 29956 459 46643 34807 30364 32820 33560 44814 954 4594 34710 19318 45339 15705 24505 56749 496 34456 423 710 304 39287 33728 6629 33790 27519 990 33133 760 667 53085 1001 13357 32975 22910 559 32796 8701 22181 724 17220 876 33542 947 649 8995 350 10042 48769 54761 33473 872 44581 47083 33030 30825 53799 840 25463 661 33640 33364 35242 33022 413 138 6386 32939 33134 32977 8837 33759 56293 44662 33110 13193 33193 60749 50486 37751 450 43025 13152 8165 21992 62145 11377 780 52212 49783 387 33110 33695 19223 44981 42234 33868 1234 33784 63915 324 62398 32835 19434 860 54861 391 33617 57 24850 1117 16608 30936 345 4994 250 4427 33709 33646 50698 620 64446 402 835 33207 32940 35730 32870 32775 54634 24075 1330 325 604 34317 33067 60293 42859 25703 193 40808 62 4864 33019 33635 32816 33100 33235 399 31302 4194 460 46308 883 650 6106 698 5009 992 59809 21557 55639 54225 29654 32926 33227 32769 768 54814 33710 20410 4655 33615 567 18095 54609 33 2487 758 29311 20935 535 41894 13448 63376 33368 30113 14587 759 49030 107 41171 100 2687 41431 18213 33135 140 49588 32930 13194 5643 22692 1200 25557 36067 33094 617 16277 36147 32974 617 33669 766 33145 42633 32799 400 53193 16890 44845 12019 32774 33131 885 498 57 180 46056 48336 6250 45331 18947 9443 15052 34314 26663 56 6216 9642 44434 16439 40761 32937 589 33476 30705 39315 33665 233 32953 44091 609 22771 61733 33134 32885 33598 885 876 61 37886 12 33218 11053 391 33103 33014 33618 33128 23578 33595 33358 58373 695 16051 1550 59384 655 342 40995 1612 51016 17555 33024 59794 48729 33264 724 47187 33512 75 61783 824 19956 57272 33059 8888 55772 15484 11194 9031 2551 861 44489 17544 433 504 10755 61338 39949 313 49265 4194 34082 33118 60721 33252 8752 804 886 512 142 56929 18012 19175 13740 45950 11214 33422 63718 42479 1005 60956 12587 443 32781 33629 383 33517 57587 37020 572 33705 55801 15738 985 658 63254 613 2951 5230 33465 33183 19031 13337 64344 15884 33456 17270 32794 863 33015 1640 371 33347 150 13594 2263 33494 874 12282 510 48314 52085 30581 49191 33389 60574 20358 61764 50285 33767 39294 47584 17 1018 33365 29486 57 14082 60600 247 33319 37466 23969 59183 27218 35 21336 17083 60233 54512 139 993 62102 25079 678 48774 6929 33131 33056 57462 6686 4904 58015 807 33356 4960 567 48135 32977 339 63329 119 29757 17047 61484 244 290 13163 21711 53224 542 33520 106 547 33694 442 17201 6939 33720 33722 33180 27259 310 33392 33732 33445 40732 46491 807 563 33559 33545 566 25526 54084 579 31478 33080 42429 325 32866 33503 18738 33104 63343 40753 32878 32797 3587 4468 32830 33245 491 406 928 83 21604 33763 32909 33626 33331 627 606 33621 1730 12172 702 45032 131 198 30456 20274 5070 32782 33659 47285 43864 156 52180 10964 33544 18599 271 62076 33225 32890 923 29042 32872 50846 33726 33000 699 698 5316 291 42894 272 57831 533 184 25726 54624 37526 525 33576 438 11116 61493 44310 59888 33591 44175 1208 9189 32923 44524 57245 29676 450 33039 33267 348 32926 22280 690 30367 654 49897 41768 706 33346 33512 9976 7650 45523 77 584 48422 53189 493 45785 56308 35847 12035 18265 1221 5581 22877 33151 171 33721 33557 41 25765 300 275 34975 30431 23101 32812 55948 141 8278 586 47623 655 554 33583 33320 484 10259 29479 32796 11455 0 3234550072 +1024 33671 963 33049 33050 33105 33026 33378 669 33246 33789 32866 759 190 592 956 728 1005 688 33642 33118 33294 32783 664 32943 33507 33107 32873 1007 33199 32795 32938 341 543 946 437 863 931 83 33723 768 33115 117 32932 33274 448 32917 33217 890 855 33320 945 33133 33692 512 33543 32942 694 509 32833 988 473 32864 33003 184 32867 907 411 23 33764 731 699 592 790 33052 33180 33053 32869 947 199 32870 32968 33244 33604 33443 32871 339 33420 650 875 33496 192 152 33373 634 252 33725 599 32941 32848 197 33133 33180 908 33249 857 790 713 833 510 33216 221 645 33356 32798 2 614 592 33296 32916 518 32916 33679 33334 32773 665 33030 33263 562 652 980 32775 321 33324 415 33492 33581 33022 802 23 608 33327 32987 33321 33488 33728 706 33202 32984 33197 33126 33063 45 33277 706 637 33307 33160 799 569 505 687 33281 33733 33743 850 543 889 33600 162 942 33311 78 390 344 33497 741 32817 33550 852 33762 33527 33771 33035 33340 434 1008 33082 449 33216 46 33791 350 243 33525 32826 537 32827 231 950 247 21 285 307 143 113 884 241 49 495 897 33384 376 33495 25 497 514 608 158 825 933 450 33454 110 319 568 846 33398 33466 33353 33258 360 146 596 361 33187 735 33717 33742 755 33529 32812 33420 532 33058 32998 32805 33710 33615 33724 728 33576 474 174 309 33230 33279 33418 33125 32880 33257 185 33066 33014 33040 33107 985 971 437 33399 33106 869 33782 984 33016 625 33777 33449 33519 32777 489 50 829 138 33446 771 548 33130 46 442 33068 685 32886 33250 33071 33224 33256 403 33682 724 126 32856 33621 33082 32954 32968 663 33380 849 32897 773 631 516 33711 33263 33537 32971 33066 20 32922 32946 429 32774 452 32947 33450 275 33284 420 32874 32824 32983 658 890 33029 173 33112 1021 33143 33392 164 33198 621 195 168 33159 33717 893 32977 677 644 33589 257 374 728 882 256 294 33333 904 269 33471 33340 33701 237 341 33122 139 612 33337 524 32969 32933 452 26 33465 581 30 507 33473 58 514 429 33055 53 46 33104 456 33515 33620 184 161 32956 33781 33053 33398 381 905 33511 774 914 568 33190 782 32921 33693 33762 33172 681 32790 32845 33233 170 116 32958 179 33621 33622 547 33139 33188 33194 33392 32826 33539 915 428 33660 780 33500 33489 37 33131 32967 33701 33144 171 486 33438 32816 32878 33013 33735 154 32917 181 811 831 749 606 33753 33129 298 32979 33674 115 33367 626 33092 33552 930 890 33588 33484 61 33192 33764 646 78 33587 33615 832 33558 469 33190 32830 823 680 33220 130 25 195 33114 493 33662 33290 580 604 32966 653 389 33526 459 33421 33756 33270 809 33067 33659 33143 693 551 32872 32954 33048 33047 33595 32988 64 33584 32999 302 497 667 33687 33355 33328 22 33033 33481 33152 68 33562 33520 33394 33137 559 33373 33577 33270 33516 709 33638 33768 33270 33483 33460 33566 33383 174 154 869 209 33465 33584 33026 33609 8 33564 33588 33200 100 33147 390 33347 32875 465 20 33303 161 33357 33681 832 33294 32930 82 33279 831 33652 529 33463 333 33509 32866 33530 753 33106 33391 33309 33135 201 33172 33270 405 259 33567 888 435 175 33023 33523 32782 496 342 32877 33743 70 324 33321 675 431 943 1008 33296 485 33565 32877 33618 33494 578 165 37 33340 33380 33066 124 170 908 33746 342 33126 106 805 33161 810 119 687 299 33126 33444 571 480 215 33421 499 802 33470 211 564 369 12 33504 33712 260 353 289 458 33149 33250 49 174 33372 33024 33594 33716 609 836 33398 50 33666 33748 33553 185 32881 33546 33637 33208 637 32933 755 919 33674 33583 973 33514 32830 33361 33429 33371 33581 729 875 33065 459 787 833 820 881 33589 334 486 306 32776 33662 927 33245 726 806 33533 33619 668 33186 33169 878 33677 27 33358 42 213 33036 33716 33067 33288 32797 946 33730 33683 245 32945 950 33088 315 324 33133 33723 938 482 358 32804 33693 599 544 130 33386 33617 565 77 859 33407 33022 436 868 880 33464 33673 33458 33642 200 81 32970 931 351 33281 33340 33136 253 33594 72 176 33533 774 979 748 33362 32781 33267 633 472 32833 509 33211 727 289 984 33042 652 33295 64 33682 616 558 159 47 608 758 32960 32840 33459 748 33475 611 33123 33317 285 33578 33021 968 970 306 33616 817 33150 392 869 724 33383 742 462 214 33519 33065 857 231 33563 33020 545 34 33331 256 33473 112 32 32854 571 33215 754 33162 33265 439 32959 145 821 75 973 768 33622 364 33037 120 191 33305 47 287 216 33155 415 382 190 33190 635 32815 916 32820 58 765 32910 33148 74 33074 960 33643 816 398 33370 61 33163 33321 524 33336 33167 33436 33480 435 388 897 333 33556 347 708 239 32909 33205 80 33195 33623 33079 33179 33065 33391 33371 33522 49 973 33554 895 246 74 103 33455 216 33289 363 33758 33549 954 33386 451 810 117 33187 33475 460 491 744 689 320 88 33231 286 33353 32816 145 33071 33274 33047 33641 32940 742 580 773 33284 871 914 309 957 80 33354 919 375 6 267 269 33404 33128 350 33348 33187 33508 545 33524 32828 373 416 841 33323 499 213 33349 818 33092 688 33426 433 33545 33008 33770 52 33462 33437 717 33453 1000 33212 925 33477 33781 33417 33639 887 238 33650 32812 33617 745 163 32938 483 33740 33314 544 144 32845 292 32779 33264 8 527 964 1009 33146 23 33126 33597 33339 356 278 33068 33399 33194 192 202 325 33066 835 499 145 40 313 33281 477 71 532 33481 370 880 33511 33467 926 24446 35337 22092 25675 36736 28957 29337 33404 62052 61334 37225 578 57250 7025 48724 33647 59356 117 33735 283 14609 3406 32899 5979 56919 44183 33042 33540 1874 267 276 33017 30859 20243 33591 223 60644 642 33023 440 1009 264 26766 832 61001 35465 32923 17722 33275 47969 32919 195 344 45092 32880 22366 33369 33092 33222 23060 674 48965 32990 32921 14191 16715 27422 33392 52041 878 59662 118 46118 60789 12175 10826 21954 63589 815 41434 33772 261 716 577 33266 35091 33738 52987 11993 33318 518 16881 33164 33357 13012 20518 133 18037 895 38 33549 60703 2066 33342 875 31206 1598 30490 616 35820 11465 57383 16623 39850 14613 2646 57978 31105 16850 62162 419 6103 13601 33347 33348 4423 37158 33539 35552 3972 48 937 16542 28729 63345 18373 1218 64201 55384 25071 224 33324 920 33772 46242 20 11846 117 32850 58431 169 33047 33041 33100 433 44614 32895 50603 51795 33389 1467 754 33344 33119 33773 33098 50656 575 58816 17697 45659 392 39005 33256 33509 1021 13527 44755 254 2982 10567 33514 32972 138 62223 32769 39828 7567 51424 23151 18425 33782 74 28540 682 213 33687 459 41939 33707 44417 33716 54124 245 39035 745 33216 21255 534 33668 105 362 17535 21878 30745 32774 358 391 59496 32807 20083 33156 33746 169 1011 43310 293 15416 54366 32948 33126 57199 618 498 642 33072 9511 605 21869 93 33599 11702 640 13058 3586 22096 41312 30303 276 6344 161 28395 45376 54210 39837 33488 420 29406 495 54753 33706 33732 39954 27388 6178 33041 728 10415 15303 395 689 50006 33184 178 32916 29013 33372 44488 33037 99 4352 33208 78 44201 22249 49323 33746 39176 33171 45921 663 18423 49556 49441 28820 32831 251 24012 33506 813 22005 33773 33052 530 65 35362 27 348 33718 1520 51019 33232 33382 27003 32863 50160 42294 60470 54776 36046 33745 18684 55857 60177 26669 729 2144 61477 33775 32810 33571 601 39508 32 60170 32787 33259 33 32826 33279 33422 33555 32870 33178 33046 14140 15587 145 639 33526 33066 375 332 841 37833 188 33156 20887 28776 33609 182 14692 29951 22101 51240 33540 3067 796 95 584 22174 226 331 353 23346 40020 256 2289 43443 1066 19519 50420 55556 621 41099 33617 5548 33590 23285 49323 601 802 33449 5578 305 64472 967 63700 48162 33303 220 46016 50443 709 537 51439 573 45749 55139 33602 33423 33705 42075 38075 37548 32886 14389 10642 666 35374 815 64 31367 4171 33259 46262 32967 22805 34184 33558 35655 33774 63951 904 39510 1855 33072 33727 33461 35429 33604 209 62753 33592 990 33707 53807 31566 48994 8522 21974 604 44632 10526 52065 33167 40557 33021 28609 33564 33697 42944 33258 28566 625 33354 33086 464 40549 33341 33283 19163 70 33499 30041 38410 19939 21178 42940 16134 33660 64265 886 1703 18197 1447 32993 19277 22710 38356 33767 12000 8405 478 40642 892 33285 521 33651 32800 59077 33226 55147 33283 32871 54309 36747 28516 25933 50430 32820 20868 32953 7780 33554 10449 34486 37220 8245 33531 33749 33490 33743 25360 1456 1245 33134 33632 87 434 33325 196 33433 49956 11582 27863 33667 33314 19243 131 27372 83 32827 63173 33103 56437 52761 33048 952 32944 33571 33341 14761 43794 18613 9684 162 4579 45908 25718 50995 797 29610 50361 775 34885 38850 532 694 2904 1010 33322 11549 8460 46345 33340 63258 288 33786 33768 33640 541 33492 33276 33597 11599 33418 33132 690 33181 63235 32939 40076 11243 32831 197 25411 33246 13938 62222 33678 26012 48391 40820 33720 62331 29173 978 21230 858 15942 406 16687 37169 946 32920 51520 48742 39377 54622 4007 6183 17861 47280 51 360 36003 92 23853 33546 5 33152 33224 534 33302 170 51862 32956 750 34499 35382 4 33664 7335 707 33633 58393 51796 799 738 5690 83 33723 37533 40553 33013 602 27221 21298 48697 32927 45450 55837 16413 33291 30117 33531 32825 733 52624 33385 890 41880 56966 15423 142 24208 30 495 60 40190 127 21713 5190 341 54320 484 33032 371 61154 3480 41200 920 47320 33053 48091 15715 226 14624 58327 33016 33184 43176 17591 33088 45834 28511 33300 58 33731 661 50257 817 26471 49767 488 52303 33312 33156 56112 33696 250 16628 32916 14599 938 693 42029 33634 12172 295 37407 47030 33281 39389 57718 283 32834 33758 896 16 59146 391 387 50392 33033 30493 261 33095 93 62674 31054 36115 62957 284 57654 250 9600 61390 40730 36272 33152 543 33618 508 898 55124 62355 21277 10 32839 30007 10669 671 51217 33759 28573 505 56252 39916 61726 43644 33514 7814 56232 791 18401 725 32881 26097 6409 33427 81 12513 10540 35258 737 838 10088 33309 14120 56458 44474 33108 62602 455 33245 10895 41663 49498 933 33541 33742 46227 583 46682 33684 12744 963 33404 960 20284 53488 705 6064 33159 59120 36154 38400 125 33252 38756 593 288 53398 33775 823 17556 33329 118 33325 35702 32995 461 61937 63820 664 40419 33645 8499 33135 588 29450 55152 33016 33651 11109 751 53610 37141 10921 33696 282 305 41 447 24251 58092 33562 804 45170 44517 33017 895 32877 53981 57 598 4791 33155 604 33556 970 39705 46256 32923 33744 455 33019 42862 40047 31617 672 897 32940 33713 58138 274 14264 625 34763 13858 39367 44755 22169 28408 4990 839 33130 2357 852 53977 33753 40881 3930 33440 48102 801 32909 33159 57965 580 19502 43098 33068 855 15019 791 45179 51 33765 16683 27884 33036 837 57084 26186 511 43693 698 50650 33130 14789 32867 32972 36960 10735 40274 33675 52401 32860 57480 33410 27020 543 33071 865 53465 33291 18268 3662 33419 23305 896 58738 33049 49900 33709 31740 53312 32782 18249 33297 63534 33673 33254 43919 169 19110 56694 482 159 32898 47811 234 589 43966 62203 42284 58562 32938 31568 620 56119 431 18369 39811 921 446 118 56539 1801 49580 60094 33323 24974 217 6407 22737 636 33768 18895 602 36836 63572 24683 32950 33253 683 63990 59577 0 3226937894 +64 33612 32900 113 33301 33701 33602 335 33206 33330 130 33020 921 850 625 467 713 691 826 852 790 391 33337 366 33257 33141 33270 33762 715 32862 512 33612 33053 33262 833 33776 32829 33607 33345 890 33726 441 741 33455 457 33468 440 542 33066 33530 446 33466 121 33649 33019 770 33156 970 32862 33283 33564 658 33558 33343 181 965 33260 14430 32998 276 32965 33407 56901 51979 47285 35547 33247 33079 55616 11928 54606 3896 701 80 33501 19348 29514 26339 32927 41406 39006 33325 908 33161 28102 648 33360 36824 50251 32967 8525 295 9 754 32932 26468 33624 33521 32833 56119 715 15426 24340 458 280 32781 45260 32844 33123 28439 12502 249 33192 33449 16317 33035 43195 29156 24512 0 3198067317 +64 33415 33323 32846 544 263 33297 69 32889 4 33618 122 176 33142 846 236 32983 33185 150 33146 431 936 975 32821 617 108 829 33578 32826 344 33177 184 1001 33525 33622 14 886 460 33333 1018 252 70 33298 32890 32832 33098 33585 33606 850 585 33207 33298 161 33785 33015 33169 136 33412 33708 825 33429 33285 33198 33414 501 349 33789 63682 61698 3335 49359 124 23866 223 419 547 275 410 32957 50740 33693 32783 57015 34068 33540 33751 11813 695 57 28450 26970 10557 9407 40902 50870 32912 955 44853 3025 348 92 17101 14976 477 357 33654 30551 10466 18276 29066 29941 16575 50702 18717 46826 17120 33497 644 500 62539 3761 33464 32 575 33026 553 56200 20304 33381 0 3218804821 +256 386 33482 33244 33722 270 33524 555 951 32936 33564 33216 401 776 33310 32794 437 444 275 278 593 33077 33142 33453 584 31 458 983 33022 593 753 32919 88 276 356 32850 934 547 33740 33383 33767 46 33114 33596 33666 32960 534 33333 33121 437 353 910 15 402 32914 33385 33509 555 571 33043 7 33064 33217 774 545 756 375 33482 416 340 561 506 474 703 32777 33764 713 33109 33024 33125 33672 63 953 32979 958 121 33379 32916 750 33142 614 276 761 32787 33150 469 32848 33729 276 665 647 33255 188 32913 33383 133 33677 32927 33196 33284 32993 749 32941 33100 33215 33032 63 32801 33379 32 737 555 33397 427 33499 33113 33537 31 347 672 349 33266 684 33311 33309 128 33285 565 33763 33130 33640 33550 32990 720 453 33333 556 33309 323 32872 245 410 329 33681 971 759 32790 438 33779 33232 33011 389 818 46 33128 729 33071 32921 33571 32964 32788 720 33096 173 32790 983 33254 32824 124 698 269 32921 706 26 545 33000 688 353 33258 33195 33567 550 512 468 441 33530 363 32886 33091 727 702 33564 110 33648 33334 917 33371 33414 690 975 33716 33190 33542 33636 324 33685 33600 33311 556 258 320 33477 928 33348 33790 25 754 363 857 33313 327 827 33415 33628 888 33648 125 748 971 33683 33080 33613 343 33139 33718 548 33149 33307 261 672 849 204 585 409 441 778 33453 33009 997 53624 235 21559 73 306 220 36207 8776 112 44738 515 90 3063 51348 52475 33517 8675 39757 62226 33617 971 31128 33370 32835 44165 33516 30016 29229 38605 33120 2422 939 55985 33411 766 33479 32914 125 20576 3128 992 33500 33454 33357 61927 58699 24760 1914 33365 32839 63049 51575 2544 475 238 33272 45240 29018 354 32794 35785 333 33161 619 33562 33282 11493 52148 87 984 17716 4007 30993 46136 50820 33514 45092 50388 757 33557 1055 260 33475 20621 2055 33300 44376 16642 60064 33290 459 42598 912 47153 504 53412 55899 34974 32921 5720 51546 35480 16606 183 925 714 39547 33552 33462 38772 914 33016 35262 41873 33317 28 54973 45910 4494 667 870 62058 33138 149 33589 59562 423 29824 45436 49052 396 32904 706 33192 61607 33209 739 33187 710 54389 33383 235 33123 688 33569 61126 24414 57399 29614 33589 61950 40061 32918 18574 59681 33393 33665 43 62301 210 4923 55514 39337 23837 33333 565 33000 33079 848 9 50557 51933 32797 27912 382 5198 470 51915 2242 33540 46023 32782 52137 33210 10282 56659 64146 33004 33235 24237 5887 27944 34646 42108 47911 33028 32898 33112 1943 42047 15942 38441 32800 33162 40321 599 56387 46967 16597 33399 33226 58165 760 33750 601 33125 14473 31 33406 27648 1823 33253 25859 32998 9212 49117 694 5673 33703 115 863 33595 33152 32813 238 10039 85 32814 33557 33193 47073 32798 31015 29998 783 412 58398 46380 616 530 33080 15412 2220 57174 0 1082184872 +256 33313 707 954 33560 33748 33699 33220 302 33790 33548 33061 336 33667 33041 179 33252 33174 825 33649 892 33532 877 33471 32901 33740 33427 33744 896 33532 33469 33120 115 764 33037 819 913 33593 33507 33200 33465 64 32979 851 1003 32987 537 33010 553 72 210 33472 33639 550 424 33482 513 33600 735 33199 1019 392 730 634 382 875 33782 978 285 33518 32972 33623 893 33057 88 33373 503 112 33415 618 33168 33460 369 686 33497 33357 33590 33513 33502 591 33584 1002 609 951 33666 921 498 33630 800 352 49 33188 33512 1019 33120 33549 33473 542 229 33156 33297 33451 33158 32846 33704 33338 994 33383 33397 306 784 657 33299 32998 33570 53 33221 166 33303 33751 33161 115 472 33541 33783 409 32984 32795 32803 32943 32849 32940 419 928 901 483 33135 270 808 332 32910 726 32899 33571 510 33035 33210 312 174 960 940 145 33147 127 160 567 693 666 68 33418 804 669 33024 699 771 33432 955 448 33685 33576 335 489 531 33044 33474 16 32856 554 329 33183 293 243 33530 222 667 33715 33375 203 32807 33180 33542 33100 571 359 144 33160 901 33619 297 441 33054 33159 33117 33116 33788 33241 580 33564 33032 33434 33002 33081 398 33272 33155 139 33004 781 1011 844 1021 31 33198 989 829 33455 636 33538 32929 384 1006 165 518 33733 32801 33260 168 447 630 32807 837 229 68 597 772 32977 33120 29445 3363 33984 33342 33399 25957 90 35603 39380 748 20385 47014 39935 644 61562 33816 54533 58370 9021 33321 32870 371 56755 105 32840 816 33034 58908 235 27510 26916 33427 39843 33344 23819 21258 930 63227 26519 64068 33101 29144 33357 26594 8263 508 13 465 33425 39996 17548 589 55035 33011 39151 59350 53671 33732 32769 1008 64336 142 18486 661 8803 33535 5016 32879 46836 54 15746 32966 57296 33061 116 51000 54981 1802 33586 28682 54073 627 47434 52652 33773 33367 664 2612 33626 5492 32791 286 33318 100 18228 27657 36488 30350 52520 946 57811 49214 45181 622 60171 262 33741 275 920 39249 33607 651 9417 33362 8848 28566 54471 59871 33673 523 27066 33410 8498 33864 61807 33662 2183 6391 35453 14013 281 56822 33147 54488 19648 63751 48378 255 34724 33308 52803 197 7421 33123 20315 46071 33394 391 27872 32832 36932 32953 33282 410 34546 33102 467 19357 39819 32996 33172 466 9623 45864 16256 56767 355 30197 431 58905 28371 36574 32968 46806 30286 62265 33309 347 57306 20686 33581 969 33359 60829 14370 250 41459 33327 33236 675 11 33142 33723 53324 309 298 32801 60803 795 40 33678 7674 33701 786 11159 20057 37504 33051 17391 33480 33572 46560 60129 637 32902 51036 33145 15902 674 33608 34437 869 33683 21059 1018 33014 850 17088 720 584 1416 409 33311 18582 2522 38185 10481 965 3 33325 33514 50051 291 7518 33132 103 32808 756 36859 33384 52849 33001 56532 1691 51789 156 0 1075179308 +256 475 671 18 33631 32992 697 33487 843 336 33089 33689 652 32866 847 196 32994 33288 936 33089 24 32875 548 33151 640 32809 801 32836 24 837 641 288 33061 636 33465 831 1001 494 873 515 941 33198 701 33243 400 411 296 33068 33467 32964 33483 152 32771 227 604 33454 784 33455 461 346 591 961 33508 317 493 32891 33502 599 976 32801 32832 33254 33165 33293 964 33461 170 33599 33160 33007 32804 33385 210 736 32948 33791 545 33508 705 32903 466 33544 599 33554 33728 33771 33030 299 33291 33165 33147 603 105 33149 33771 32791 594 33747 522 902 33446 219 529 32866 33183 331 32815 933 381 33683 168 766 32784 245 99 677 287 358 33227 33061 32794 739 33493 40 33657 32968 33526 32772 662 861 33171 934 880 33133 32884 33311 33338 626 813 319 304 998 33055 33418 316 33168 33473 227 33252 431 544 33733 33392 101 347 33167 595 33303 70 33652 32857 33155 953 33143 33771 33624 465 882 939 33018 11 33224 33541 32996 680 33541 33540 571 33027 33733 33365 179 32793 33173 784 32904 720 768 574 33490 858 32778 892 33319 476 604 32998 33136 386 32843 644 594 33386 486 33091 448 174 33348 33236 27 828 593 714 33080 265 32905 33419 33168 74 655 32900 32996 33023 652 33504 32994 33605 717 717 722 32824 33238 32845 33673 403 647 763 32899 33782 899 33768 33250 33220 32912 33581 952 33435 432 793 56110 33547 31157 33326 29972 282 217 21789 6455 761 33771 42644 14790 33141 12588 1209 22392 42778 12013 388 57917 62657 33346 35985 778 28688 33357 60438 270 18457 27023 38289 42144 52074 59680 741 45448 807 33108 434 7615 578 33364 105 32910 33053 33540 47301 34725 29087 1005 33750 5689 63573 255 24 62697 33384 950 57244 21582 22762 33729 46979 33598 33526 468 32930 33002 259 32954 220 32809 2776 33094 2704 33220 33129 31074 37811 55385 63808 922 33231 33101 33634 477 40863 1533 33425 16329 33687 964 30399 22516 351 608 56829 19242 535 282 21567 59189 51251 32925 32802 50398 12543 692 73 33504 194 4033 38149 10239 520 926 255 33361 194 33439 920 597 6184 30495 43465 6058 47470 60337 29262 641 33459 979 2896 95 13278 733 64044 29605 1390 13 28336 42125 691 62048 35856 20494 33288 16200 27632 33710 828 800 32851 302 875 33057 52080 33172 33412 33716 37835 62990 35603 9304 33613 2627 33232 665 47346 496 748 52158 33627 34422 57231 803 35426 30190 33127 28615 994 1002 33438 167 876 2932 2623 32965 3894 32958 713 23202 11551 398 53615 33719 26297 43169 32816 33406 35174 318 578 42955 4339 11137 46328 53548 31052 60011 3267 61861 25608 52326 333 33270 37041 63092 47424 33504 32889 10122 36505 34442 22638 43493 6224 33074 33449 16939 6637 57420 33471 23534 27721 715 33414 9025 33680 33615 33554 501 151 1525 5022 32931 49828 30549 28137 600 6054 443 22428 0 3238523268 +256 852 569 911 33665 244 107 33434 26 913 33063 931 252 33242 471 33636 33680 33184 33229 33250 12 32811 33280 754 922 33728 32850 308 32879 33130 33014 33280 138 33337 33069 158 26 33566 32794 33228 32830 33791 486 33755 33291 113 33601 33398 743 322 594 33565 33463 32805 595 526 33525 32820 33118 118 979 315 33155 33629 33558 791 33176 726 97 33596 33339 33752 33702 33644 895 8 363 81 153 542 33131 33492 505 33658 33228 32794 141 319 342 80 9 11 32833 229 33284 33371 152 41 33105 1022 32997 33057 33617 242 33125 799 33563 1007 647 33015 100 33139 33137 33593 33334 764 32946 321 220 32 577 33410 4 32909 70 628 33692 518 33007 677 32931 312 1021 33259 33068 33233 33304 33014 33454 51 418 709 563 33228 33355 972 33672 708 33612 634 33508 1009 33374 33225 42 33478 943 32886 33023 33762 32892 929 33325 869 340 33680 33495 33290 32993 33453 92 33658 674 33395 33261 32849 33205 449 32772 33435 32844 5 32854 749 410 33664 967 584 33493 32994 33262 32835 440 33031 33361 440 33148 224 33676 331 33071 33416 310 13 32924 938 32898 164 33655 203 809 33581 706 33092 33163 933 33653 33229 365 757 32855 229 161 33103 637 276 466 33239 33472 770 33341 33075 33507 33209 136 33227 482 33301 221 493 299 616 102 780 33779 33450 412 32845 450 33210 746 33325 32781 628 699 32984 340 256 45584 35499 112 79 33496 61540 823 2558 61185 23001 35887 33238 93 16605 495 21152 33339 18 25835 30590 649 558 33771 20 13050 33096 4523 953 551 7783 33212 831 11211 265 47524 43542 5186 26749 886 33077 33243 33650 18072 17972 881 1188 54178 33601 28889 27459 33757 59373 445 33289 7867 57334 32772 39133 6479 20808 33022 32927 57621 54339 60 61057 9155 21735 27 59989 1338 409 19887 19902 5482 43447 40424 46490 57579 4516 25430 46488 33778 32865 33004 16603 23394 12407 319 684 15257 58148 7879 33561 33295 433 37384 21117 64077 29702 32771 16847 21259 259 32940 9606 33408 33324 800 35506 275 33348 54407 13336 8736 1651 6035 49210 694 7318 32907 35997 954 353 9056 9 47253 47725 13206 114 600 185 11733 53014 4913 503 5973 456 33204 88 33187 184 33146 480 33694 33340 34443 161 32932 22849 27918 33129 45921 36261 1553 329 783 3019 33532 796 33690 454 543 1018 32959 33001 43742 33220 43556 33738 9633 685 49339 44239 37170 32967 89 312 627 518 33058 33002 415 37933 45717 61951 18054 38323 61 33464 11546 33067 33432 33023 32825 33366 728 31294 33408 951 9041 30635 34091 32801 41288 60792 33618 7 477 33080 55796 403 722 599 33018 618 47738 33087 54573 33020 43489 55962 37853 505 33191 2585 58556 57816 393 334 27018 33681 4085 32979 45312 33297 32885 23150 2282 47395 32802 26295 858 70 32889 42114 952 21147 559 33471 19987 38138 3435 76 49514 0 1067564316 +256 33640 1002 230 321 981 906 33614 744 976 33204 130 267 32824 32987 642 100 33765 76 33644 934 282 33409 9 33125 158 407 307 32926 440 33594 42 633 33641 32815 33327 946 33148 33575 86 14 638 33233 33523 276 588 818 129 731 658 33312 33214 32772 33228 32976 32907 32870 33353 33588 342 32857 893 416 737 33198 33318 778 32838 530 23 635 32807 630 33478 607 213 32847 957 33598 33485 53 537 33458 419 32917 33727 33527 33163 32940 33266 997 308 32954 32770 32894 26 813 33627 33687 33223 33305 32914 638 383 33548 486 434 33289 123 691 815 514 32883 176 353 404 33301 58 554 479 63 33576 33750 205 665 195 33637 33165 33507 674 345 898 307 139 33485 7 752 177 33102 33494 414 824 33182 434 32883 668 500 64 744 33060 33078 937 584 380 32940 33503 436 32995 744 33721 385 33691 33270 33201 32778 565 317 678 734 591 597 33167 33295 33316 1004 33341 33380 733 499 33199 33670 33541 819 33114 610 33511 33330 32852 32842 33383 33531 33324 33463 944 232 585 33611 32830 987 342 33418 33623 298 33091 727 32947 831 33031 552 781 277 33093 872 33551 32 258 679 103 161 991 33271 106 555 67 691 1 33650 33021 77 1020 33098 920 33086 799 33316 33457 33612 318 33696 32974 380 222 621 10 835 142 33242 33293 74 33277 341 880 33745 32964 32949 33250 33396 41876 26250 579 53504 32770 32957 173 33298 33639 39623 29352 30758 5040 196 51247 25206 3990 30012 33391 41258 950 47215 26193 2852 18546 33431 44162 33786 33139 387 33436 2094 28881 770 12564 10990 33565 25372 33059 58026 16871 58710 276 33689 14767 33673 33318 981 33573 749 394 9418 33128 57484 730 63851 47314 15602 286 54319 63264 3428 33456 10250 580 33639 32816 869 36737 54 62393 59409 44406 44494 32806 72 16965 577 55000 34827 527 28808 666 33625 21549 33544 21769 15672 284 33139 643 55542 6 33435 50974 16927 32867 47568 21030 51706 52 33726 25734 6803 33745 902 19768 43714 40340 559 370 851 51719 978 258 437 16553 38 930 47645 37931 32896 32916 55039 212 60876 50745 33435 2896 33971 21292 33542 899 21235 32845 33483 477 102 7531 317 33207 39830 1447 1557 33741 53128 63078 57719 357 33254 33193 22576 32806 39225 373 3450 40992 493 19045 33703 869 886 33028 363 48455 762 57136 33147 5735 33130 5 37444 47864 41351 209 33162 18245 7 14333 26716 43994 15668 36097 38285 33365 540 33384 55359 33018 12051 45622 35060 56 23765 56694 33484 47419 40568 33509 172 375 567 33102 12310 683 52616 32789 44325 34376 33557 33904 683 54864 33677 33090 32828 738 469 33622 54464 32770 28395 35343 33664 620 43474 244 35195 56701 49409 34992 32955 36575 33456 47657 960 33075 32942 63574 51566 33624 33262 60948 36865 33509 29663 53605 259 33262 33788 8660 33479 2203 32783 32956 32870 0 3213820343 +256 599 33096 527 33426 105 32784 33112 33502 33248 33029 32896 33245 158 33390 739 33466 826 994 32900 951 33690 505 33687 412 33277 379 122 1011 786 119 33772 469 879 335 33664 33053 864 59 642 80 400 32770 33234 523 33354 249 612 33771 451 654 33694 633 33268 33412 614 340 32934 32833 147 33047 586 33503 111 242 33463 578 33184 750 33300 33467 802 632 591 201 488 32865 33770 859 160 220 33454 612 920 652 456 775 537 33181 334 33668 33591 33709 800 465 583 33569 46 884 364 33027 33548 748 33579 963 503 366 837 1008 918 33161 33080 759 33640 33361 33281 579 33394 33188 76 33715 760 127 32885 33321 475 674 933 33109 33628 425 977 147 723 971 33273 33129 33002 33609 416 32996 970 33071 824 164 941 281 339 30 32846 410 32810 32999 33740 160 32890 33147 429 141 33264 33321 33012 810 33318 33387 33791 636 753 411 33134 145 441 224 32841 33671 297 582 971 32990 248 288 33469 33183 32985 68 33628 622 32906 679 32969 508 33192 383 33689 933 33000 461 33453 33168 520 318 33654 436 32809 94 182 33740 76 33684 33498 442 975 33655 32948 32794 33735 86 32935 464 84 641 33322 33175 33099 54 33219 33598 33369 33604 32825 33446 33586 752 491 612 33072 33341 784 33320 333 33251 33668 658 583 311 434 23 676 65 854 927 239 991 33209 291 850 33541 32995 33255 647 33387 40096 488 26233 37836 19195 372 33079 57218 23152 33326 60079 2272 688 4560 943 39200 33292 3191 58180 13997 51340 17319 33217 968 23096 60919 934 33399 42326 30943 842 909 400 799 19870 33500 16826 370 40124 33587 25 33790 33503 50591 56850 21737 33451 948 33360 22566 714 1214 16131 972 28696 32981 33106 33494 1003 229 18013 387 62792 321 33459 33424 34011 45809 33342 35962 60663 97 516 46714 32866 32926 32957 13697 16704 13368 36748 33514 55105 59266 32908 29350 4629 724 52992 46096 32894 9315 425 587 17468 41778 37398 17898 33687 28517 33418 33568 16211 48951 49723 4746 17396 7107 53660 32801 718 913 940 33025 39902 12344 8441 50388 513 47337 24796 1418 98 21432 56257 52409 33752 283 330 40951 48827 33424 32796 33015 24612 15050 30428 999 33697 15339 37245 418 8170 261 22290 43964 34480 33306 51759 6873 6942 33769 909 33248 33569 173 33160 17910 33421 269 33265 455 887 33438 49060 286 40375 33778 11331 807 32996 58511 23310 33746 17275 239 519 44951 60463 55020 57885 33640 33853 32869 47849 975 735 610 27987 32785 42879 9937 33381 38320 33597 44463 33418 24222 2255 344 488 39 14501 90 25645 3236 38484 69 22362 52109 40183 33312 8468 34684 33256 8675 63086 33137 33036 4388 33128 63928 5395 524 5960 22221 403 56033 925 44862 564 696 33777 33273 17648 456 47112 584 62107 153 59884 33569 53771 23807 47363 33362 407 49902 6902 5567 17236 33675 0 1083947268 +256 33197 32839 482 33750 33645 33369 755 571 972 33444 481 996 33342 33309 888 33611 32907 33286 33197 33561 33407 814 33471 543 424 33730 575 33570 33113 33610 559 33091 32941 32959 33757 781 1020 543 248 32954 153 32874 33277 33275 589 562 830 391 731 327 422 33395 254 33308 33155 33191 344 33518 450 760 33782 33056 33100 33115 33306 33636 682 740 678 988 890 33695 934 33628 32779 579 117 220 140 929 33134 799 33039 32828 178 33641 32853 33339 819 893 33359 33789 32983 14 33008 850 808 33604 33243 33040 1000 33788 33577 762 33314 33123 33162 33305 33372 33414 33695 33486 881 576 33093 33192 33755 787 33683 33486 32991 33668 237 682 6 436 33222 33468 887 182 33230 33770 33055 33285 635 33609 271 73 32961 33166 33271 366 242 33589 790 32877 764 33479 495 32888 682 33494 833 10 33205 423 33093 33247 32835 33785 99 33063 641 33091 33456 381 33636 33692 32829 33054 946 33310 942 33459 33103 783 32832 33279 633 33453 733 147 33736 33654 840 33479 923 841 32814 33663 442 33458 807 33084 33261 659 76 33224 428 33536 33088 1012 629 33028 260 849 33543 33606 164 355 33102 980 974 708 521 33355 433 190 1006 832 2 255 33509 499 32829 79 32861 33225 659 783 33213 296 33437 33574 33002 417 13 33750 1023 14 33257 864 350 607 266 32785 966 57 986 704 33437 740 33165 691 32943 788 58072 27525 944 20212 518 39982 18381 33053 924 33068 33762 10876 4503 24461 14 33573 386 33503 33671 9720 33382 836 63477 51675 33481 33686 32875 33566 21924 29096 11872 9622 33426 59792 1364 779 64006 42 966 9857 42363 3735 57883 559 591 49 33767 3038 33199 19944 301 33561 6243 52298 57035 19422 645 33009 33453 39409 1007 25889 28397 33661 33138 33155 33098 33219 54132 33578 29835 523 33006 58621 37483 27403 32775 23417 32899 33787 61779 33274 33036 371 60593 62435 33678 33406 44721 313 2586 8469 23835 7145 33004 15149 453 803 697 898 33318 39457 32796 27546 41107 33762 33084 309 30278 1187 21771 33788 32783 32833 33147 62977 33577 53426 810 46279 6362 49358 320 50017 16685 33252 33575 41562 2692 49520 58 20311 697 45107 32828 35358 15392 39274 931 192 14357 10390 5578 33158 4340 33500 33377 32914 33071 354 31023 33366 32804 105 10182 32780 49097 6684 151 50104 33246 676 33040 33030 33223 47252 44001 25347 27323 33321 33668 38859 44738 33726 786 40167 413 33252 29942 14512 5967 32815 29404 63369 33227 7950 638 194 855 16053 616 99 16701 32827 61115 17964 338 33713 21374 40877 789 510 58275 25558 5022 41354 32939 33749 23607 42152 2146 59776 33606 16647 85 33949 33412 18975 56144 314 62172 19156 185 20186 60703 24926 32925 33094 47542 39833 9138 35201 42573 326 33573 612 33169 33223 33551 22458 61827 586 39253 33936 40395 7485 33510 35387 33278 35171 61644 15889 201 9988 710 25918 0 1081182473 +1024 540 33234 167 33658 33268 32991 578 26 33578 445 932 953 33314 33634 468 92 33697 33018 260 33294 33043 33036 33624 607 33078 606 32866 670 73 33513 924 33094 32904 32923 6 33084 336 33719 664 485 146 33440 33026 33173 348 33057 33584 33342 576 33509 568 482 33028 240 32875 406 60 676 33704 33591 801 657 828 907 33742 724 690 33298 33042 239 468 33206 33349 681 309 591 893 970 35 663 33590 964 32818 32868 447 33217 33754 32788 33203 85 32813 823 33477 33518 1021 858 32993 987 961 33615 745 952 727 128 739 120 396 33109 33031 33090 33357 885 437 882 33078 227 596 32947 113 33664 32922 258 938 33580 33474 33254 501 294 775 983 33435 963 33024 32877 369 292 1023 33003 1009 33747 33581 33193 33303 775 33747 672 33709 6 346 292 33205 33775 32776 32772 33605 33087 950 199 33285 33499 790 33117 381 729 33712 33047 33623 726 804 33038 33017 32971 33490 33185 522 33391 32947 825 500 32979 236 366 33561 33387 447 32856 33084 308 33032 984 33518 391 719 33756 274 33180 33729 33027 477 1000 906 33556 473 535 33233 33750 100 975 33307 988 32905 33229 33593 33723 33390 872 32779 270 33018 33779 33644 760 33275 33344 384 90 526 803 32770 642 33551 32882 341 33634 862 33250 921 713 358 33739 33545 254 33680 33244 98 127 32896 879 163 33360 475 899 33592 536 409 408 548 32982 686 765 204 569 531 33269 138 827 33601 33243 146 827 33717 731 33666 928 33727 32775 33668 33596 127 33343 316 33451 25 32900 748 76 182 51 33459 392 686 134 631 381 32837 33055 816 33576 32890 33220 23 33334 669 290 33478 561 33688 33139 204 227 32784 33469 593 817 158 32987 784 33522 33762 33065 33078 33650 33220 616 32883 208 32972 32953 955 33668 33500 226 32841 32903 285 455 906 30 440 48 33232 32914 271 32983 33264 783 33337 33480 33061 246 33387 907 33253 878 33193 426 33233 33084 33788 32910 441 702 33689 33209 178 829 33400 33766 33346 488 572 32943 32893 33731 206 33392 33718 33791 33116 742 120 1021 33752 800 138 33536 32979 32956 32878 817 33390 762 716 33297 579 160 33696 650 526 919 665 948 456 33 33374 33767 33727 417 561 33141 540 33233 768 33671 380 37 45 33051 248 523 211 833 822 838 33209 656 310 32923 33192 32970 808 366 33524 33585 32971 33769 33582 312 33342 306 261 298 33432 852 408 635 475 141 440 260 983 442 292 33721 33755 778 535 32843 440 33692 177 33418 33489 222 589 869 32901 374 130 65 4 33484 32970 32794 502 33686 387 897 291 33606 622 1012 485 33274 33266 765 33170 33414 33523 33601 33678 33366 33231 33330 33780 33409 669 800 952 33546 23 682 162 32798 545 33526 455 33214 364 591 33674 103 33704 33147 33707 46 32955 825 7 371 447 499 408 32846 33265 750 32930 33092 33239 33331 240 33230 233 327 33762 499 629 33712 183 32914 500 145 33577 32846 477 1017 33077 508 885 33642 610 826 33538 360 33561 78 287 772 33684 264 33766 557 32792 872 794 648 33662 33300 810 449 33519 33170 33381 565 622 625 283 33364 542 33594 32947 495 33022 568 433 929 33215 33787 32895 32936 33303 5 32840 24 165 33170 32819 33477 994 33704 32932 6 33123 256 316 867 33019 33076 159 644 519 32827 33457 792 32994 724 33676 32838 33098 535 525 33123 33402 570 464 900 33514 43 634 32784 756 33176 149 33011 818 498 61 33226 33500 33776 262 262 33778 32823 987 630 33147 824 33395 515 33243 521 514 33143 33742 281 355 775 1019 33171 211 566 161 130 959 33255 33340 33270 528 32774 498 32877 911 755 739 115 194 33081 33540 611 939 920 608 729 670 33545 936 247 33746 921 32963 371 193 32828 32832 32797 33492 917 426 585 33657 33034 124 33164 386 32776 33188 33214 33270 33153 384 740 33271 33260 220 33236 496 33163 32908 177 33576 33466 33003 33229 983 1008 33687 721 33156 33381 32959 485 33764 627 700 33245 33536 725 32816 33531 33577 32930 33609 469 33499 33777 33539 33339 33776 32993 579 795 33752 812 110 32992 620 827 820 1 33398 33677 738 290 830 32946 401 677 32913 809 33289 33344 33084 674 33280 33597 847 372 911 705 32918 33632 33452 33190 33507 32792 500 92 682 32811 32802 33744 33226 33027 812 33142 148 422 33087 33651 13 503 33031 182 359 33446 700 483 691 33086 33230 32871 33159 33054 202 47 33535 33267 32873 96 32904 33135 930 33274 217 33296 33049 33394 891 33736 33121 33450 33772 218 475 33622 32876 33114 531 33667 33399 33455 312 33317 303 129 32961 32776 895 33744 839 643 107 743 230 32782 33264 431 33614 33113 33436 936 191 33111 133 33624 33446 182 862 33763 277 183 33737 728 925 522 896 33088 606 147 33675 711 70 217 33238 32785 32884 33390 116 407 33736 141 24 32837 1005 33680 32851 996 33236 721 32903 579 32856 249 734 33694 33342 456 33157 33395 80 984 466 608 157 547 32968 33293 393 33456 902 32900 33561 33422 33675 757 33293 114 629 33266 902 33073 895 33462 33744 33451 33474 466 33219 32878 33484 32932 797 44 274 33080 33537 1009 888 794 837 540 15 831 355 773 945 322 637 33595 116 1001 32946 82 33365 266 930 564 33043 17 33371 33230 220 33702 33542 32945 33523 150 33681 171 731 493 33592 537 894 346 33178 626 33209 922 692 33242 445 32834 33664 33359 32859 33424 33112 33680 1011 33596 33477 33506 33529 33583 33214 33315 1020 909 546 33301 33462 312 838 16 997 817 798 33698 833 349 1 32799 62811 349 8408 37020 33211 51408 33348 991 28423 33335 554 33306 64254 57992 23295 92 32856 30260 710 33740 19883 948 4495 323 58911 43529 33440 40544 21212 600 32827 649 3834 33345 33393 19438 642 47339 41495 3584 36813 33462 32850 33783 33467 21105 33523 11686 33619 32855 33527 32792 33765 3871 38440 33096 33771 404 5722 907 14173 187 32970 33729 872 619 33541 944 39344 1723 33096 33778 33821 1530 5632 865 26980 32985 688 29066 33517 997 57484 140 15824 789 17361 862 40991 24749 45537 20294 62121 361 53260 18327 456 33772 40382 370 32879 740 1930 53264 33700 14366 32821 388 33271 33529 183 37901 28767 33606 41162 1104 617 33033 33602 23705 48234 20187 37808 29198 45672 33267 3609 55972 48809 59649 33710 27473 5012 16667 32990 58638 46041 12921 652 82 553 32979 24131 35129 302 204 13611 4040 1140 56422 779 41913 33003 163 19984 60933 34504 811 866 29604 60415 37999 33655 33732 286 32805 996 1107 14521 28925 30634 956 20633 37923 52368 47056 898 46958 33193 35296 60792 40685 33569 32854 33013 42775 219 33528 33466 4126 642 938 678 46415 46512 1785 33022 29745 32961 983 6589 33771 56453 33693 14074 42446 55161 906 43296 33323 33300 58581 22539 33049 49943 327 32989 482 10311 33004 903 33318 33318 33393 1622 33034 24110 33736 928 32918 48366 18245 27969 64299 575 33588 38153 978 108 32922 15353 33213 455 20540 1007 323 591 7854 5257 726 12662 33695 37 32777 33454 33680 117 2336 18649 210 32928 33691 312 294 940 14910 8 155 33637 33636 59250 31467 47809 855 50853 146 47910 531 33213 23157 53889 49516 18726 3576 33324 60306 541 33454 10033 39430 58555 21324 41009 398 4716 11265 60243 51579 26489 9044 14759 642 38461 12498 33366 50941 33502 634 88 33245 31434 2480 9654 3550 33442 41 33038 33556 61436 33754 32912 62971 66 302 264 32877 26187 853 1015 33420 81 28140 30802 51663 28470 39656 32933 40491 33464 33070 33282 32927 12252 37915 33519 18 806 39103 32788 9049 12233 449 29675 26012 48874 773 8 1996 948 856 33148 3224 666 53438 23022 33652 483 11410 7044 33360 43956 32990 33080 58274 23776 31676 50725 217 60386 9542 21233 564 30924 288 161 32966 33010 33587 35787 33317 50530 286 62819 33752 33295 601 396 48853 39089 464 32811 23742 897 47879 21566 33248 2070 33685 32816 63794 34171 21163 6244 655 43131 470 644 15598 48926 6677 26598 457 3507 444 8897 51260 21136 899 19186 40168 623 609 415 33441 61980 33054 33259 30389 33607 63218 33302 33001 636 11443 1004 46238 12564 50164 854 193 26774 20961 32934 33229 942 2871 16353 33294 49070 33046 32782 22 360 61387 31160 42797 711 33372 44967 53581 32874 413 33737 10612 33670 62381 43973 44016 56240 14201 58933 49597 32835 33284 254 49469 7982 38462 32841 562 607 12256 3768 33719 37391 534 472 758 40775 15763 41045 30565 40414 464 6638 32886 536 304 33414 1873 34629 40626 33784 962 11065 938 381 33506 12438 40272 61103 53010 53808 407 15522 27603 20410 60366 512 376 1909 32983 29466 62289 33266 311 32885 33712 33381 33240 21524 17676 8 32857 49073 19262 32925 27164 47508 53817 526 26770 935 33729 4478 48605 368 43125 58767 33657 43146 60334 33343 18911 12890 858 612 768 33500 50739 64414 188 904 31295 39714 750 33696 157 583 33736 405 904 32859 33104 57238 414 36948 33242 63 33435 10974 41774 50958 45572 33717 580 33289 57431 42318 33048 33086 33505 285 289 33602 33636 40651 26232 49953 33706 33729 40383 14006 257 389 56954 14354 400 52192 54769 14805 2189 27950 22884 33300 28020 7058 32959 24033 32899 33272 46699 595 11585 228 33350 33737 32804 33704 616 256 28424 44360 959 26890 49583 26840 54875 51430 85 753 19856 54011 561 33934 32937 941 28631 20321 53 33080 12484 43643 33780 33551 29251 33673 44803 621 537 795 27222 17730 33332 32892 176 33348 33404 33493 900 14646 36281 33446 13412 3676 33202 8641 60140 33695 33548 35151 27739 32970 52203 33623 767 777 8541 42 493 33350 30147 44674 865 3596 33673 42456 21380 33369 37622 616 32781 577 20991 33686 26039 55638 17212 33711 40273 36988 21875 820 33571 33680 33437 33459 3795 33760 42390 33032 973 40103 32843 33182 5481 305 58708 209 309 25567 33439 447 781 33656 45666 12538 33774 59517 7072 19436 254 33733 23078 603 14586 32821 123 1018 33024 743 40 11470 10723 33351 51128 33038 866 52313 53602 641 33115 540 32799 32961 32819 40587 834 715 496 37574 32783 7943 32897 33169 32813 5538 33472 15 4 39905 40351 46445 32782 33327 38167 840 13654 43558 21046 44479 50381 6123 60193 3438 2856 33309 2760 204 272 33252 33410 42363 52185 13309 143 15127 33033 33516 826 335 781 41525 465 19418 50314 1002 1237 27555 315 56396 877 33072 33634 33101 33215 156 760 224 4220 33245 14550 32928 33767 847 50407 50822 33627 15934 49076 797 52720 42542 4681 41671 33534 38576 31044 14570 58283 341 982 39298 391 33404 5423 668 60560 994 79 46510 15443 62852 232 33343 42269 125 901 32970 9143 848 33163 468 7916 32774 15026 71 33169 493 46051 61 954 19706 33160 33656 45123 33312 30841 56 33723 60743 568 13063 46977 32839 61237 33323 771 48207 26618 43322 791 48605 63576 20017 33537 49450 707 19666 33067 830 33044 404 128 10244 33098 3106 55949 54769 56887 20106 36 3727 44189 38269 540 44201 53368 783 1 26973 420 4142 1700 31410 57468 53036 23526 96 10073 33633 366 1007 276 33212 33042 4275 750 4007 52441 33469 32987 7020 33801 40739 29564 33090 26881 872 37247 30414 201 33345 33025 181 29744 11959 14624 572 3 9383 29519 59744 529 33182 30847 33141 33546 33661 13139 38392 33562 33064 33158 7017 255 800 433 15502 3273 33745 38597 51028 28036 26597 27114 108 47369 422 843 32867 63668 374 33269 561 56 46232 2815 13893 33425 21335 21539 97 32790 0 1099031296 +256 557 219 33763 56 33471 668 593 33023 571 20 33034 33332 33616 33354 32946 745 447 174 724 33756 32787 32805 410 32966 32970 33414 133 577 543 33653 59 349 33501 33576 971 33041 192 599 320 33195 800 632 672 805 612 32978 489 174 33435 33542 33289 32826 821 33401 33323 33192 33286 33668 76 131 87 805 569 32952 885 33316 159 125 350 33471 678 852 27 32804 537 33734 534 460 33451 33152 32881 33463 109 118 33398 988 330 33021 850 18 32811 797 33204 121 33441 277 642 32934 33254 274 446 32775 886 32869 33524 32828 697 33269 32798 32922 33082 32876 33257 712 33167 33030 32894 111 33523 981 85 33497 33416 663 33743 33526 33762 824 6 361 33148 33111 32872 592 33764 1016 33410 31 540 238 362 32939 33027 409 33688 587 33732 32971 686 33114 33432 995 325 243 442 33375 543 33380 33104 33563 33239 33742 33088 864 413 32799 2 374 33071 33484 94 32853 32906 32977 32862 973 156 780 459 512 33368 33759 161 230 32802 33088 32813 33376 667 25 250 33386 33710 32789 33707 33772 33075 33364 32817 26 33238 33532 33722 32816 167 32799 33316 33781 41 33078 33369 33643 33451 195 336 33207 668 32853 32935 33130 33425 514 844 503 615 921 832 756 924 33125 33658 199 32788 530 432 261 33698 554 32994 154 33617 33054 33783 33369 111 288 32822 811 33494 824 33574 33346 33192 33172 59 677 50820 32912 33764 57852 46598 32794 32774 980 221 35453 948 35316 33741 30 23658 18755 33607 33296 983 40585 32896 275 33495 32926 33161 7813 33187 20557 1416 59827 22619 33041 55455 13815 310 33422 44147 30020 6526 33411 33221 16457 63255 19290 33654 10688 32806 32843 783 5876 33471 268 54775 138 387 445 32961 33146 28116 32981 33537 37049 33182 468 16335 25796 60494 21626 33059 30091 46508 32794 710 30898 33435 35257 820 33218 33733 33517 13 15755 33660 263 35093 63779 9047 54272 2155 2018 50043 50184 23135 253 19868 9258 198 25333 33419 45104 36 17130 14399 11700 742 33269 4636 44962 51663 31242 227 64051 32870 20327 33310 472 33276 14095 636 57986 755 253 5615 33632 21623 46386 49448 63148 44627 38589 151 54699 31296 15117 22781 654 869 48908 33669 33153 702 400 39874 39255 58100 34375 45082 63013 340 1018 8242 32892 815 59737 22687 15279 6404 16936 14252 33779 24191 316 58 116 59960 29114 36389 961 56366 54823 57272 423 29419 46379 44178 85 40171 24 694 33535 33349 50083 25749 32952 20043 6209 249 534 32900 33772 33382 38911 790 53653 1006 30175 6363 9135 12966 50211 21614 434 1010 33073 33433 1365 27 20364 33229 698 9698 52600 57302 548 16735 38551 1021 33159 33439 16493 47466 53208 32812 381 46 33001 12571 805 16352 50257 32783 138 45698 16810 55163 914 713 46095 58152 517 520 831 791 13025 17034 342 798 33182 42011 57211 887 59480 46882 1023 806 33569 0 3235735470 +256 859 793 33666 33623 32832 33570 33590 198 976 449 33034 829 33393 690 887 33544 33349 33132 638 428 33436 135 33011 589 594 33048 32910 32981 33396 388 32833 33069 32866 128 70 33059 221 32837 607 33025 525 763 250 33664 33643 33683 32978 33672 53 33421 680 32823 666 33489 555 68 33709 32814 33556 1011 387 488 33193 33623 32770 33578 32952 33578 514 714 33728 726 32938 804 33200 33783 841 32846 32771 311 591 166 32977 62 33185 33045 602 83 557 635 33155 33776 33340 33111 33787 33189 298 1004 32886 33116 870 33250 641 33774 936 33437 33570 33516 398 33754 767 970 354 33154 33543 33715 33744 122 33658 120 509 33642 33192 33399 33311 33647 120 686 433 33578 33386 328 33487 33463 33190 32999 80 728 193 33366 255 33505 33640 32851 95 32995 90 64 574 460 703 33121 33656 33441 775 33370 33544 33022 33782 736 157 33244 33413 163 33639 32814 33204 5 33053 816 291 32941 33693 512 33649 33635 33777 33490 33693 33401 957 83 33132 719 33055 33758 33283 33018 33725 262 648 33750 615 709 325 117 33111 1002 33292 597 33519 520 33651 204 33604 613 962 33507 32942 33387 33200 33293 33479 33334 507 33614 903 466 33018 33453 164 33381 33394 591 299 33017 242 693 32801 32932 33397 787 517 33669 32781 359 33633 485 503 461 129 33489 33086 193 33764 33154 643 803 32862 933 54 33521 33278 661 33620 774 111 58318 1344 18277 33592 63909 55369 33611 33515 48648 49678 33212 19215 30240 32784 45149 33595 33220 33761 26666 7789 32823 494 32832 28044 47823 29057 33115 56624 33260 36687 440 825 59340 53070 33351 59395 26384 46 685 33725 741 282 24326 14061 332 59894 250 49478 33530 991 684 1021 33764 657 138 431 46900 908 52 53640 787 33723 22287 32990 32779 33162 32958 586 426 7023 39668 29647 33326 33288 193 44118 33255 13962 38933 446 33637 6133 138 214 47235 32956 991 33638 5337 32977 33722 1939 43877 45545 40698 51224 23001 346 1 23047 27693 682 39610 2479 45460 343 14526 7806 21127 14011 49 1013 39565 49641 33012 423 33744 33586 1005 655 742 14746 33126 32799 818 292 427 17394 761 146 9351 32854 37787 1001 56893 33580 45843 33283 48927 8106 95 9899 218 45734 465 38421 43074 112 21264 37387 53352 20601 517 33658 14812 33401 7673 33063 306 32878 5468 33514 911 33101 960 33671 33488 30947 42633 404 552 262 9927 785 40 6964 11004 47748 683 32797 596 9606 33098 33018 35186 9810 33170 566 18143 665 37638 33122 60823 32894 718 20342 261 15085 22129 482 33105 20528 33060 522 22427 879 33224 60193 4239 43783 578 163 33587 33011 33658 51974 33501 915 649 48382 16136 17369 33155 33355 997 225 32785 5225 7865 32947 784 60434 506 64152 6197 32998 53170 11117 16365 627 30065 52334 599 5984 401 40796 33489 22298 18351 24964 33521 33748 35201 748 5299 0 1066595627 +1024 33651 33712 33260 236 33117 193 710 7 750 33632 945 32800 488 84 393 1020 32829 33597 33768 500 32941 33008 926 373 340 33195 847 32953 33643 815 33730 890 33085 33288 482 33131 540 33219 117 32873 455 435 971 33245 687 32961 33753 761 33755 14 564 32999 33482 33733 542 32806 33267 511 33200 33215 162 600 33324 32918 514 33442 42 33555 15 33264 212 33651 880 33599 33153 33338 418 32791 33179 33713 32893 797 33472 33583 937 33423 33611 33031 33198 478 33122 32930 33690 311 925 656 33371 33027 561 33289 33466 279 572 33657 1001 971 33353 33153 787 33541 378 33018 913 33746 708 32900 32827 33381 32781 277 552 292 342 33602 741 33269 33235 32796 33658 238 428 67 877 33405 91 129 559 33439 643 83 413 33147 430 749 616 32796 118 33435 118 307 287 33541 167 33277 625 33315 90 33171 33395 51 437 32923 275 693 33550 33527 794 32957 32990 616 33431 33577 33421 856 32952 33342 951 33671 33693 33391 724 32954 47 449 33068 33508 811 33165 33506 32803 32826 32901 504 33006 33539 33602 198 647 697 928 33059 36 33689 33609 976 33148 33753 1013 33115 440 657 33595 32990 33602 481 856 822 1019 996 33222 32977 8 1008 33146 900 33337 644 132 33502 32800 33261 33134 33255 33277 32974 250 690 32942 33559 139 779 834 33416 33098 44 32820 33768 33210 33356 846 33646 33183 327 544 33133 33303 33304 75 33106 107 240 33497 33574 192 33260 961 941 979 440 33167 312 532 221 398 555 33072 33377 33103 617 314 33665 33484 33096 32885 33761 433 460 56 33451 870 33059 33242 33270 33713 33424 33686 33319 143 1014 220 33647 300 33331 32836 711 33717 469 33144 668 699 441 460 892 33316 811 33432 745 144 33588 33268 33681 33090 149 765 33167 497 32833 791 732 688 33187 28 425 33729 32810 33571 615 33353 813 656 33050 347 33671 172 624 33160 863 33138 32782 19 32867 5 32819 32886 33496 529 32850 431 33038 33282 33688 33622 33362 773 595 754 33330 274 33505 33164 33520 32937 677 390 519 115 949 32920 66 397 831 33482 33035 714 33239 427 33227 353 33738 33645 33394 640 373 650 722 32919 949 622 33343 412 853 601 352 531 33492 945 968 758 865 33541 33377 33715 33450 33374 107 574 809 956 78 33185 746 944 1021 260 954 551 546 33697 880 32905 424 33154 33088 33184 152 33452 495 457 189 33349 33613 328 33678 482 483 33225 33456 33246 43 33485 569 33091 1016 230 33784 927 148 33523 33601 326 526 32985 33634 32993 259 123 32873 33340 33596 266 914 32930 33756 587 831 516 32803 166 32788 172 33662 32876 32912 955 770 204 33441 33520 313 417 378 33194 32988 325 439 761 33372 400 33588 33731 33005 281 33701 467 33162 33039 764 33291 442 33324 246 359 33504 773 33700 33653 33632 33626 33234 942 33385 32889 32861 396 32846 636 92 33426 66 2 17 621 32785 33339 33750 460 850 251 32856 750 33740 1 549 405 33367 33595 671 444 32875 33588 412 33698 33201 33743 33040 158 33783 200 378 33069 33312 33765 835 33665 33135 33481 33190 33402 447 33216 33185 33505 33194 109 33392 43 638 532 32810 102 95 33365 33171 370 877 33323 793 33257 33404 644 32872 196 720 133 33734 739 32910 33586 32858 33018 835 519 33368 33015 791 10 33104 755 33721 33158 32788 33057 33616 33050 286 218 33461 369 33306 52 358 32942 33132 33054 32879 380 108 396 814 973 33048 615 46 545 747 892 868 329 32814 33216 288 32843 33587 985 153 616 980 32927 33042 856 33071 80 33171 934 713 33101 33254 793 780 438 33769 431 923 518 33200 33014 33106 33477 613 97 33510 33212 32960 650 973 33088 32990 233 32961 63 560 100 503 33173 33157 373 32861 33042 506 105 333 33653 137 260 319 33483 464 32900 725 777 869 763 33434 32895 33570 33001 33680 894 33501 33557 32874 33791 33126 32869 374 95 33637 377 33206 33097 578 422 33270 32977 294 805 520 913 929 33401 33411 33665 178 33101 33609 33495 33271 328 32795 299 158 32889 32803 670 33536 98 33481 33780 32814 33147 33640 319 453 236 302 119 304 33321 179 821 33437 111 33204 837 10 208 327 697 33173 33566 32988 33578 33014 33757 33642 305 33747 1 579 33292 856 33232 188 355 164 33070 727 422 33391 349 33119 32781 33486 176 719 33400 441 33281 70 32820 634 33306 130 440 33749 33251 659 999 742 719 67 260 33775 600 456 33087 741 33281 33314 1017 157 32819 33034 204 33214 33514 33482 33424 125 33163 33068 33052 392 33346 95 32826 1023 809 32932 33728 33747 808 33770 33442 155 33693 33663 32935 745 726 292 37 285 343 363 33518 33202 33622 32909 33722 495 931 33627 744 439 360 33744 33038 33470 467 424 33376 961 807 33585 650 429 33656 459 562 461 33437 654 33634 33406 32914 33313 519 33268 33665 33250 33104 33729 848 357 216 32917 501 329 33568 33180 33617 33569 33219 999 647 33330 876 33429 1023 185 32987 33558 32814 33239 123 33442 32912 32832 84 903 33730 33045 233 307 99 939 33069 963 540 33610 88 607 1015 33167 33224 366 33662 33026 32859 670 558 32841 33678 33078 612 763 965 288 305 1020 33261 33726 33303 33362 781 33782 734 32837 33146 33021 33510 33585 215 32857 33293 33679 33752 963 187 32993 654 395 33556 33525 279 32870 967 33423 32912 33143 33495 408 321 33118 579 506 333 741 703 990 33257 487 902 33376 33634 32942 33061 33196 869 949 370 274 179 32899 115 33537 751 173 33005 33602 33159 33410 186 663 714 33117 33168 846 33548 32955 32879 33700 603 43720 248 6060 311 163 43030 32845 18212 607 6550 65 24743 33363 47151 60909 4119 53688 523 33115 7030 351 33422 14596 33121 2487 633 59194 33280 13787 33205 33470 56760 971 5717 43135 115 89 6543 52868 20519 40013 58095 62777 30282 6900 33068 48124 47125 643 12030 55446 1007 10796 33516 13405 33529 206 52515 33645 14379 33009 27433 20628 22610 33561 906 29244 24849 164 63170 618 12430 330 38426 32987 82 38493 33204 35383 36234 46181 109 42780 33136 21019 18264 33602 643 33036 324 48875 14210 44556 61326 5116 27460 32965 42554 32836 54965 246 16287 33085 35460 32829 464 15809 48642 33037 32904 8502 25611 33558 19183 662 33515 23803 33760 49398 622 55837 316 32889 199 13806 23171 33242 22297 39703 32779 32921 312 40918 58533 44574 582 22515 33275 55371 38463 36138 33013 288 953 9760 33203 33517 14101 4406 5147 993 33127 629 313 163 19235 33122 325 943 12637 50494 33767 30798 33665 23709 307 21685 21238 62689 17755 37108 48867 542 33038 155 35117 33162 54198 33448 33471 28763 312 5059 6925 517 445 700 32986 33349 568 753 96 33392 7902 61464 42855 53225 33504 477 950 40039 14793 954 39150 60537 788 97 806 497 18748 56617 258 33521 124 832 33417 14381 25908 25285 8181 33662 7832 33511 29240 22913 36736 23570 33092 33333 575 232 43059 434 759 50980 671 130 17672 501 135 16650 12907 49691 35985 46426 33519 33019 32802 7282 41131 11022 33131 117 32852 33397 33293 41157 33744 48806 33444 40198 490 890 33352 30145 755 33353 7780 33513 32983 20575 35998 200 172 25364 33400 33343 33039 15540 33704 874 19 84 27494 620 33570 33027 33666 33032 6265 6585 32775 33273 33447 54137 30434 33881 33774 48406 4912 47799 24086 33773 458 736 33474 31716 33229 46880 33170 167 40939 33666 33499 780 617 767 33333 45958 33555 33352 12077 724 40472 20434 48307 47858 39524 20014 64349 682 210 51331 5647 1965 103 42975 15966 53104 17744 70 13924 33134 47961 28252 48194 33574 357 8051 513 6064 22977 33644 980 356 9805 33477 32992 53083 88 21406 33066 42764 174 14922 712 49155 46262 33002 62 33269 51660 47123 33396 527 184 32965 473 52410 58255 14957 33677 11060 33648 38425 379 22075 57926 32919 236 11163 751 55311 701 33631 26368 430 33126 55711 63669 32979 33748 53557 8085 1812 43811 629 52849 719 33009 33558 20775 998 596 33692 56578 38146 29643 33467 900 30157 34258 33256 57751 53853 12449 943 6509 30026 33648 19089 33575 110 9425 41623 32866 55102 771 25926 11824 112 365 33659 22314 5346 8299 38037 51058 63509 15234 32875 33782 949 33082 49173 786 23616 43910 32910 164 32813 388 25186 47851 25621 560 12578 959 40389 55309 221 39072 681 33731 32960 982 13302 50546 33668 33192 767 33477 179 7433 58908 33767 33010 40499 41078 59181 33520 33120 48055 32881 42467 12014 49009 43030 33778 22631 1005 695 32901 9114 41043 33415 33091 33667 16676 41364 743 33316 29785 32879 33179 30129 33620 545 600 11757 44201 55129 202 3541 25803 48560 827 7995 215 33223 33784 33687 914 21788 807 33268 301 33127 604 33779 50049 33560 1427 25589 26074 257 5252 683 33667 14254 46991 56414 488 708 33145 255 23028 496 939 22 77 32830 33069 33597 6590 20683 57963 57843 33286 36552 893 649 33519 33546 11652 45563 601 27125 675 51075 518 33290 63706 33365 28581 60315 11980 7305 42675 835 32989 348 58384 17140 52931 27286 588 33149 33567 57109 33219 36914 34241 33579 342 38347 508 462 103 43421 42 892 33460 33199 32861 60849 14996 39179 34555 32830 33586 184 33078 694 2109 2380 18054 20256 896 41308 915 75 29253 18459 32841 32811 33224 32956 397 185 33175 33567 43916 263 32810 25841 4278 587 2471 33762 1002 33076 49451 33701 42972 33198 427 77 33097 22988 143 33536 49221 68 44506 33168 14033 46477 33400 33219 57252 33462 53963 289 62983 41310 294 62063 33844 32781 687 679 2858 474 14326 531 828 10954 17995 4125 33735 97 890 62352 33306 42111 321 183 9162 32925 33485 33727 60354 48155 151 33481 32821 33619 16506 402 18865 33046 652 14366 58644 32958 33227 61177 656 33048 43984 837 54771 33767 782 12769 11173 33377 57011 3849 4700 43907 33032 9863 487 731 30602 33689 495 36347 33145 45591 43262 33378 413 18827 251 19351 2677 522 51495 18672 59444 8242 33548 413 33508 33194 779 23320 24577 33645 51946 33184 4311 32864 346 812 54370 198 828 29748 48835 868 60053 118 33279 1256 286 39527 37194 623 33461 7816 33275 18682 1004 410 896 10 27950 7727 27429 33010 27807 831 562 33781 46965 55484 33641 483 44900 33650 59054 33060 173 40851 996 33525 33762 14638 43927 33239 4977 56757 33457 33736 838 33579 63792 62569 30340 33073 20506 266 386 33351 25764 32900 46625 33338 59891 35207 990 44710 32909 33180 24557 57018 33285 512 53180 33092 33184 22396 54 33194 38535 33336 33053 50702 33491 519 33212 33141 377 22457 33014 33568 24709 25458 951 33382 32992 39186 916 33306 19421 341 39594 867 57668 906 29524 27 56113 21722 784 58448 23315 14918 33736 537 33384 784 8194 25634 895 396 949 27635 33218 521 858 33087 654 33614 875 57420 6915 33200 55557 11290 33744 1908 188 107 47005 33406 17181 20838 744 26989 41156 577 730 347 33090 51754 6701 8732 182 50443 33142 33538 27585 51 29 508 33044 33137 347 276 33114 102 64246 12425 52383 420 292 30064 60966 56538 1580 23720 33259 43575 41036 3801 33200 34706 54276 13220 55581 33281 58883 33312 33615 15190 33084 33727 24724 913 58940 37940 33169 36307 49646 26812 20075 59446 40080 32773 18485 198 52147 47130 459 46848 56013 55755 23432 33700 105 33636 36425 58828 268 32894 935 940 12348 33544 33152 33646 20933 733 163 6564 30351 22711 9 2903 54961 323 141 54034 36319 351 46 33182 1798 33274 27169 692 33610 322 48583 24900 19843 617 5046 33156 0 3231393649 +64 558 574 33132 906 442 59 269 841 900 33317 33755 33201 697 33450 527 818 430 33127 300 33432 540 717 264 33693 429 995 33294 32802 32840 33770 33686 647 1009 949 33445 288 227 160 33092 32779 747 32983 33662 32920 124 871 358 872 33014 57 33305 97 33512 33406 32836 33186 872 33716 5 33593 33343 417 33315 381 691 541 102 14 33529 73 33160 686 32990 33463 635 33277 32877 33029 503 33706 123 33586 33 524 1022 581 33610 19 815 33074 490 33539 533 532 33670 930 33015 454 101 342 33553 32906 203 33089 37 33623 1013 191 32903 1022 466 33503 498 204 33190 32918 32907 187 705 33243 529 33754 172 653 143 168 33729 32872 2153666211 841626888 +64 585 33322 32888 32873 764 32892 719 32852 307 528 32847 247 33493 33566 33605 287 32915 942 430 33432 146 33519 442 33051 33761 32937 33777 33202 869 32800 33705 33095 32863 33627 826 33402 33778 620 51 301 136 216 709 441 32823 33587 580 33216 41 150 33380 674 33518 33239 742 229 33261 33264 14 32785 33209 33123 33462 32804 552 33500 32960 979 556 33066 32975 33013 32879 32945 305 160 33683 788 33424 33320 171 32839 32872 33677 33146 32893 33389 33058 373 33286 575 33213 33697 33669 670 734 33419 32899 269 33638 33167 686 330 372 898 795 93 33504 33336 926 33250 33050 614 214 682 33377 1003 33441 33592 167 571 33281 33426 32933 33464 28 685 843 2148421587 2982918520 +256 178 607 32786 130 33152 547 568 33060 33119 948 33418 33018 842 33217 32946 937 274 32969 33139 479 32820 33323 33102 861 895 33355 498 828 33448 32923 33472 32924 33618 324 483 32932 420 33788 33209 689 612 32774 299 32889 183 33765 33527 33518 33474 33637 33550 33556 33318 114 631 33593 33327 364 32875 33606 33131 666 608 672 542 33678 206 775 33360 33619 981 326 33653 588 33096 33233 1015 406 33014 2 33373 710 403 33666 647 32817 32957 32892 547 99 32810 33215 22 231 33119 79 33637 764 183 514 502 33069 33099 33581 33678 111 582 767 1 33529 186 33426 929 33773 809 454 33326 560 98 32816 262 32862 33174 33366 32794 32947 33583 32860 33546 33111 948 33459 571 990 33208 959 33424 647 790 799 155 742 33530 940 604 32957 264 33149 657 581 668 32863 552 33351 33369 217 658 33001 622 1006 33764 132 804 32989 871 725 468 732 60 905 33351 551 433 614 33097 352 814 33069 33464 33145 32796 32843 33669 33169 32965 760 33747 120 32853 67 833 33368 208 643 857 641 552 32849 947 837 33247 32997 64 33457 33438 74 32775 554 33236 803 216 326 604 33441 399 33787 371 33428 922 32817 32847 492 33547 32974 509 588 33034 33643 834 33693 203 930 32845 645 914 33047 359 977 33570 252 792 33765 33153 199 218 33085 33073 33764 48 32963 32933 32973 33725 33091 33301 33490 109 393 661 714 33105 33731 33665 468 32986 33013 33597 515 245 32825 464 305 137 32834 665 762 33131 620 33454 33352 247 32910 972 520 428 708 45 33771 33631 32938 33742 33468 33419 32946 33212 573 32991 33213 1008 33587 71 100 371 33120 990 33276 376 844 33249 972 786 828 33775 536 551 33628 33358 1013 33292 64 834 319 32935 32829 144 32843 92 33146 33064 593 33554 104 33508 32901 33547 33370 240 20 928 32799 32894 32967 784 519 33004 33077 787 32988 853 348 33684 678 787 33654 33464 32820 32795 85 521 13 33439 3 33731 33566 33752 852 33031 32828 264 33382 918 416 33020 33645 711 58 33215 916 33114 915 87 33144 32931 718 143 357 243 301 24 418 33755 33493 32925 33385 33582 33557 33618 33665 318 128 33325 33315 33733 623 33109 33395 464 32894 33530 941 33550 32828 32890 33751 33283 33268 380 33462 32799 33542 32777 964 921 33500 717 879 33520 33539 33012 365 252 33390 33004 32955 33236 456 341 596 33739 32948 33367 282 384 33706 842 33327 33007 32836 32791 33310 665 366 884 33394 33073 31 796 370 33504 33417 423 750 81 776 33318 32814 732 461 32892 318 436 355 32970 32992 833 960 241 271 33066 33176 557 33472 991 289 721 192 618 123 33660 33146 32904 33259 780 33771 33105 33588 615 155 32866 33017 681 983 183 882 192 33026 884 33392 33006 590 721 713 31381 2987456644 +16 32926 33142 33211 409 33652 33639 116 33582 33391 524 922 904 32812 47 33236 33201 33355 33043 178 109 32913 33701 495 33626 33052 33247 766 814 257 852 33179 33079 2151686332 844799268 +16 549 33336 294 33465 32999 33412 32961 33742 33060 33657 203 33364 33075 1003 33762 33705 40 811 33133 40 33665 32954 33364 82 1000 32910 504 774 919 323 33274 617 2153551063 2973495584 +256 874 33661 40 32917 33771 33017 212 727 525 299 887 603 639 551 33262 627 129 33760 65 33080 33738 622 33580 33485 33631 33633 33127 32855 33464 723 678 433 358 33411 33052 33332 66 33053 289 33149 32979 33538 102 33699 32866 32897 383 155 436 818 33257 682 286 32998 79 33523 33118 79 931 33786 370 91 359 32858 602 72 33605 769 936 556 33591 47 640 496 602 141 33477 822 32989 9 133 33087 36 33570 33075 196 575 278 6 33416 42 698 33702 33212 32988 33435 638 12 33787 32902 423 32931 32915 768 33731 33176 33339 477 33239 33679 949 33680 33130 32970 736 522 266 819 950 33095 603 327 32997 33007 404 33706 309 273 712 33408 32902 28 33593 987 33524 33193 33622 259 33472 33431 713 32863 235 275 33477 33070 33682 812 914 767 424 33520 33544 32779 33251 33394 33098 333 33124 603 284 32789 33353 33007 32782 33393 330 155 32924 769 1015 411 825 312 32934 32773 32847 33483 33314 33583 155 446 863 550 33480 649 621 384 762 33705 156 184 438 745 33481 134 383 585 353 956 760 899 33342 13 32786 33024 33593 827 33668 33613 32816 32953 498 73 32778 388 812 69 33088 428 33093 692 26 741 492 240 444 458 33399 89 246 33016 623 645 33546 32987 742 33082 357 33580 33114 207 473 32976 703 1018 954 33609 24 749 33479 32987 483 33733 270 33644 130 33601 33770 33439 33033 366 33495 499 103 32861 33045 33470 33261 33277 4 615 99 32979 485 264 155 33765 59 33685 33482 166 1011 851 32964 33193 925 558 99 949 393 33177 818 734 92 750 452 33405 573 33372 275 530 32856 909 100 32881 32843 164 32913 489 32828 303 33427 204 430 33554 32937 523 500 32926 33165 152 331 33487 152 33432 79 41 32793 33750 482 33304 32852 33403 394 33377 32946 971 719 33212 33321 546 33725 428 517 262 210 596 33582 32952 141 33749 33076 792 791 62 145 33479 33305 33547 33527 849 33304 843 32866 32854 301 419 32828 33179 33762 509 640 90 32883 847 33366 906 430 33579 33445 783 33699 33534 474 33455 33245 458 33202 33759 33224 782 699 33634 33711 994 32814 33179 613 33696 746 33011 32966 105 688 800 33301 33055 371 40 4 58 33779 963 1000 314 32898 33059 33316 33342 33159 134 32885 375 33652 210 366 33565 33732 545 33669 33010 887 390 33731 311 551 772 128 22 33673 33103 57 33246 33438 311 475 33464 472 32924 33476 50 33258 314 672 33662 912 752 32931 370 973 237 37 293 33718 530 316 628 887 32899 527 633 33068 906 710 33302 405 33378 5 1012 33708 885 33262 33504 33246 82 3 863 506 32898 266 62 1012 665 312 1015 200 32878 306 524 33616 390 33532 405 32835 33091 33192 689 33179 33712 748 377 7300421 829083536 +64 531 32795 33236 33408 33432 33200 331 146 193 32895 175 33720 175 106 33773 428 33198 116 248 33195 33087 416 587 32852 32982 629 443 33769 33333 33214 722 33573 53 33022 947 33460 33768 448 970 33411 116 441 33026 33304 33742 322 33286 33114 33679 555 33462 33285 492 33383 915 475 287 873 753 33521 33685 33030 190 56 709 80 207 33452 619 416 33144 685 694 33141 33002 338 317 33277 32892 32962 33467 32889 943 661 33234 33068 396 33237 96 25 345 32892 33716 33333 287 33008 129 773 33225 33122 2 432 33736 33726 60 33017 1022 250 33114 869 33276 112 793 734 292 474 32903 33263 597 33021 981 1 281 33568 459 33523 33207 32909 2153620055 840356292 +256 32999 33708 800 860 33662 33474 591 411 33302 33060 33408 882 198 33436 696 875 33097 556 565 32783 33055 604 381 32912 32881 133 224 303 150 33373 482 33405 165 33196 32788 373 765 539 816 208 420 477 33195 982 147 75 791 33068 182 203 239 785 33765 33017 33251 399 33622 853 803 143 33422 723 103 33304 32891 32892 32940 33349 32950 33578 782 33040 834 450 33430 344 33491 32839 33647 254 267 218 931 33735 33312 33584 913 134 265 780 33458 228 32810 48 32912 33693 33559 391 33065 33650 215 33296 33483 33172 33221 480 32981 33469 33705 33050 33091 33008 45 33180 33367 33788 33237 919 940 277 33067 33087 625 33488 32817 33115 584 32962 33008 33407 33166 59 33644 33748 404 32809 33191 33094 33694 33672 33600 33503 968 763 33551 33486 345 32906 189 299 33760 33730 32990 33728 975 33646 32876 33248 33094 55 32875 497 32932 33361 33663 506 290 33287 789 33143 33539 33743 33720 33486 32777 104 33727 30 190 32878 764 32910 270 33068 33418 33521 33584 32925 33752 782 32880 32992 377 32974 33673 775 32813 33618 10 32912 33729 33503 33454 779 32874 33082 568 32769 33646 33526 33364 33222 385 666 705 33737 934 33132 24 33233 33688 869 33786 407 32790 32989 784 33569 435 33194 266 6 345 255 617 33426 32803 531 599 32840 32786 33742 989 32985 33224 33461 897 335 772 220 33151 33764 90 246 60 662 981 33765 33198 488 854 33543 807 33068 101 33587 33082 54 217 109 607 33025 33606 163 44 32896 539 32791 369 567 772 33423 32942 138 33132 294 347 741 755 33439 818 33278 33646 703 33401 645 32835 664 981 33035 33280 33411 459 608 184 560 113 32999 348 33068 326 32915 33468 985 33508 33623 1014 33269 33245 719 32834 33054 33635 33128 242 929 774 33731 491 33553 668 622 32990 32793 294 965 435 33461 32950 33508 33639 887 33088 30 33691 33106 32965 33408 230 388 442 33542 656 32777 33036 937 33120 33366 558 716 33622 446 981 253 33355 736 33603 32785 449 33301 33403 33487 280 33615 33428 968 525 33404 32801 32983 963 661 138 33415 33307 33080 477 33344 601 33072 359 33505 33018 217 926 591 651 53 26 314 863 361 33309 33006 33608 33546 588 1000 950 32975 33235 32821 33544 33192 33244 33776 33369 268 132 33167 225 33056 66 32846 694 966 33255 33368 171 32887 33230 607 33053 548 914 616 953 548 33252 177 33570 426 33223 707 33435 32874 862 32861 33351 33170 700 860 33407 871 33633 950 33469 558 33169 95 33678 712 33507 629 33361 289 83 33141 33678 32996 229 70 32823 1015 910 636 540 656 417 481 33289 33068 556 33236 710 33401 33103 33526 32978 745 33205 33319 33151 33252 33635 32823 32821 257 814 33357 33455 33779 754 33455 33159 33715 664 33648 33178 32795 33328 32975 2150706079 2981766264 +256 32827 33601 33295 33122 33014 767 505 33773 33499 33782 816 387 32781 33378 33687 858 33209 721 32952 144 1010 33561 288 33525 580 35 33718 33326 720 661 33248 631 287 33670 155 33439 33000 33783 823 669 631 152 309 229 33195 33334 494 32847 540 1016 33645 823 55 33618 243 969 33540 141 33254 33451 895 885 33465 32996 32792 704 522 838 33330 31 33526 33024 363 33750 33345 1015 32802 266 33779 766 33734 471 33645 32863 456 33016 33658 336 839 299 401 173 33482 673 32931 33656 227 271 267 178 32977 32803 32873 621 299 917 33668 33619 32908 168 33772 610 33396 367 175 33544 33520 91 463 33751 33486 33497 725 269 33391 32890 33094 180 33534 32974 425 898 510 1011 775 376 33771 333 32781 32918 33277 436 33750 32895 167 33449 432 33411 641 33173 32988 32847 92 33745 33122 32851 33214 371 33279 851 953 33069 402 434 33429 213 646 542 310 33367 488 339 167 33175 4 33255 629 522 391 33459 33538 36 167 33439 198 32841 788 734 32808 33650 33317 453 232 979 33317 49 33647 33552 816 17 301 579 33189 33408 393 33115 432 33774 33389 33156 33245 462 33262 26 690 733 343 33345 203 95 33441 33206 32825 33371 319 33784 63 32882 33509 791 663 33082 51 33750 33356 85 33323 284 33373 981 33629 33466 33219 246 33778 33037 32933 810 30 33244 716 33133 33561 32947 33662 33266 33217 33704 33085 32776 33387 876 214 921 921 33768 202 33291 119 33100 730 552 33225 625 33238 530 33563 233 456 955 826 33298 33137 33170 33468 496 21 33678 868 227 842 33470 33317 988 295 33777 33627 33244 33019 831 654 660 33164 33309 758 33108 33092 32902 33756 33652 552 33431 32788 33160 359 33200 194 33336 659 821 33124 33454 33597 33201 33627 33749 388 472 689 33666 33466 33190 33281 562 33333 33293 33111 867 923 33172 517 788 46 33469 866 106 32859 33787 916 633 198 511 33154 393 33443 369 32799 32898 33453 140 33471 1005 33311 33035 573 33249 33622 32881 33232 33152 33414 33360 358 1014 210 33474 33534 905 637 32827 33105 32987 33034 376 467 418 688 338 473 552 809 125 867 33070 774 313 566 33502 32813 953 33116 33604 869 115 33775 33761 33297 518 33777 33008 32891 663 539 201 806 952 363 32870 707 611 33725 956 821 39 381 32777 650 789 32995 33160 33009 32835 32870 33538 325 451 637 925 704 648 33560 32820 99 3 322 33783 175 119 945 524 732 33769 33626 33350 33661 33569 32792 33160 32931 33288 485 33444 33663 33237 33115 719 33233 553 33544 32931 124 33690 990 661 33017 931 614 824 78 530 33773 109 33181 33604 910 465 33772 792 11 33338 864 33221 801 33266 33294 810 841 577 32780 66 33429 32908 449 33166 33372 804 677 33068 33286 707 610 628 6238220 845873884 +16 33178 72 33644 32777 519 252 33337 782 33640 32824 664 418 996 33186 828 33607 33020 32782 33022 33139 32815 33517 32957 33376 310 739 33725 33455 482 210 236 32880 2581556 2974067440 +256 586 317 182 732 33222 32813 33205 330 33435 96 91 32809 32908 322 35 276 755 33165 779 985 11 33317 33591 33404 33658 289 32887 33337 17 33063 33084 687 33502 436 474 896 261 366 33434 33165 33506 32774 33686 33670 286 931 33530 33157 608 910 33030 33649 33789 77 969 670 33227 33003 33587 33724 34 33136 159 901 1013 33237 33655 33225 576 295 713 33691 77 33246 33100 33061 33748 102 33659 861 700 1022 275 33524 33114 33647 798 33499 497 832 33560 266 798 33196 33063 467 19 390 118 33233 440 186 538 1008 32918 62 814 496 33165 32962 425 33188 249 256 32915 33420 595 525 54 32865 2 33064 193 33 33618 95 33299 33530 32838 453 33444 32935 33410 33226 517 32981 783 32991 584 33056 33023 33551 919 33278 33237 32893 33145 32989 32944 33172 307 733 33280 369 33193 32924 33472 33129 33113 33262 33438 461 33046 602 33784 33082 174 888 271 314 349 305 33350 692 33499 33417 490 33553 33759 585 898 109 33584 76 33487 980 33243 33479 32881 391 359 33372 29 110 231 1020 527 865 545 550 33774 33507 847 32933 33212 969 670 897 983 912 33576 827 32788 33545 686 33574 773 87 33630 33649 33131 32961 33318 33641 5 33710 58 33396 32797 189 33442 33207 33101 33042 631 563 33258 33147 32863 33052 622 33439 105 989 301 33243 33332 33518 33609 697 33164 33266 32840 456 33364 32857 176 33660 27 33358 33280 33107 411 33212 33721 631 675 32962 33040 327 33140 33226 33016 796 33072 32840 257 1018 711 32878 934 33575 33753 462 32881 32793 591 363 33556 32801 32787 33188 32827 433 80 737 33439 33188 33121 33524 110 119 177 33080 271 33421 33615 33402 960 32985 796 398 545 33618 296 862 36 92 782 11 153 498 32931 33598 33548 32963 78 33791 33254 45 652 33777 32774 33379 880 33588 33678 32839 894 33697 33472 33309 33366 33084 33515 33207 33490 762 33010 32971 864 33057 32895 83 33660 32975 33741 606 581 224 802 33416 43 32998 652 307 420 650 98 33418 33494 32798 402 896 130 32868 453 33641 33503 348 33075 32902 216 693 32872 32921 33780 33649 33495 33110 16 33505 425 31 33505 32906 560 33375 457 1010 141 33233 419 33360 32787 561 204 844 1002 91 569 804 33311 907 546 33710 742 391 417 484 32921 33227 32969 562 87 33633 32944 33214 33229 965 437 32852 32931 33044 32897 32777 32863 500 32947 607 33534 167 449 685 33741 111 409 446 33331 500 33392 611 33623 32864 33088 33454 954 144 853 33790 33686 147 223 33503 33397 251 32796 33523 32771 297 838 33378 32870 263 32968 33303 780 33377 927 451 104 617 33127 33317 33500 33711 32909 33524 455 450 786 33591 737 783 886 32870 156 1000 33260 33071 154 33316 33767 33700 33216 533 822 547 33235 33781 754 33731 2153884584 2982206288 +64 884 57 606 33690 33147 292 240 348 361 678 33474 295 728 428 382 33043 33108 32863 33413 177 450 439 873 544 68 327 32878 33450 118 349 33383 33599 318 33509 453 33004 336 732 560 33790 33472 440 33693 869 890 896 619 14 160 32884 33514 994 33734 33556 32991 365 32937 33006 33043 33487 491 664 33070 735 32901 816 757 387 32839 240 32935 751 33648 33716 773 236 930 33336 806 306 32895 888 13 459 32773 33258 796 32774 660 474 33246 33115 747 33086 33761 253 33137 369 32828 32951 32949 32876 33461 33401 32853 1005 33395 690 74 462 810 91 33380 618 33572 420 514 1015 33102 618 916 693 33651 470 465 32840 33724 978 2149131301 846375524 +16 32999 618 386 577 33254 33615 33627 33194 739 923 272 865 360 800 633 261 515 344 33318 33285 104 33088 33044 33084 634 426 33159 657 189 32783 978 33524 8326391 837897096 +16 782 33773 94 33751 46 32896 401 568 33095 33421 33037 33189 603 33529 33698 43 33588 291 32879 33276 33308 705 261 33598 818 659 88 33750 651 548 649 33322 5869687 2984659664 +256 33303 32886 33649 33780 460 917 32774 907 595 400 293 33515 348 32861 33236 898 457 119 33168 1001 449 32782 837 33315 46 33151 832 32969 283 189 33648 33265 609 249 32808 233 33303 33561 32925 670 32860 531 32898 32806 33469 460 33409 902 33396 604 33544 33113 33366 33206 33091 597 33398 923 960 33191 33452 33642 890 33085 883 33081 33784 612 33293 285 32789 33060 33033 33142 275 517 49 763 32819 33125 456 866 316 33044 33431 33544 202 33366 33212 32791 32955 33555 33386 392 33328 33769 33333 33641 33461 549 33074 33397 33653 33529 857 342 33744 640 33617 112 32903 33643 858 33645 33122 284 32872 720 508 502 33447 33425 33527 690 186 391 32963 289 47 614 33475 765 33375 26 699 33153 992 467 33409 33523 33455 840 432 341 638 33700 866 33598 207 33349 649 593 662 33 32899 576 33329 33371 409 109 32914 146 32816 978 33550 153 583 33102 33234 33777 33355 33465 452 32846 33054 214 33293 884 33088 33661 772 475 33779 150 483 33232 33195 32922 979 552 33097 32899 33759 379 33179 235 179 960 32930 33324 33446 33370 33689 33260 33007 322 616 547 354 32805 868 33210 808 663 487 33361 33352 41 896 113 750 33434 33496 604 33184 878 33351 550 962 1023 993 664 33241 33723 859 276 33084 931 33761 946 43 33412 33346 32863 33540 33151 32830 33140 164 536 777 752 250 661 33278 33299 446 851 32784 33784 270 839 704 752 47 33142 33632 32799 33760 32787 984 499 33068 723 33298 33013 32899 816 33350 33608 557 166 33696 937 774 564 90 33686 539 33498 745 417 906 33541 748 352 33044 33619 33708 33079 541 218 33415 32824 97 552 33443 33534 33492 33045 797 32789 50 33402 843 910 361 874 547 427 33076 32857 33690 615 931 545 805 845 33298 348 33062 33587 629 33138 349 198 369 841 702 535 220 475 33441 758 33482 400 173 33199 256 312 33214 898 33570 32857 33158 33556 267 33155 751 33099 763 32959 33004 33133 175 33671 32899 33249 531 33422 33445 32851 899 890 33252 33644 33639 146 33675 636 242 33000 32937 32942 258 33483 814 536 111 33691 33215 921 33608 578 33501 894 33206 69 874 32934 293 342 656 33006 682 297 745 852 489 486 1003 33115 1009 33785 715 289 32951 33269 138 393 32919 33614 61 33429 26 737 180 397 33738 196 33172 33761 33744 192 859 33292 820 33282 33448 33125 602 33651 32817 101 622 33240 33504 33412 583 28 913 433 306 33174 33245 33152 800 33692 909 99 33710 74 802 245 865 33750 32919 33676 603 32896 33153 522 33710 33378 312 396 33087 632 531 33512 33391 33538 32877 125 349 916 33013 565 33402 359 33550 33547 32782 744 32773 448 817 709 33238 33554 33251 33088 33694 747 32916 1001 33418 33086 421 33631 765 32828 5748269 852817924 +16 702 33421 33277 33696 33144 33089 32893 756 33073 33138 116 32990 596 356 729 341 32876 342 33551 804 549 33234 33608 33459 302 472 33454 237 32818 33533 33210 32833 2149641237 2986621456 +16 32840 33654 33751 688 33122 226 32886 126 46 33547 32842 429 508 367 182 32850 33327 32904 33518 33556 917 528 241 33348 32934 32849 33155 874 760 10 32979 33327 82266 828179376 +16 905 33326 913 33367 762 796 301 1015 30 33400 32979 32986 890 33783 630 82 33456 32797 33506 883 18 32797 33398 69 33154 33722 855 33331 33262 33095 817 33464 8313244 2978003808 +16 321 599 33073 699 33031 33319 643 33600 33258 780 593 33617 929 33174 33475 766 33663 41 267 97 282 153 33566 33646 33235 33494 33017 32897 941 33244 33604 637 2151757952 834510768 +64 33169 33689 781 33478 877 33175 32869 33340 33462 33579 605 800 32909 453 33470 32956 551 859 33104 256 263 33678 659 298 21 33292 32944 508 32791 33489 615 33454 789 211 455 33245 33509 989 676 443 33107 32991 33544 33340 32796 33054 622 33451 32810 32780 33578 32993 349 33325 33090 349 66 32967 359 824 698 255 33140 832 469 279 992 32986 152 277 91 33449 33774 116 401 601 33387 33050 33506 348 547 33000 33735 33747 182 478 33211 943 33547 33109 33519 922 852 955 33438 74 33192 26 32983 33082 462 33320 32904 32920 33071 33609 589 650 220 745 33730 33071 544 884 33694 33202 888 240 32869 916 654 873 772 275 33152 274 468 193 8061884 830105648 +256 33723 779 569 337 742 32886 33587 33622 934 33711 33084 33662 784 772 877 33675 33732 33538 32831 514 669 33778 32935 32908 804 32830 356 32989 33504 575 319 609 889 33515 962 33072 32779 33586 33389 976 229 33426 33325 293 23 262 814 46 33146 829 1010 33080 33602 33678 204 33556 33185 32924 680 33044 911 723 203 516 33605 310 284 33704 33280 33153 385 33356 818 48 33271 33510 32788 33230 251 339 33598 244 33230 32819 211 600 954 562 33621 32834 33024 919 654 110 150 33747 244 543 517 540 311 33241 494 33037 757 33163 706 33146 33345 265 521 32786 33477 426 33685 33457 203 452 33373 48 564 33428 32883 33470 33576 33666 167 244 33668 33463 33749 386 33707 33697 311 33026 33420 241 32944 534 33457 33725 99 277 727 700 33636 697 32817 33451 33640 33169 728 492 729 38 143 32904 674 33352 342 121 339 32948 33457 33788 667 33158 972 33538 33668 33531 949 32922 358 793 33653 902 32 782 33407 894 959 33659 33736 33576 903 33209 33372 33091 223 384 890 32785 735 892 859 380 33577 33156 594 464 37 32967 557 648 1023 32998 942 33549 507 424 32841 964 260 1018 33660 608 64 33614 33173 32926 33638 653 32906 33005 886 36 784 32982 562 306 117 46 32864 189 33155 33140 999 33518 33731 962 892 764 96 987 471 249 845 32892 995 33220 559 445 33535 219 570 33685 386 32892 37 883 33083 33620 33221 33491 960 33080 581 1019 33166 33206 33633 875 121 33232 33349 772 422 33593 33722 33005 210 32952 958 69 932 60 33592 33331 33051 192 33256 33453 33176 33489 529 33191 267 33132 33120 292 250 33137 1002 545 389 894 32793 33362 968 32901 33732 920 33181 651 33502 32906 33191 33779 33354 812 647 422 33608 33250 957 763 274 33642 32890 32945 32996 32919 33218 421 817 384 33150 33262 936 33270 531 474 544 733 32815 955 33334 537 441 32997 33536 32898 640 33412 490 33405 242 897 361 33130 165 548 32802 189 211 33618 32891 33371 33219 32882 388 322 33091 33475 33282 33483 150 748 310 23 32777 517 32850 893 33177 176 833 33556 838 650 33006 873 33701 33400 33137 33135 19 32803 32899 32998 598 33637 601 574 553 33131 33385 959 33022 21 582 497 33457 42 150 32928 697 33613 33471 29 388 259 629 138 32916 753 33354 32796 780 33269 32889 33066 32819 33224 406 874 841 32935 328 33652 33263 339 68 32903 989 480 32968 275 347 32799 33697 951 859 661 629 382 33562 532 85 659 318 33102 33733 32833 32836 32967 1023 401 33695 32929 33440 750 33776 499 33165 568 305 32853 457 106 218 242 33211 33309 87 33317 203 33361 507 33434 653 33605 521 989 33639 124 538 971 349 51 33383 33786 33589 841 33766 33205 337 33783 706 430 1524368 2975646640 +16 33576 33558 32996 455 47 737 33651 367 801 869 373 33579 481 428 32915 189 285 62 33678 750 481 913 684 907 32824 210 33778 230 423 33254 880 32935 2151549555 801682560 +64 32923 33492 683 33254 33786 33659 33018 33693 520 33518 33196 935 765 344 32881 33245 33447 33432 211 552 33598 33372 33251 607 943 33514 33194 33320 284 237 33734 969 304 156 475 132 618 33534 1009 745 33400 793 262 32884 190 108 33103 33369 33719 33482 33235 33459 972 33098 759 249 32897 33249 33358 33509 33502 1005 913 902 698 107 32940 33259 32921 686 33026 382 868 33056 33355 33737 934 33226 405 381 32930 32933 158 32914 33568 654 33141 412 852 409 33346 33382 757 17 33070 212 593 32778 33361 33370 33254 33086 33308 978 849 690 33429 1004 3 32838 473 33219 33210 267 227 33723 496 32780 33576 159 217 33394 455 184 985 33383 867 956 6229845 841882776 +16 560 32965 589 363 33716 33180 33346 861 628 32858 842 32897 250 33784 32833 797 625 33295 629 33470 33065 632 33545 33500 271 33460 33754 317 826 545 33686 108 4464713 2966569568 +16 32904 33591 912 33564 33246 379 103 33017 498 33192 33341 33324 225 458 33295 32788 909 886 33301 32994 33599 527 926 33278 733 33092 425 33292 32968 307 936 504 993278 2957022208 +256 213 32854 598 33443 33708 277 969 33351 33617 182 65 897 33668 32904 33567 33730 1012 32776 33163 33584 33627 685 940 32831 421 499 33222 33307 837 937 33221 32979 615 33495 32838 391 73 367 488 33439 950 158 33240 33469 967 815 442 473 33340 953 170 1003 33444 231 721 33679 32816 33147 32824 33394 33528 33701 72 869 33527 33024 640 33114 569 33750 32793 32770 250 32927 32803 135 451 207 33088 165 33053 924 420 33209 67 32979 182 32794 33095 33764 228 251 896 268 252 32935 33609 561 33353 219 627 621 32880 326 33344 33548 558 712 881 340 33554 419 73 33169 32927 548 33245 33403 74 155 32935 33764 33005 119 33264 935 503 457 285 969 537 646 682 24 912 853 33155 32944 32852 795 32888 405 33650 32784 82 712 33496 235 32858 92 33774 33001 33056 307 33485 687 33024 33405 380 999 33501 33279 475 305 33303 33366 33729 32886 664 33105 169 33263 466 752 415 33439 662 659 385 645 799 673 33649 33430 33538 33224 53 540 848 32948 574 69 171 941 30 289 32990 413 947 182 33131 767 33673 33020 204 32788 33331 315 33413 119 822 214 33159 436 178 33790 33355 33455 32942 526 33006 144 33015 7 33415 33019 959 509 88 33563 32954 33594 32769 33238 32971 716 703 33180 33317 507 331 32779 353 33521 652 33041 46 577 33316 33449 203 45 154 33482 139 33515 1004 33423 33378 131 389 436 33155 757 33044 32871 33216 700 286 333 99 33043 32776 421 33631 33384 32842 159 589 146 33193 873 7 475 296 33463 883 33105 898 402 508 33655 33410 33379 32787 32812 32951 33521 851 484 33083 685 230 351 32862 33472 33148 33274 842 637 33436 958 33378 692 32859 33131 33533 195 1010 595 33139 33207 478 33148 33533 33520 32862 33399 453 35 844 33569 32912 32802 33026 33010 35 995 532 32903 33290 196 417 33744 33774 33269 930 576 32810 531 944 33093 32991 33516 254 253 344 157 33363 885 131 33611 32835 549 33658 70 755 33725 32835 955 33180 33772 392 828 580 646 32791 33716 431 33120 745 33217 73 33686 36 33337 33392 752 33677 32 33501 33625 877 130 33063 691 33040 33581 649 33550 33091 397 32780 530 33739 53 681 33337 927 826 440 32889 33182 301 260 241 946 50 243 33781 21 33206 868 33418 413 33325 33522 651 164 33098 33205 33758 32949 931 161 33132 194 32915 55 97 33535 987 490 33561 33380 897 33029 8 405 33516 33357 736 33212 32891 871 33195 33277 33124 298 631 436 669 32910 944 33426 560 918 33559 132 168 227 790 33002 1010 33670 740 113 33012 33226 625 32902 33143 33093 33571 33551 33601 33554 734 33225 33601 33154 32967 282 33436 32784 914 32816 819 33398 12 615 200 33154 684 815 33220 381 33150 544 483 966 340 5575041 2995680768 +16 33303 33105 828 416 33601 33475 33121 777 639 737 33492 264 812 959 142 297 689 33263 32931 462 698 436 398 33457 33509 33484 33572 263 808 115 33413 161 1902414 2980264512 +256 32947 958 750 33054 304 33409 750 389 33511 32820 33115 33617 521 347 176 33383 33163 998 33009 33322 810 540 32975 986 849 33694 373 992 33548 469 33722 33134 28 588 33462 415 816 33562 33128 33574 33231 33410 852 311 123 32806 32850 33195 32774 643 330 33549 469 588 39 851 33426 33574 558 33674 33167 565 33704 576 33332 182 33348 17 536 540 33138 33094 888 33273 33297 554 969 900 148 657 926 751 33052 562 33079 33534 744 32884 18 33011 251 710 33716 737 998 481 528 764 33235 33586 33413 33608 33029 33535 178 322 578 889 135 971 21 33547 162 324 1015 33205 33513 33560 129 33112 472 32790 32862 32832 181 33534 787 32867 32794 32799 33007 988 33308 33791 510 234 551 429 759 1007 167 948 33313 33552 33224 33526 145 519 838 33275 33478 755 33010 32780 442 609 33604 632 965 150 24 33608 33409 32858 706 33431 570 33443 33399 817 407 242 32976 33104 500 1001 22 273 191 33413 538 33697 272 123 618 719 637 31 33378 33687 1000 33735 166 865 717 33340 33257 33126 32861 750 32983 33434 33360 656 588 799 33037 410 33785 432 33604 33449 33440 33593 453 33131 844 382 538 924 33755 33271 966 511 33160 804 32948 33520 234 669 33144 33377 32770 865 33419 33384 374 997 33000 33641 80 33142 171 641 33462 97 32891 341 33710 346 278 841 33074 767 635 813 947 738 955 33130 851 342 33209 33366 1012 6 894 26 861 32800 33677 33592 33276 33681 32955 279 145 33341 33209 474 175 32886 538 33043 33339 33053 1007 653 255 239 215 33283 33208 33073 676 33467 33339 33777 966 32820 774 32848 32916 33510 33702 32860 33353 33748 33269 883 33777 33088 33090 709 1003 33058 7 32804 33685 33619 32773 33760 54 309 33673 205 312 33737 475 627 33414 429 33682 829 50 33360 33296 33766 33563 845 968 961 33253 33481 33341 33458 33578 448 33570 488 32924 33187 33706 33186 294 33751 1012 33046 648 452 33673 37 930 33123 32909 857 33784 33274 33594 629 33253 406 33187 643 896 33000 33680 418 570 982 677 646 442 701 33655 32811 893 33590 33545 400 32820 33233 886 33529 666 32815 503 33290 33240 33540 330 32903 65 46 476 995 394 33698 32839 33163 583 538 33505 405 979 33726 289 335 542 232 33173 32997 32989 67 33767 627 33115 33677 33106 16 33645 729 677 191 232 33114 349 32975 209 33490 33227 33700 729 33033 33155 33252 202 197 922 824 33449 33043 302 33386 33488 337 33241 690 33386 33446 547 33134 340 33587 53 33447 922 928 291 33285 32913 1011 919 32871 56 220 33066 78 395 33488 467 36 205 753 790 33529 33040 33423 623 33541 32950 33745 33457 33237 129 32946 892 33124 33287 23 33676 255 627 33584 397 621 203 33209 643 33192 762 33385 3361876 822656192 +256 895 423 667 33630 33052 298 33435 664 740 691 33005 33564 306 33140 694 33079 473 33587 185 33261 33633 33475 33652 33318 299 33569 731 33274 4 33713 32871 775 915 942 33347 33026 33120 33127 32869 618 661 33173 33204 604 367 32797 145 32873 33608 517 33205 33488 33414 790 33179 47 666 967 267 33514 33526 117 33789 1022 33708 784 84 33179 128 309 929 348 33416 33659 33532 32770 33219 33539 802 32807 162 32769 33413 290 32864 33771 33405 514 33581 383 683 33281 481 421 33478 33383 32920 127 268 282 32891 992 776 33705 33027 385 89 140 32945 719 809 33063 33474 219 545 33331 32835 914 493 33353 33330 33189 33256 338 652 620 33101 222 360 365 33533 32948 33216 32847 33401 33706 896 33045 29 708 581 316 685 32900 982 806 556 334 32 30 610 33488 442 33573 33620 33449 33628 33614 567 332 33669 32916 33361 33081 33530 782 33666 520 539 186 33400 33707 488 721 33187 715 930 178 33391 982 33461 32893 33212 33332 647 219 32887 32769 5 473 644 33054 32904 33765 33419 32810 399 33325 33622 32794 340 424 32779 16 707 32954 33 32827 580 33278 1009 86 773 452 792 428 33655 243 333 1003 44 976 33454 33129 33219 513 590 33517 80 847 33175 944 761 14 773 33358 33626 808 32982 33243 33039 812 33763 32910 33456 682 647 192 108 813 33555 33151 33605 391 33248 614 433 884 912 33687 1019 727 33024 32879 369 32863 33184 33771 33712 32796 717 243 166 33379 33314 438 33495 33251 376 497 966 33588 908 33004 33497 425 33714 33101 591 33429 33772 30 530 195 233 33472 401 49 33310 32777 750 814 33690 33030 33371 44 33618 383 179 635 115 32876 543 572 32834 33517 33546 32955 33402 33025 33027 33399 290 33734 617 501 86 33601 33013 757 32833 706 957 33196 388 32969 33563 1018 33438 976 32819 33101 33663 33269 33059 908 36 544 32812 773 32794 791 223 32989 529 33446 6 33417 293 335 33745 32878 2 33010 32956 33079 925 33534 604 743 768 1013 890 33756 33361 33632 887 33277 33573 233 33607 33328 465 954 33639 537 202 33296 32879 249 33730 33346 33487 33672 219 289 32858 315 33585 46 281 33358 909 294 33491 385 33345 221 33375 785 33620 33774 781 169 472 33579 514 628 33242 32833 33665 33092 32772 33510 150 33722 295 108 231 32966 577 591 33116 282 332 654 897 748 33256 33317 33705 33184 33073 884 676 33573 481 33330 202 753 32914 806 403 33260 33478 33553 33555 33784 33447 33666 252 32775 33167 33140 33666 652 696 666 33530 156 33346 33752 33135 33054 416 683 543 486 343 324 580 607 782 33494 851 33157 33250 33451 33386 33649 33261 33658 8 796 112 976 33529 33196 33398 552 523 782 479 434 907 32838 289 948 33356 894 33774 32861 2154206196 856140788 +64 984 33145 32928 33358 318 568 32954 33071 802 51 74 32772 66 32774 332 33583 737 33703 229 33478 397 1005 827 414 677 33755 33691 33414 946 33264 161 547 33611 33266 612 282 32872 33431 33150 837 719 698 696 910 33440 507 33003 33249 626 513 127 32797 33626 33583 898 33270 33739 182 386 33443 33631 177 392 33179 321 33015 32972 497 470 659 33146 403 45 241 156 616 33459 829 228 748 33306 877 33141 471 33045 245 23 32963 33357 954 33517 33559 33760 200 79 32825 32830 33222 959 33160 757 522 33666 223 33367 32812 232 484 32994 33296 134 337 33623 33737 33594 33422 528 33426 806 563 76 200 33231 33743 1003 33358 33441 32811 2147692178 2991315412 +16 387 33640 33351 321 143 833 32939 329 32875 33216 33772 900 33545 33035 359 32867 33756 718 220 279 33571 444 240 33410 33610 33332 724 138 977 33653 209 685 2149818032 2984126720 +64 33293 894 992 265 407 33327 913 33659 32890 709 33368 33089 135 33094 33743 742 890 73 33107 743 33623 33134 246 217 1 33251 33391 413 801 33042 32912 33431 50 951 32806 516 542 986 33374 33303 33267 33574 387 33237 33381 879 910 616 33166 32862 587 312 377 33243 33694 33279 32772 32831 32962 33248 453 159 33675 33608 931 628 97 33644 33541 33277 475 32894 774 201 33342 33510 33644 33026 33202 238 33267 32947 33065 390 33318 33020 33497 297 743 453 33788 33367 859 268 49 383 96 31 33768 611 228 32938 69 110 33365 33483 243 32871 623 33099 30 33188 32830 33713 32849 786 249 33221 575 623 9 253 32926 32831 32890 32902 1019 32876 2717746 836585832 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 897 33397 664 33426 448 33352 419 27 37 389 32799 380 452 33007 33600 32776 5215432 5215432 +256 33653 33165 33622 493 33240 545 805 32845 900 1006 33124 483 33768 80 287 32823 33770 32915 33006 1002 815 33199 33631 33500 32812 635 921 33426 132 33524 33041 33364 32772 915 714 66 942 33234 74 33724 848 33630 33141 405 32837 997 32978 33670 33658 33779 32835 956 32991 33788 21 441 33301 588 32817 32847 81 33421 33017 33639 33429 32925 817 990 372 33055 33611 993 185 33198 13 33773 660 33272 32807 32860 53 33448 33566 476 33752 33678 320 33273 33164 33725 33107 615 33074 33015 33127 33477 32771 33112 33366 130 428 443 33267 872 481 33399 33748 33157 32776 33642 260 245 33076 726 33354 33010 33326 742 322 693 895 33627 893 33422 33062 301 33761 33550 671 545 279 526 552 33003 33307 872 33601 33203 761 33366 32812 607 227 272 33020 33641 32899 32959 570 891 658 32977 33123 822 32905 33387 656 161 33236 607 33366 32929 33583 422 753 33288 685 523 607 283 561 33157 470 33288 33150 400 336 32943 77 33526 775 33101 337 32943 32993 32829 614 33055 182 285 33718 373 33090 1011 589 135 151 33652 32853 32888 360 33473 33465 537 32884 626 32830 123 906 685 33732 32953 33786 33327 33293 814 493 33359 33520 494 591 33205 33182 32832 704 797 33162 192 897 242 21 1018 33076 32995 134 947 775 33567 33247 334 33538 33334 12 713 858 33033 32896 33448 33040 33614 33100 734 253 649 845 801 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 813454 2990608384 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33114 32771 988 33436 32830 977 33641 33017 33670 822 963 138 33433 828 32772 857 490 32927 736 378 172 33466 44 550 788 33522 33094 855 460 33510 734 378 33174 83 32867 207 32963 33167 33147 32817 835 777 32909 661 278 535 365 33619 878 33746 590 32808 522 739 33439 38 515 32932 33308 33709 391 130 75 32977 4867437 4867437 +16 32811 478 33293 157 33061 33449 491 33480 33703 562 331 768 32931 543 731 33373 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 5121577 802160640 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 357 33209 33692 33017 377 218 79 32780 828 995 33599 329 727 33514 33180 33637 838 33428 941 188 33466 993 697 787 33244 32924 33746 33640 44 225 33628 33648 457 57 33543 252 282 450 33441 751 97 33427 33495 33380 32954 33434 362 781 47 33290 764 133 996 33669 33348 32803 53 32888 33489 33582 33594 625 33695 996 3269004 3269004 +256 33226 33601 33238 32857 33215 770 820 308 81 991 505 33149 388 33153 146 32993 32970 32869 934 33660 32840 641 33721 10 33191 565 537 289 791 118 635 474 33431 32798 18 32878 32850 33672 33473 113 33279 263 723 767 32846 33303 32977 33429 33373 818 264 686 355 33591 562 7 733 33618 33650 33063 674 33374 33401 33553 33781 956 793 65 39 33617 377 33636 33285 221 33242 313 33416 244 33691 303 320 900 32821 479 32957 165 94 975 33238 645 820 32936 617 43 530 33517 33312 33530 32826 33711 33562 637 940 32976 63 33473 32827 33773 595 950 952 32951 205 33216 32972 405 33194 724 667 644 33057 445 33500 33744 578 637 32833 33766 956 32911 651 33730 828 493 177 33178 33731 302 33153 110 33233 582 448 33364 32919 563 920 33776 33764 33685 33702 33209 33420 33681 33229 33728 285 326 33617 33211 33150 222 294 33256 954 33025 32873 969 33339 33500 779 33499 107 628 32810 33622 407 33518 33403 33778 241 33613 237 33009 722 33343 563 339 33762 33307 421 163 33744 494 698 33603 466 1011 409 931 1018 998 268 426 33487 772 33636 33028 783 552 32943 33198 108 33106 33424 896 33021 342 33259 212 769 579 33469 111 752 994 33426 33354 214 291 340 33435 32879 33536 87 33444 108 33133 33089 110 33503 32967 33654 33117 271 996 923 296 32837 33323 32891 33062 650 32999 799 33714 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 6191239 2996934656 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33643 32905 33425 111 316 766 87 33387 33471 33387 32952 491 641 32907 33136 713 579 33446 33576 403 275 33181 833 851 1014 923 894 33631 33589 173 279 33203 252 33713 33732 33786 33049 33116 33625 33557 1023 703 33405 739 38 658 32941 973 175 32948 33033 32908 33284 172 832 300 746 33301 33500 994 33727 32835 33785 33745 2131627 2131627 +64 32 182 1 118 544 966 32893 33053 904 29 336 33567 33342 32779 33715 33620 32827 33449 33682 33737 33420 690 817 32952 653 33758 33755 122 32784 406 985 187 33006 32892 32844 53 582 33515 33068 33445 520 33273 695 210 33655 496 292 188 32860 33509 103 614 591 780 72 1019 32968 32818 448 664 561 330 368 33027 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 284759 835330048 +256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 779 33529 445 33719 849 32955 299 33269 33773 33258 33020 32953 614 33658 835 694 821 33706 815 254 751 32826 712 513 33054 32900 383 33022 88 686 539 33402 627 178 32935 522 33138 33155 140 544 123 971 33069 1002 839 33731 246 33133 748 954 346 33320 599 590 276 969 33173 33713 652 772 291 32891 509 301 261 32991 327 769 510 32903 549 33170 570 481 32792 33012 33295 336 33541 666 33039 33338 33517 1011 871 313 368 832 472 32798 32824 290 520 484 32804 356 33588 33027 33264 438 33573 33540 807 155 3 94 679 32918 33213 32826 149 33133 33748 33171 121 33534 901 33088 32947 443 33564 33240 44 356 33428 169 33140 33748 33564 762 812 33438 33205 666 204 33270 636 126 283 175 33219 32947 32902 33370 33018 749 222 166 575 295 146 997 33729 33403 414 33206 33119 33228 33499 33727 493 33229 33519 334 384 313 33175 33601 33504 33614 781 33496 33697 33237 33589 32802 33029 33394 596 33772 33004 712 865 616 861 971 32847 466 354 536 33394 19 33435 33615 971 33487 32776 33006 277 473 980 33545 32779 33266 400 32941 186 33298 32880 139 910 463 700 33762 676 236 33777 763 33213 33095 33498 33626 33489 196 685 731 33012 33287 886 32990 33671 33389 775 50 33390 33486 33564 821 908 135 440 32887 32817 33024 33410 32951 757 794 104 32919 33433 560 33487 628 33376 995 5960116 5960116 +16 246 17 33752 714 181 33316 33361 33406 20 842 33473 2 33580 871 529 289 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 6372538 2970501120 +256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 32863 996 202 33107 997 33510 231 33248 33225 866 33706 33022 601 33596 33529 32873 779 32899 33220 32907 689 343 757 33744 33244 521 32969 32888 32839 33227 33097 33400 33302 202 559 33302 33687 33033 32911 33083 33790 759 32807 33060 695 33352 32799 395 965 568 703 66 33435 364 150 725 33725 135 32788 1011 457 227 1016 217 33131 881 33526 191 33674 33043 33564 360 32854 33397 33474 848 895 380 399 33255 32848 524 32925 33231 961 33166 572 33300 649 958 697 33380 33330 458 33633 735 33392 32774 33590 33377 914 33685 32880 432 40 967 33061 33175 33485 400 51 988 354 32849 33754 523 109 33741 32883 32830 33563 342 33337 294 123 33274 33363 1009 708 261 564 719 287 424 33137 33083 33603 33125 32795 72 32832 381 32910 359 33787 906 927 33597 225 32800 505 33416 32928 33115 803 542 33094 32857 32979 923 33184 86 33770 33681 32907 661 687 33068 370 170 32897 33462 33597 33648 33425 32947 639 963 32 32907 867 691 33775 402 33612 32971 32834 33377 33616 33411 33395 33352 901 32957 251 32785 644 32905 33635 447 292 510 33061 33568 33328 418 33458 33629 832 32983 399 33050 839 558 33000 818 33092 6 970 21 962 137 33207 309 390 478 32887 33237 33382 33333 334 187 259 849 150 315 33022 697 33366 898 601 848 790 20 33042 33134 940 33343 33096 33759 137 33695 201 876 33430 3583273 3583273 +64 33761 1016 33525 56 33189 33481 33568 85 33022 33161 122 605 5 87 33454 650 722 407 32918 33208 33736 43 856 32900 33260 544 32920 32966 955 855 32827 32847 917 32925 32911 369 33379 32846 751 33411 546 33177 886 625 352 152 33607 33341 275 96 32998 33251 33583 32929 33587 33756 874 33285 33580 33390 33111 903 487 702 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 2684612 2985844736 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33446 930 313 33548 309 489 850 2 327 406 33355 33253 33591 33771 186 33557 1413546 1413546 +64 847 92 33149 250 32924 668 220 32 217 334 33094 33750 248 33334 32853 32838 842 570 33673 33752 371 662 33701 743 555 25 32936 33148 33384 376 361 33459 420 33367 33571 33724 673 33641 33764 33416 193 594 377 33225 32972 33728 32978 33095 901 33322 245 112 32832 804 569 33555 32918 1011 617 33429 33684 32968 33616 612 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 3065015 2993991680 +256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 361 33583 33602 613 866 653 197 162 32906 32804 766 33165 301 209 652 428 99 32989 842 436 361 33013 32889 33319 729 371 33676 88 72 33125 543 871 495 125 32804 32950 18 32966 839 472 33382 33678 522 417 428 33353 91 33463 603 828 91 32956 33544 696 711 33402 33681 906 33736 432 33129 367 858 733 753 33045 335 652 32790 33781 32990 675 33337 450 850 155 978 32914 710 33307 101 33559 920 190 327 32973 33392 794 603 33503 824 129 110 33325 987 396 33257 32792 218 33317 3 33624 32869 33073 717 886 535 33590 32833 33563 312 246 33425 33325 951 946 33402 668 674 244 791 33120 33019 634 32858 32889 33413 862 817 115 797 33651 33717 33173 32942 280 777 33019 32871 550 33106 32808 656 33287 473 32797 738 573 33249 590 33364 425 976 32962 33746 33158 33411 33353 748 453 33084 33332 287 33311 33464 33505 178 184 724 39 749 33771 191 341 33471 33429 33706 434 231 33053 33452 813 33241 999 33519 388 284 364 32979 783 33066 826 125 373 116 33026 258 33413 33224 33412 23 33732 33033 32966 33791 33054 986 286 338 498 33049 642 33649 33203 33188 33084 33064 445 830 782 32947 376 783 33653 697 685 33323 847 559 33598 33385 992 989 32972 33449 33119 33579 743 776 356 19 236 32887 125 431 563 415 33560 33399 33588 987 33152 406 33087 33142 33406 5479146 5479146 +16 33427 32967 33574 33629 33297 172 680 783 563 945 572 253 32848 824 32812 910 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 6500714 840810496 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32943 793 661 33024 270 675 243 423 714 33617 33583 32830 259 925 208 1004 387 28 566 33714 33718 243 737 74 173 33520 220 676 33609 33446 775 888 33392 33068 490 33164 185 490 32989 33650 996 595 910 33646 12 33403 330 1010 129 107 981 33372 33426 400 33129 32814 861 32923 957 668 32976 894 334 33313 3967636 3967636 +64 918 33454 33303 33757 32986 123 741 642 33128 695 33773 32771 375 33181 32792 32905 33733 931 33039 648 630 58 352 33407 452 593 32907 33744 32972 33100 32849 33560 33055 317 33279 926 419 260 32904 995 503 33092 339 32772 33386 33615 33626 33508 646 4 382 33294 33326 602 355 883 32827 590 314 33274 559 33107 329 33626 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 318801 2964553728 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33720 584 811 620 707 159 12 287 354 975 32873 87 747 33290 33511 516 1563812 1563812 +64 689 33366 107 438 32778 688 10 177 33460 33112 933 33660 33689 559 33291 432 32844 93 739 33265 33218 547 982 33424 32870 33334 33448 776 33071 427 32957 33790 628 33729 33310 33502 32906 926 640 33532 782 33273 33535 285 178 33573 33041 127 33418 297 419 905 43 443 676 32905 358 730 33512 33520 646 719 33053 239 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 4408449 795869184 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 559 799 32846 631 413 32893 114 423 33221 879 33511 460 245 714 33204 333 8014945 8014945 +256 13 33416 33282 32982 33449 535 826 504 32837 33626 32896 292 332 33052 33398 33167 33561 33136 32814 364 887 32863 123 960 32973 78 33590 121 33444 347 870 33558 401 558 400 33441 363 369 553 33015 33052 899 421 7 33407 33789 395 33052 33327 466 304 541 33531 33265 431 811 33777 33670 244 33594 33100 337 33117 730 33435 33550 724 742 667 15 33600 940 33215 33310 59 282 145 159 427 32946 33057 33656 654 60 512 267 33727 32848 963 32996 274 182 33404 197 33220 32797 799 700 32874 292 33660 100 249 33418 726 33256 801 32956 33251 902 206 32898 33005 84 827 33380 32873 29 33502 33422 354 958 33243 33412 959 32809 32844 32973 33079 33425 33109 33624 33599 33545 33507 33484 111 32840 32861 744 32933 113 1015 33315 33591 33450 1016 32789 33332 33015 484 889 33001 32772 33265 353 33297 33202 33300 33582 247 916 645 33631 448 161 32798 33538 33020 866 318 808 343 33663 585 33644 395 33325 125 33508 33717 721 33002 963 32932 33270 237 937 33329 430 33766 814 913 265 370 32877 33298 97 515 248 434 33018 33717 225 517 212 659 838 701 32932 787 33212 128 33199 33760 727 543 33216 810 618 33086 810 32835 587 33631 308 33644 33323 32877 749 744 33237 701 412 33770 386 33633 394 33617 32773 765 214 912 33235 33330 33674 33479 32905 899 32886 33321 33126 397 754 812 33582 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 4039739 2979880960 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33224 107 33684 750 32797 33748 787 459 33371 32853 282 279 95 33747 33297 642 442 33465 32838 709 454 445 605 544 33635 318 33172 33782 33322 33487 33519 411 33413 691 169 746 33651 33639 754 32870 33606 40 548 10 1021 280 151 33246 879 860 33669 33554 934 33069 33339 33192 33051 565 981 33536 33528 317 33709 33392 3007696 3007696 +16 33706 33585 32971 602 33661 33170 290 808 33202 206 145 213 80 33666 669 33705 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 654739 2988232704 +256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33361 33007 250 33017 33288 844 32935 604 35 683 33250 33284 33649 525 926 32930 32799 84 33480 694 167 782 33005 33494 33033 32851 33232 32845 85 568 44 33499 788 748 33336 67 645 486 33555 33536 227 33386 1008 346 908 943 623 33787 33491 33374 33246 32930 513 511 764 32987 185 84 102 33067 788 33037 68 33175 1012 586 253 32824 850 33368 389 230 574 785 220 825 33103 1020 507 388 258 484 29 26 33613 402 33010 32790 172 33556 679 671 181 968 333 994 169 32951 425 355 670 783 665 33046 589 33226 757 727 33733 32907 33694 177 33718 33512 652 153 794 33697 365 950 450 33552 33182 176 159 745 32947 33189 33208 59 155 183 349 33654 661 691 33682 426 318 325 172 418 33223 863 866 33694 382 33162 675 33037 33145 944 636 369 294 33266 32864 32829 844 312 1020 421 33214 33399 916 33493 413 911 33731 535 32799 1010 32903 286 33031 44 32903 33207 396 33082 231 750 640 822 435 72 434 3 33184 726 983 33045 33736 397 32982 596 987 32962 863 32944 33569 33647 33748 1023 33495 301 555 100 1017 589 169 32926 33387 149 896 33489 33582 139 33055 34 33094 33020 608 396 902 225 32871 33261 33461 32861 33361 504 998 862 32820 33179 419 33698 33077 370 33783 499 33631 405 33564 332 1016 33323 887 33397 33041 655 33296 32840 559 841 4242796 4242796 +16 795 219 33005 248 676 33668 157 756 193 33456 32958 719 32814 33249 33233 33578 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1507200 2941779968 +64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33218 32922 33751 32990 63 121 473 33726 33646 33091 33286 829 33233 241 402 33218 33788 33388 678 661 33612 547 352 128 574 189 81 828 470 33149 690 33549 33518 265 59 372 591 174 238 721 33381 531 33031 33545 33627 13 531 817 277 33332 33442 458 196 640 32902 33628 846 778 32799 765 32983 33198 273 33464 2227995 2227995 +16 33448 761 33101 33231 434 33520 33115 32834 33510 33355 33501 870 592 901 578 304 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 6622723 2961408000 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 540 417 874 33721 388 33208 406 33731 33719 33135 33543 32900 33660 33359 281 32964 1506616 1506616 +256 33078 32910 92 33578 696 737 33183 189 33235 33320 725 159 33282 944 33186 222 33149 33342 33764 33617 33257 32868 33296 33256 875 33048 32959 585 33290 33344 1002 116 445 33431 584 996 200 32807 768 324 23 32939 32949 264 33639 19 33126 888 33457 262 892 728 33616 33419 32917 706 33560 144 462 33007 32867 33042 51 33304 412 369 555 32884 500 650 614 1005 33138 33183 830 33219 33246 33373 33369 360 33070 590 808 33184 33655 33317 662 33601 33409 33210 691 961 866 21 33158 804 712 33241 33710 256 486 335 910 306 33727 219 640 33061 342 33335 840 33565 32974 33760 33557 33583 33165 754 149 392 33323 33394 394 201 33493 967 949 617 33432 33520 33560 971 232 55 33628 33151 577 175 32895 33540 745 33142 33656 33641 33784 493 33723 33510 694 518 823 741 202 32884 200 841 367 32784 33753 33559 33391 301 142 33289 214 963 33540 651 638 33476 946 33356 574 32909 486 99 512 534 33397 926 33321 33257 33777 871 32779 33355 32794 33700 33624 414 33006 76 152 33759 33132 32855 32877 33640 459 924 325 968 33623 32919 33396 32921 33529 277 33093 33627 33146 32899 367 697 729 33518 32945 32844 235 33349 32833 325 250 33287 33759 948 153 69 33109 451 33723 33147 33471 33321 470 33028 33614 33635 32986 33448 33453 33685 33607 1019 32918 57 959 632 33429 33062 560 911 33726 511 33517 769 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 5006247 3004971008 +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32879 33606 481 32933 33745 1000 33398 339 205 378 33120 401 597 33639 352 33307 2657803 2657803 +256 33705 33024 836 33460 402 33146 33721 33218 267 33178 32827 373 16 33601 28 33019 654 34 33288 32965 33430 32943 218 186 23 33486 33096 33094 554 32906 686 32972 33226 33299 997 785 472 332 996 33538 1014 832 797 32932 529 33460 33713 403 33501 33370 961 850 33703 525 849 392 40 33217 32894 370 33642 466 33315 33729 761 910 33004 32954 33003 875 33204 79 32808 33263 32849 519 1003 33477 32935 782 33526 596 33370 204 33068 952 409 367 33363 753 33119 250 33393 33416 32934 607 33619 206 32893 33566 33628 223 14 32985 899 32889 33780 33298 33320 651 619 159 32847 186 33314 33455 250 1003 32779 32949 599 33673 295 33278 33191 33194 33261 341 283 33101 38 104 217 985 765 780 360 33666 33661 33091 32827 1011 33087 927 33139 773 33526 762 33541 33771 33366 247 33125 32902 832 450 578 164 13 837 624 526 33390 33744 33178 433 452 972 153 33026 33630 455 3 33467 33000 303 710 774 33509 281 541 524 500 98 828 33130 573 33771 33266 634 976 421 32968 691 32826 128 170 53 33408 95 451 33767 33516 32769 32781 672 19 717 33776 516 898 33770 217 279 33666 534 33623 474 33582 634 33334 33174 26 32871 291 32942 644 33304 856 33393 638 557 352 163 442 33502 32798 774 33142 90 250 864 1004 33591 695 445 831 32953 33610 33499 759 564 32825 33120 776 32836 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 4636500 855769088 +64 33115 33553 64227 32842 33186 529 218 32905 861 33242 64323 30378 96 33677 841 63495 95 33354 230 33199 32875 374 63207 533 520 33273 965 33717 886 730 33290 722 32914 29899 32949 595 33381 32953 916 33755 33752 328 33382 63406 680 827 506 64124 870 612 459 63416 743 1005 538 30631 33678 792 31259 33227 79 33004 33125 64276 24297 41579 63683 23807 60999 45870 36704 57784 18479 1077 63503 63744 53308 59543 40827 31128 1625 63747 14091 38613 546 47073 31052 43349 11121 48905 46157 23937 8003 58774 3815 20414 54284 30115 39061 22266 21808 35836 19438 50805 45239 45562 13750 62596 55027 15183 14265 30544 23810 49378 9343 63181 47566 52769 54292 30667 28598 753 30907 3515 56837 38614 44498 64183 0 1338632305 +16 33006 33472 33643 33017 14 33162 32945 47 33406 33096 32870 32791 159 62589 624 687 58764 15755 61036 44035 24379 46395 21799 19837 41409 43205 24770 52015 10487 63559 33080 19743 0 1310299480 +64 62739 774 984 33033 63904 598 32874 993 129 31534 33667 64155 33707 30263 678 62523 485 1010 62617 33276 270 31036 30812 33478 282 793 32902 21 30427 30742 33552 32998 33256 64013 33417 535 31210 33447 31294 945 32816 1012 453 389 373 393 33252 112 33136 27 32815 31200 33678 706 64346 62599 33191 230 32962 33646 185 33107 62549 966 30074 23895 17932 11598 30046 55144 21891 63693 58705 63144 30911 30269 10859 31487 25415 31043 1648 44548 64385 25247 8203 64306 63270 44825 2248 47996 1571 37462 30196 29744 13103 51864 35693 29968 44697 39768 63147 18320 30926 36537 59011 34762 54347 42598 38492 13261 9244 19150 52887 8639 50987 31690 19110 3133 62809 63944 9576 35022 5501 9208 44122 28829 31202 47659 0 3460769128 +8 33532 64489 32865 32775 32950 32820 602 132 32984 30013 54943 47633 48186 42330 20503 7387 0 3466968596 +64 33751 63392 63260 32825 775 64249 33736 33409 990 32957 30677 64378 62665 484 720 33433 33504 33346 33045 33043 33428 30396 33179 33244 33049 33505 64469 1002 33177 33170 33527 32984 1016 230 655 476 33122 32841 463 32905 32891 62715 33740 33255 32994 33682 63518 131 33198 33007 183 30127 454 192 32905 106 560 486 421 140 63583 31102 910 33215 61963 29745 62735 12199 40660 62799 2464 26500 48556 35507 31482 63430 29876 49773 61320 7642 26380 28871 44628 8441 51411 64068 55064 9225 40535 54738 64219 21007 60744 30805 23248 49125 19559 47594 12388 27455 50674 63389 36634 41950 10900 63969 28149 47703 39265 44276 31324 19083 25972 18261 8575 30352 44721 38110 8268 21349 13076 18008 15001 62174 63763 63970 34602 40614 0 1337263216 +8 820 581 280 321 32943 31670 185 63953 16830 34386 45428 49450 53163 63442 16080 63736 0 3433043712 +16 32893 106 31556 33618 688 33676 781 492 603 33291 80 300 977 63732 33097 33557 4134 51025 62553 21648 29939 37903 39271 34682 11562 3375 48537 15217 25728 62473 18301 47507 0 3451494656 +16 33565 64010 647 936 30191 502 33713 32914 922 33115 62857 31647 33399 33376 194 62693 58447 29989 43861 10619 30823 19820 57518 31453 24956 7620 31116 63120 34305 8388 23783 29873 0 3477227935 +8 62646 33615 33322 64161 30856 1002 33587 32892 63594 15517 48256 62502 63528 48394 19726 56168 0 1302989856 +16 33006 62920 33038 33130 64144 783 33664 33662 33697 33402 33057 983 182 930 63828 725 53373 64337 24308 24277 30818 12295 16960 38120 41544 533 63141 30621 18027 63429 31008 2625 0 3473649136 +64 32835 32792 33176 243 982 33003 432 33668 29799 62696 154 33007 32970 33339 32816 793 29779 33458 32940 63129 33069 31677 30177 823 63037 30751 33319 30453 526 400 32894 1012 937 377 33229 32788 32809 33025 399 32958 63986 143 33206 33195 430 33492 33665 62637 278 84 32897 29915 33272 166 14 33120 33369 30349 33029 31709 175 30458 135 1001 45041 16982 40723 7993 21762 57679 53113 36348 64000 63055 29541 61984 39446 516 55723 34209 31508 16715 56017 62703 105 62509 30753 61600 31733 63678 29204 63714 23783 62372 5369 56468 26475 50981 58294 10244 57377 29932 61856 7587 63658 10241 58364 46720 58879 38530 39625 63826 6515 51764 51621 31007 55012 28183 4444 34293 59038 63183 25227 63818 42422 62669 29312 21783 0 3479150966 +64 33068 130 63107 30621 849 348 33349 33041 152 37 33191 33078 30201 33735 182 32997 33295 64024 30295 292 64464 720 33165 33595 63139 262 29923 32937 33482 783 989 932 33786 757 128 984 30682 1018 33780 63133 33638 88 63047 30767 781 864 33788 62466 33441 294 32840 33690 64451 62880 33156 649 961 33500 397 32885 62696 160 639 682 36396 57764 63832 64325 4005 47668 54008 42621 18605 16131 62491 6780 30695 31504 59735 4490 1940 64012 30006 38033 64256 58828 19261 25906 30204 49722 64346 47405 16044 21844 37584 40628 44369 5786 46562 22647 63584 50892 42810 30796 48038 31660 63002 30841 26447 63200 52736 63034 62867 5466 5426 14274 30869 62977 46757 39884 42777 37257 40129 5785 30301 4668 59388 19867 0 1327928336 +8 811 172 319 33285 365 33499 29698 30574 28508 26501 27065 51796 9762 37531 64286 64471 0 3475868476 +8 33658 406 288 30008 916 33204 33740 64000 40237 62214 3913 29845 22305 10321 17123 64293 0 1329815960 +16 33420 561 33187 33639 63319 32857 547 665 627 33658 779 202 207 33755 705 743 1195 45355 42222 51530 63584 42313 63114 29065 1342 31453 24763 39081 63635 53234 34786 51153 0 1317040768 +16 317 62949 30272 972 30089 749 30387 772 609 33144 33295 954 462 33072 33782 33758 35691 63475 30951 52612 31334 53406 63867 34538 28019 599 60941 38543 16202 53635 31650 23523 0 1322456082 +8 63570 64170 30199 31674 33331 759 63098 529 64289 64108 63567 63226 50281 59126 63632 39104 0 1329743022 +16 952 32802 30194 33733 33710 33572 32928 883 62656 33088 30207 106 33144 33124 33630 875 24006 60814 63442 51032 44239 60266 27446 61541 29933 13412 30447 36796 10624 27287 40819 16770 0 3454175640 +16 33137 614 64268 64290 33228 566 400 62619 62524 137 905 33779 32868 322 918 30742 3197 12530 63632 30598 16040 28402 45566 63418 63756 40642 63994 14352 35485 34652 12112 30682 0 1327744030 +64 63240 33132 33125 542 33043 62668 389 30554 33626 33095 29917 613 31245 42 32885 253 33029 33285 668 867 33361 51 32789 927 62543 32803 268 32816 33260 33043 32877 33113 779 63052 33705 299 32946 30465 33639 30928 32849 32949 962 399 33557 59 63772 33413 32976 329 283 33779 29894 32852 328 32786 30032 64395 33671 381 682 33260 987 135 30217 43250 37537 58068 57958 62574 60156 31224 62264 62988 31697 42945 63331 15483 11252 38267 59828 37880 20086 30198 59826 14883 57036 35367 31442 2070 17186 35945 35306 44035 44345 53900 55864 30301 37119 33788 48883 64145 56221 31288 50811 1598 34051 47914 36728 64365 30950 62113 63744 59958 20061 60009 30891 50731 53384 29104 64006 63131 48604 49127 42911 43900 19697 52990 0 3457626464 +64 992 32912 33746 981 30474 680 32992 20 33654 63320 309 854 33589 32769 662 32887 32954 32973 737 32775 289 33682 33172 1016 30966 211 31461 33602 30023 33276 33248 62942 312 32833 95 711 63350 33559 33114 64054 62712 344 486 30997 30845 319 893 33614 222 877 33555 33148 33589 63198 63326 576 340 1012 519 33592 33219 31013 32906 33124 20500 61622 35981 34874 63596 16939 38016 2789 17726 64117 47713 39758 23693 11284 60416 24010 26870 23865 19769 49200 50974 24649 52006 33803 63944 34545 63820 47399 63967 63974 38692 63105 53246 12010 51861 14377 63882 14593 695 31411 64342 39737 28590 62955 30050 34578 17217 18874 53658 7478 28369 1317 61076 63177 31528 24977 13488 34229 20640 33040 60251 30310 40119 30855 0 3481657234 +8 32870 64473 63861 31597 33748 819 268 934 19134 63579 30941 63073 3115 16212 61715 27197 0 3464517668 +16 32954 33124 33373 576 33153 29863 33346 869 31632 33305 29772 63825 33578 32769 33430 30335 19601 53979 28649 43361 29102 63193 63222 51455 31159 20922 64458 63149 49432 50168 62907 63214 0 1321736018 +16 758 939 32850 33121 86 29773 33015 33129 64354 32897 33052 356 33678 110 31114 32885 62302 8944 37841 24743 46228 62692 54456 43412 30325 16504 42345 39555 30240 15677 64120 43471 0 3481393524 +64 63515 32865 64146 32890 33750 30737 893 463 950 407 33732 33697 194 33579 33333 425 224 927 33552 33214 30934 591 33449 401 195 937 230 860 63736 49 32795 32984 32843 33530 30120 643 30602 62690 939 33239 426 33112 32847 122 31517 469 31028 1015 144 29977 33179 33569 33581 33020 31112 33489 31735 33345 30447 885 31104 267 32899 62776 63701 33341 31368 50688 48207 63239 45056 52005 41956 51108 40520 33208 7933 34530 22521 41231 58727 48382 55996 23609 62716 55850 25940 14624 32848 45162 13650 25114 30743 55628 5792 64465 25532 8358 31381 62010 64046 31558 3776 63595 35968 54526 56375 14753 62862 30565 64118 34029 20564 63964 17521 57476 20078 24700 30336 37804 64318 34407 62750 62757 30956 63500 46372 31128 0 3494155595 +16 32852 945 33225 559 32976 32985 412 63309 30152 419 599 33169 563 33481 287 62613 51220 36847 20517 17872 16904 47846 17169 29700 29901 3503 26360 7391 10840 35531 48434 31426 0 3464361856 +16 666 334 33016 856 30816 33144 42 33264 783 63651 33472 961 31118 11 29925 788 13610 10884 33439 2736 62998 47743 62149 29833 38704 31419 14452 33650 29862 56359 63678 30427 0 3475823752 +8 599 332 867 996 29762 64116 31446 62651 760 50140 9096 16827 63637 30653 63708 31249 0 3483669577 +8 34 225 33560 64510 62931 64287 30885 33029 41384 63720 60353 62566 29931 29896 63928 40436 0 3473190169 +16 8 843 790 30344 32805 850 460 32786 33347 33077 62659 62649 32795 33725 396 33539 61133 14046 60755 63389 22902 46735 62764 30664 22985 27023 31005 31610 21506 8023 52077 62095 0 3475573226 +8 6 63163 33353 30310 33540 30800 33222 33453 50563 64218 31469 63389 18491 63762 35621 9205 0 3459238472 +8 62647 619 33614 249 62846 284 33163 753 30435 23479 11367 22290 64154 40560 26878 11076 0 1310731596 +1024 63344 30223 31353 30509 62857 63127 31622 64136 62727 31320 64280 30736 64339 63063 31095 31433 62695 63002 31590 64075 30973 30876 63799 63986 30804 30532 30954 62961 31711 63386 31297 29880 62794 30993 31153 30967 63875 63399 30433 62853 30904 30158 30214 30398 31375 30526 30228 63590 63126 62510 62799 62674 62531 64446 31502 30900 29919 31497 63448 63158 63615 30120 31071 30516 63574 63994 31034 30456 62791 30710 30296 30240 63363 64281 31148 29827 29741 31101 29887 30900 31727 29813 63730 30479 63522 31018 63459 62537 31063 31724 30052 29899 64446 31273 63053 30430 31564 31380 30962 29872 31645 31660 62552 31165 29708 62530 30349 30625 30691 31359 62833 62834 62640 62914 63566 31181 31006 63702 64257 62996 63071 29904 29839 29958 62950 62751 64292 31615 63986 63706 64452 29977 63849 31631 63897 63806 63479 64318 64085 30274 31612 30875 64044 64019 63896 30061 62985 64229 30200 64397 31381 62970 30447 63150 64080 64164 64103 30605 62591 64397 30853 62720 31246 30226 64474 31112 64124 62488 63246 31386 30368 64269 63045 64218 62753 31635 63598 63417 64472 31127 64283 31014 30908 29931 63563 29815 62719 29962 64406 30836 31546 29996 31297 63719 64142 63970 63018 63642 30992 30576 64258 62934 64081 31399 30841 63368 31422 64083 29700 31184 62688 64224 31244 31509 31676 63945 63685 63813 62927 31513 30011 30834 62635 63739 64096 64240 30800 63526 30559 64493 62609 30895 64351 63076 63211 63697 29920 30983 63589 29727 64308 64086 63303 62574 64200 30682 30838 63834 30158 64397 63885 31532 31356 31577 62901 63873 62513 63143 62596 63537 64478 31006 63960 31261 62939 64271 63128 30523 63815 63431 63577 30209 63669 63870 30783 63793 29740 62579 30749 29811 64334 63113 31163 30964 64237 63632 29766 63872 62762 30149 31586 62549 31283 30404 31423 64473 31239 62484 64509 29995 64416 62464 64149 31193 63172 30993 30612 31092 30599 31250 63044 29885 31113 63975 64392 30847 29781 62923 29900 29966 63420 29919 30301 63020 31729 63632 30114 62697 63790 31080 30256 62516 30849 63829 31339 31043 31081 31593 63464 64173 31114 64392 63953 31271 62988 30861 31023 30781 31343 29911 63050 30964 63775 30637 30931 63831 63962 63211 31197 30647 31189 63124 62686 64163 63088 30023 29869 64014 31349 29838 31318 30672 62633 30151 30261 30649 29975 30227 31193 63577 63598 30436 64414 63873 29964 29918 63280 62630 31601 29735 62939 31008 63717 63797 31711 30684 30418 29827 62982 30083 30206 30599 63763 64027 62794 64496 30048 64296 31310 63226 63387 63790 30319 62489 30302 30218 30863 63829 63376 64046 30785 29776 29954 63625 63494 62916 62551 31700 30790 31389 30852 62471 30458 30739 63333 30014 29727 63489 62706 31415 29776 63312 29784 31439 29846 64444 63709 62953 64316 63401 30453 63606 64241 63700 31578 63143 62527 31663 29838 31004 30870 62850 31161 63176 30696 31300 62495 64508 64146 30347 62713 30301 63113 62779 63952 30335 31141 63044 30415 30146 29782 31564 63386 62798 30380 30173 31403 63542 30321 63369 31247 63299 30485 31212 31346 31613 31071 63401 30377 30575 64468 64388 63276 64251 63452 31545 63693 64164 64024 31016 29746 30992 63321 31172 30901 64265 31574 63624 30822 31200 30008 64451 63140 31577 29864 63943 30130 30791 63171 31226 63446 63084 63505 62769 31464 64469 63361 30929 31443 62610 30678 63524 63058 62484 64023 63599 62756 62559 63791 29767 31642 63090 29997 63378 30612 63773 31079 30436 63454 63666 29867 30523 63742 64355 63040 63755 31721 63484 30085 63739 64106 31586 30247 30454 31672 64140 30110 31671 30375 63778 30462 63713 31466 63502 30824 30210 63448 62538 64323 30387 30716 64048 63031 63857 63211 62637 62810 62740 30291 29860 29903 62885 62915 63643 63268 62902 62597 62944 30719 30346 63555 31114 31548 64355 64475 31403 31081 63243 62937 62929 63281 31032 62833 30179 62503 30483 63301 62943 31184 63872 31108 63809 30299 29748 62626 64105 31553 30487 30818 30077 30733 64467 29970 62717 30644 31651 29946 64025 64207 30630 63591 64192 30332 31740 30183 64006 30132 30956 31337 64039 63612 64065 29711 62731 31619 63101 63497 30172 30939 63432 30128 30421 30891 64473 30138 30187 63262 30555 30396 31330 31076 31570 31325 30223 31166 62785 30850 30649 31096 62588 31176 30030 64315 31420 30484 62682 64492 63969 63912 30023 31393 29792 31054 30366 31557 64228 31599 30014 63276 64200 31699 63425 63107 29811 63219 63814 63787 63699 62589 62574 62895 62779 30597 63295 31251 64433 29772 62672 29784 30162 63921 31067 62870 29721 63652 31692 30540 30437 31737 62467 29750 31233 31637 30971 30144 30067 63989 62726 62489 63533 30811 30267 64034 29753 29924 30014 62992 30162 30174 63544 62514 31287 62469 63040 62911 63384 31040 63007 63653 62818 63369 63108 64450 30334 30820 31171 63130 31383 64119 64374 31099 31733 30303 30414 63554 31370 62699 30327 63083 64374 30707 31104 64347 31167 30932 62791 63055 63816 64113 63177 30320 63752 62932 30021 62901 30216 62630 63475 64445 63881 64247 63025 31704 29742 62953 29955 63694 31593 31030 30039 29737 30316 63117 62701 30802 62671 64278 63493 63882 31223 29905 29750 30167 31173 62832 30746 62839 63433 62556 30652 30614 30565 31186 62855 30629 30959 29844 63800 63259 31188 30339 30044 63409 64472 30094 29820 30038 30737 63559 63998 30154 63163 62939 30726 62863 62635 63442 63191 31091 63610 63948 64224 63828 62875 31515 30528 30190 64303 30046 31677 31568 62686 30484 63180 63903 63411 30602 31368 63316 63667 29872 30302 63252 62845 31630 29713 31221 31259 31255 30868 63668 63551 63093 64005 63284 64252 31446 29746 30996 31719 31444 62923 64156 64056 63934 29708 31020 31573 29975 31446 30279 30774 31415 64232 30680 31124 62651 30398 30706 31221 31206 30782 30938 29776 31574 30609 63632 30691 29984 63999 29910 64508 62559 63589 30559 64410 63761 62883 30022 30362 64453 30752 64389 63332 30083 62610 63670 63016 31167 30815 31572 64263 63794 31380 63485 30289 63754 30990 30409 30931 30701 64080 30130 30215 63495 30249 62657 29745 29841 30993 63347 62545 62893 31685 31384 30589 64096 30746 63520 29742 63966 30309 62939 29866 30710 63029 64032 29909 31298 31653 31031 31247 63214 29941 63872 31560 31662 63323 62910 31660 30233 30411 31335 63669 63489 62607 63689 63211 64373 64093 30567 29977 62823 30745 30889 31621 29797 31703 29791 29916 63339 30575 64003 30553 64492 29714 31117 30902 30441 64009 29701 30461 62516 31340 30170 64486 64026 31408 63289 63032 30776 62879 63485 30092 62489 64154 63229 30179 31001 31157 31291 63759 31246 29908 62876 30947 62748 62710 63553 30684 62544 63706 64259 62733 30604 63695 31491 29856 30042 64450 64363 30946 62565 64020 62561 62790 30931 63229 63414 30107 62546 63641 62540 62900 64193 62901 31574 31499 30412 64379 64322 63764 30842 31033 62973 64067 62786 64201 64241 30825 30737 30663 29961 30788 63588 63764 31277 31076 29925 30864 62686 62680 31571 30968 62907 63898 30552 31367 63442 64034 31338 64489 29995 30279 30534 30251 30619 63879 62972 62867 30219 31324 30084 31423 29898 30451 63877 63267 30852 63696 31650 29772 30021 30147 63407 64181 29972 64428 30469 30384 62778 30583 63662 62827 62954 62775 31183 31651 63445 64109 63648 63800 30513 31260 31152 30812 29764 31079 63891 64090 62813 62688 63197 30210 31735 30707 31610 30193 64374 63991 29752 30189 63716 63121 63225 62753 30623 30659 63350 64081 31188 31394 63772 63361 30882 31405 63867 30630 64293 30989 31354 63167 31058 31113 62597 30484 64484 29983 63716 30838 64261 64355 30621 63077 62669 64170 63204 30393 63296 31726 29927 62688 63755 31526 63509 64443 30006 62620 64372 63821 29931 63265 30109 63783 29740 63197 30292 29752 63167 30211 64097 31228 63193 64087 64026 30034 30199 63484 64438 63396 30007 64287 30372 64254 63190 31032 63649 62820 64133 64440 63190 63750 63421 62571 63090 31389 62660 62988 62886 31298 63181 62531 30443 30518 63106 64312 30856 30885 63031 63940 63129 29906 30332 64360 63450 63203 30748 64449 64457 30108 30087 62957 30950 31008 29861 62697 30653 63096 62660 30195 30910 29757 62750 63973 29779 31594 63586 30365 31183 63713 31233 63840 29715 64148 29801 31519 63131 63981 31134 63480 64143 64012 63429 31319 29717 64283 29871 31700 63999 63642 64332 30272 31259 63447 63134 30304 31544 31290 64416 30789 31628 64212 64466 31188 30956 30622 63318 63512 63440 31377 64037 63679 30725 31205 64108 64399 31244 30600 63388 63188 64143 63180 30796 63491 30243 29733 30827 63898 63660 30895 31417 31639 31595 63564 62517 31354 30696 63521 30077 29819 63976 31170 63155 63675 31241 30604 62907 64047 30533 64322 63993 30147 63543 62807 64412 63272 30894 64379 64406 64315 30263 30145 30937 62904 31605 64296 63963 29876 30298 30456 30795 63748 63763 63775 31317 30560 29758 64076 63046 30435 31638 31591 31112 30642 64284 31168 29726 30614 62647 63484 62603 64160 31689 62478 31415 31494 63052 63888 63747 30056 64318 64002 30475 63501 30346 30040 30244 62618 30263 64190 62767 62960 64328 31338 64294 63241 31270 64234 31742 63235 64110 62684 31652 29800 64350 64468 62898 63869 30088 64452 62940 29711 63316 64402 63166 30881 30631 63030 31346 31242 63688 30758 30869 64026 30420 63486 29911 63080 64053 62717 31181 62493 63911 30418 63716 30988 64204 31568 63625 63787 30696 30844 31586 64039 63948 62736 63326 63485 62745 63024 62970 64027 30134 30079 62616 63694 62769 30311 30602 30877 30116 31669 63630 30282 30163 31727 64439 30374 31376 31364 31704 62520 31293 29977 63798 64316 31040 63387 30138 30359 30378 64045 29932 63369 64238 63701 64509 63672 30409 62982 30082 64251 63840 62973 31309 64264 62665 64011 64501 62976 30545 62582 31039 30920 31524 63314 31437 31517 30220 63318 63547 30009 63380 30462 29903 31647 30549 31032 62702 63510 64246 31112 63682 63288 30259 31209 31113 63596 63920 64332 31617 31662 64015 30573 63127 63405 30034 30832 30162 31400 62471 30971 30947 31586 31645 64133 63739 62865 64478 63317 30232 63941 30259 63799 30526 30621 62965 31507 31244 62527 29815 29941 31256 63043 30519 30978 63361 31669 63853 31127 63543 30277 64254 63838 63091 63316 30694 30849 30538 64258 30195 29866 29939 63644 30528 62732 30120 30835 64065 63439 31456 29756 64299 64033 30337 31115 63181 62622 62845 63720 31273 29759 30232 63187 31243 63705 30593 63030 63781 29917 63507 63607 31531 31700 64072 30488 62969 63601 63010 63486 63505 29857 63607 64455 64089 63677 29981 30190 63229 30244 31076 64343 64322 64198 30268 63527 30653 63226 30195 63700 62778 30775 31221 31025 29930 63462 63025 30638 62986 29774 31058 64241 63387 29732 30491 63161 63190 63476 62894 64298 29799 31388 30277 63267 64080 30199 31518 62483 64323 63930 30821 64010 29744 30334 30942 63893 64082 62586 63538 63739 62500 63035 29801 62795 63033 63686 62850 30929 30101 31178 30821 62688 63483 29876 64202 62825 63749 63675 62498 31188 31576 63206 62962 62893 31333 64426 63662 31633 64380 30868 62994 30882 64107 62705 30411 30469 30223 63298 31428 63910 31662 62629 30154 64468 63048 62769 29714 30801 64042 63557 31103 30544 30142 62744 30898 30417 63031 31078 30926 64328 30009 30428 63122 62555 31414 62881 63257 30633 31427 63476 63393 63101 64268 30368 31439 63298 30837 31516 63994 62607 30320 63347 31574 31703 64139 30312 63704 63598 30966 63537 64491 63360 30208 30567 62826 29889 31209 30139 31467 29861 30090 30330 30371 31413 62595 30452 31471 63881 30939 62665 31321 31330 31599 29717 64482 62967 63793 63173 64029 64393 31085 30994 63214 64301 64328 63471 64251 31431 62846 62470 63984 31713 62469 31030 31418 63643 64047 31650 62966 30726 62609 64065 31620 30257 31546 62776 30010 63717 63687 63053 31565 63914 30048 64188 30855 62920 64417 30140 30065 31077 30043 62860 62684 63741 29798 62603 31502 29885 63286 62805 63917 30162 63532 30185 62919 31409 63372 63578 30519 30252 30029 63664 62958 30445 30795 29995 64344 31040 63252 29965 63983 64357 62813 31420 30508 30282 30699 62758 31608 63618 30882 31455 62939 30254 63223 63402 29963 29889 63905 31463 63731 30440 30418 29749 30895 31368 63010 31408 31592 30243 64179 62849 62788 63943 29805 30412 62778 63468 62527 64438 62893 30858 31515 29728 63273 31146 63920 63354 30874 64381 31334 29766 63327 62853 64329 63576 31291 64502 30014 30330 30153 31014 30852 63292 64073 63565 64303 31548 29825 31135 62656 63914 30657 64165 29798 31358 30953 30439 31096 30946 63607 31071 30365 30556 30939 62533 29869 31076 63541 62714 30709 30445 63406 63040 30059 63152 64471 64084 31213 30850 63575 30532 63317 31388 30385 31643 62884 64160 4286578687 4286578687 +1024 30128 62888 63517 62727 30311 64052 63319 30634 62568 31634 30793 30720 62823 64037 63162 30400 63785 63126 63013 63301 30627 62991 63440 30053 30435 63623 63806 31359 31041 63639 62618 62570 63899 29716 63462 29973 63602 30409 63457 30256 30267 30439 63139 30779 31309 30589 63531 62763 31012 30691 63270 30879 29970 62770 62611 63358 63093 62835 29899 64141 30732 63113 62844 64491 31549 64189 63971 30364 63826 31436 30795 63857 30751 63157 30398 30793 31069 31023 62818 62793 31090 30551 31061 31415 63479 31558 63150 31044 63028 63198 62918 63048 62812 63230 29940 63839 29790 63043 63616 30943 63937 31737 30842 62953 31572 31714 31522 31474 30334 31236 62810 63922 64227 63731 30612 30551 30412 63735 62678 62828 62787 31016 30594 30602 31070 30358 31725 62565 62592 30482 30635 31606 63910 64153 62812 31669 31042 31384 30880 64410 30270 29923 30289 30105 63417 63582 30150 63541 62902 62502 31547 63904 29818 62599 30359 63627 62600 63566 63048 31319 64161 30913 62543 31380 63596 30001 64075 64060 30072 63350 31291 30739 31136 64406 29717 64384 64126 62938 30733 64450 31569 30987 64423 63700 31143 30024 64405 29948 63970 30803 62757 63863 63725 63549 31112 31617 62539 31065 30131 63353 30935 31717 30783 30726 30597 63677 62626 31217 63458 62735 30958 63048 63904 31082 30292 63242 29919 62640 29839 29994 31061 63703 62748 29956 63872 31494 63034 62491 30771 30760 30348 29983 31150 31468 64158 31636 62992 30353 30523 62834 63906 29833 30419 63952 63542 31720 31497 31395 30250 30073 64247 64509 30330 30881 63412 30132 29719 62506 30952 30242 63527 31269 29809 31209 29997 30467 30695 64045 30728 30217 63122 31694 63977 64450 62868 63267 31224 30295 31268 30525 62530 31688 31428 63395 63030 31742 64369 63472 62947 62962 29747 31690 64137 63038 31534 31248 62970 30031 64380 29866 62708 63293 30662 31119 30676 30157 62627 62579 30461 62633 30326 63109 31001 63196 31339 29889 30929 29757 62571 62798 63239 63577 63982 64229 31351 31583 30350 30289 63096 30388 30250 63375 30936 31355 29755 31574 31250 64346 30955 63843 63676 29762 62771 31260 63434 29702 63061 63093 63670 63908 63450 31597 62885 62814 63772 62909 29728 63051 63781 30211 29931 30093 30088 63998 30079 64028 31734 63502 62566 63383 64060 64146 31491 62843 31504 29949 64277 29953 30495 30226 31281 63346 30481 62966 63512 30869 31157 30283 31661 31230 31290 30188 63709 62596 64008 30286 30557 31403 63926 29727 63984 29760 29959 30306 31343 31450 31479 31363 29920 64241 29729 63015 31059 62605 64123 62896 63849 29932 30325 64391 62732 62556 31216 62756 30963 62722 62685 64278 63453 62650 63255 63637 63889 62758 31183 30738 63523 30448 31582 62820 31045 30351 63465 62895 31224 63836 64141 30290 31385 63232 62704 62735 63647 64036 31358 31500 63752 63255 62870 30643 31111 30120 30050 63161 29988 63070 31170 63092 63382 31468 30441 62711 63287 63940 64466 31743 30425 30584 30699 30777 31073 63031 30957 30779 30579 30268 63473 31130 63512 64385 29978 29708 30363 63278 62789 64297 63233 31335 30406 31411 63449 30777 62979 30516 63354 62649 30181 31334 64395 31254 31282 31734 29717 63426 29752 63322 29725 30042 62889 30768 64369 63043 30841 30242 29809 62607 63789 63712 62725 30337 29968 63527 31611 29743 62596 31725 63368 30759 30468 64314 64102 63630 63735 62881 63240 31491 64324 31171 31613 63979 31722 31099 29874 30051 29803 30498 64092 63004 31559 62910 64111 62904 63884 63057 31114 64153 29799 64126 30995 30860 63633 63127 31236 30470 62808 30437 30049 30554 30429 62825 30196 64156 63886 63146 30028 63550 63540 30716 29733 63408 63571 64158 30692 30459 31150 31385 30747 30599 30394 64264 63233 63505 63918 29961 31352 63262 30244 63555 62745 62514 31151 29733 64428 64073 30618 30599 30243 29932 62891 64421 30654 31126 64410 64409 62606 62900 62591 63587 64108 31177 30961 62815 31088 30271 31569 30502 30296 31493 63082 30548 30216 62501 64236 30339 31110 30239 63765 62587 31725 29696 62550 31304 62702 30339 30886 62535 64471 62890 29996 31644 64388 63512 62596 64096 30148 31432 30545 63299 31066 64511 64251 31091 64361 63512 64046 64475 29739 62643 31067 29722 29768 30319 63846 31515 30820 31158 31319 29870 31187 30945 62988 30689 31104 31071 30269 63915 31405 63116 30626 62694 63572 30988 30288 64219 31655 63975 63975 29896 63506 62969 30119 30848 63523 63464 30269 30937 63093 29707 62937 31029 63820 62915 30223 64160 29978 31027 31587 63556 62618 64301 30818 30003 64364 31265 64116 31617 29773 63220 63322 64196 63996 31299 63305 64386 30688 62634 31742 63843 63934 30456 29890 30109 30918 63030 63222 63608 64417 63335 62741 29831 63535 29717 63812 64259 62918 30813 30649 63707 63963 29871 29971 63074 30758 30690 31028 31451 63302 62827 64116 63287 30004 62882 62858 31007 63668 29937 62561 31651 30931 62798 30056 64183 30792 31567 31105 62557 64367 31701 62882 63514 29854 30146 62633 30727 62561 30370 31053 62691 30261 62501 31044 63372 63132 30088 62540 64069 29829 31305 63198 63244 63500 30158 62667 62942 30387 63813 64265 30901 62621 30181 63384 62935 64239 64170 63701 63137 30562 31443 31565 62689 31027 30231 64330 30272 64197 63675 30362 31207 29950 62990 30396 29918 63814 29986 62677 63286 29736 30317 30942 31413 30185 63984 63771 30311 30930 29899 29811 62504 30028 64500 63997 31429 64337 62893 30389 63336 30723 30191 31256 30608 63533 31015 63325 63669 30798 64218 31340 62523 30197 62955 31088 64451 29780 62710 63022 31268 64231 31541 64218 63734 64042 30355 63290 63516 29775 63117 63337 30003 62498 31361 30736 64314 31733 30002 30100 63420 30538 30217 31303 64133 29716 62765 63686 63126 30375 31348 64095 64158 31011 30232 30658 64372 62520 63204 30524 62596 31539 62910 63942 30664 63923 63785 29764 63575 63386 30068 30610 30970 63730 31374 30764 29851 63633 63010 29735 63405 29833 64118 31519 63690 30260 63721 63045 30735 31042 31288 62908 62821 64361 63584 30736 31597 63028 63001 63967 29714 64264 63399 30584 64113 31382 30449 29858 63510 31677 31068 31414 63555 62915 63316 29791 30110 64353 63894 62481 30876 30558 31598 30504 62998 31546 31016 31003 63915 63028 63085 31262 62777 64032 62783 62985 31416 31274 63047 29870 63987 30899 31065 63346 30270 62611 62970 62880 30424 31375 30398 30102 30875 64215 30901 64065 30624 30348 30229 63478 30632 31069 64412 63362 31087 62863 31627 63983 29855 30136 29936 29831 30179 64357 31520 31671 64228 30962 30166 63302 62509 30264 63095 30223 63514 31453 29783 62656 30268 29891 29872 63480 30852 64168 63372 30938 64164 30682 29976 64304 30339 31728 30164 62761 63705 62524 31250 62633 30600 30242 63045 62866 63112 63858 63098 30471 30890 63578 63096 31443 29766 30090 63792 63409 31665 62506 62850 63272 30338 29934 63887 30387 62808 29887 64184 64053 62655 62741 31341 63696 64388 63390 63960 63895 29805 62774 29713 64100 63565 62908 64152 31536 29755 63081 63020 63318 30646 29951 64393 62732 30247 63455 63270 30419 29916 63949 31006 31024 62850 63804 30375 30657 64040 30139 31545 29783 63344 31730 64374 30783 30074 30638 31265 63443 29838 31696 31637 30479 63725 31263 63876 64430 30174 63019 30741 63719 62818 30507 30167 30315 64191 63392 64049 64169 30115 63750 64443 64038 63533 63060 30683 30920 63025 64346 62678 30343 63429 64441 30686 64175 30834 63801 30177 62991 29703 30319 31001 62512 30242 30290 62470 30478 63919 30455 64123 62931 63720 30274 30775 31369 63687 30914 63443 62833 62864 63437 63897 63245 63959 30221 31122 29710 30037 64015 64441 31589 63058 29712 63231 63897 30715 63007 31077 31429 63416 31612 30464 62577 64249 30753 64017 63393 63736 63428 62678 63407 30100 31550 63205 31097 30307 30003 63568 63527 31145 64456 30883 62966 30051 31470 31678 62695 29929 64029 63873 31013 63143 64466 62964 64223 62559 63036 64493 31145 31543 31153 31505 64467 30294 63828 31293 62464 30689 30561 63811 62803 62982 31035 29857 30427 63608 64084 64182 29709 30358 64012 63662 63417 64174 30778 63977 31299 30664 31285 64358 31600 31257 64476 63695 31474 31357 63433 64083 30029 30493 30685 30987 62864 64225 63995 63514 63624 31333 64292 62592 64503 29893 31653 64178 30515 63238 63050 29975 64504 63939 31063 30254 64138 64074 31329 30936 64468 64202 64456 30707 63316 64080 63146 63827 63354 31647 64154 64313 62881 62799 30800 29885 29967 29856 62885 31534 30056 31693 63944 62791 64194 31225 64478 30807 63152 63418 29964 64374 62696 31436 29714 30986 30717 31159 30857 64332 29745 64347 63208 30531 31353 63548 63935 64455 30564 63843 63369 64231 62517 30214 30259 30678 62966 64493 30930 64042 31108 30940 63189 30590 62733 31096 30327 31133 63910 63640 31423 62771 30616 63467 30048 64037 63422 63532 63151 31322 64114 30144 30738 31439 31693 63778 63671 63994 63194 31080 64263 31139 30939 64202 62891 62896 64313 64401 64157 30563 63156 62580 31483 30389 63423 29707 30582 62723 30858 63169 30393 30811 63117 63963 31729 62936 63616 63367 62548 63515 30735 31564 63456 30058 62591 31087 30461 31390 62767 62808 30369 29756 64304 30343 30137 64250 30534 30287 62716 63709 30539 31268 30450 30910 30717 31311 64216 30923 63540 31679 31615 31719 63607 31688 62780 62802 31496 63902 30808 31479 29856 31404 64407 30014 63289 31606 30114 31726 31432 30278 30737 63861 63381 30423 29937 63738 29773 63016 31130 30885 30284 63445 63910 63390 63566 31638 30025 29966 64459 30525 62464 30426 30824 63912 62698 63476 64232 30931 64331 62980 29928 63214 63147 30903 63519 64082 64217 31717 30503 64470 62789 64167 63170 30593 30661 31611 63723 31674 31638 30905 31357 30977 63378 29981 30870 31559 63902 31174 30879 30794 31366 63175 63736 63745 30083 29887 63723 63234 63637 63525 64221 31537 30839 62824 30991 31421 63807 30009 63392 30269 30442 31692 62965 31147 30715 31552 30680 31402 31201 62949 31682 31364 63096 31553 31570 62970 30578 62992 29954 64132 64209 64504 30711 63354 30645 31672 64319 62834 63404 64002 62981 64236 63720 29807 30205 31090 63147 31237 63067 29838 63521 29958 29740 63141 64113 64024 64358 63234 31438 62943 29716 63653 30920 30276 62685 63203 63598 31421 29998 64140 63194 30670 64443 30956 62997 31000 31318 30523 31430 64118 62495 64111 64116 31225 30825 31444 30589 30356 63353 30512 29952 62547 31126 62580 30773 30984 63544 31049 31659 63483 64243 62778 31581 63727 30635 62580 63116 30188 29874 63710 63602 62669 63185 31153 30110 31308 62464 30788 63255 63484 31533 31530 63962 30628 62904 63942 30370 29862 62780 30794 63427 63464 63082 30515 62811 29799 63172 63486 62573 63864 31628 64340 63233 64207 64013 29861 62994 63079 64066 31160 62857 30580 30900 30585 31031 29874 30692 63772 62603 30518 30185 31583 63227 31471 30031 30606 62490 29734 63738 30420 63305 30975 62591 64032 31384 30641 63576 62589 62759 31279 64200 30581 31356 30534 64364 62784 64185 63678 30469 30421 30346 31083 30971 63527 63104 30654 30436 30382 63820 30974 64118 63183 31141 30003 29964 30956 30535 31507 63217 31279 30554 31557 29799 62795 63288 63458 30053 62691 31342 31700 64024 64081 31483 31163 64131 30776 30782 63319 31547 31578 30910 63801 64002 64313 31057 64127 62983 62553 31237 29835 64202 29769 30186 30120 31161 62783 29810 30529 64261 63396 62660 64404 31051 30611 30345 29758 30465 29757 31431 63713 64015 31061 29892 30064 63973 31017 63494 64486 31107 63388 62713 30768 30333 62990 30454 63314 63092 31580 62645 63632 29999 30503 29835 64205 64259 29829 62934 30051 63424 62891 63243 30310 30957 62629 30951 62761 64054 31023 63057 64143 30832 31700 31602 62690 31110 64328 30142 31222 63514 30945 30344 62889 31291 63018 31537 30047 30537 31212 30576 62727 30132 62857 62787 30752 31279 31652 31674 63232 31194 63471 62598 30366 30852 31195 30666 31337 64107 62991 64151 31695 31176 62465 30260 30498 29746 30736 62558 63339 31338 63688 29887 30828 29779 63438 31630 30604 30012 62527 31678 31305 31713 63833 29730 63479 30819 64381 31678 31203 31599 63626 30057 29976 64300 62551 63092 63134 64328 63416 31379 62897 63049 30207 64263 63562 62888 31191 62826 64355 31094 64096 30577 62882 63460 63117 63903 30303 30177 29935 30920 31640 63954 29827 63292 30462 31563 30100 63714 29951 30401 31602 63785 31660 64140 63166 29825 29946 30264 31331 63243 63276 62762 63670 29735 30325 30378 30427 30815 63385 31357 31378 31475 30918 62992 29956 30593 31326 64047 31216 30128 30785 30651 63514 29712 30379 30762 63992 30926 31001 31405 64221 64206 31487 63405 63958 31508 30125 31665 31279 31494 64005 29746 63537 4286578687 4286578687 +1024 31452 31253 62750 30865 62707 31175 64132 62904 29795 31466 31507 63678 29706 64460 30407 31336 30806 29768 30553 62523 63245 64038 30130 63749 63394 30793 64002 62832 30704 63477 64479 31491 63013 62915 63237 29803 62540 63674 30258 64174 64282 30512 29820 63495 63593 30216 30624 62602 30215 62516 64487 63577 63613 30342 62673 63784 30824 63478 64371 63637 63104 30671 31233 63494 31033 30599 64046 63512 64125 62618 29802 63918 64371 31308 31115 63178 63212 29980 31467 64148 30525 62942 30749 29815 30554 64296 31487 29900 63155 64264 63598 64381 30155 64135 31620 30282 63378 30037 30606 29858 31076 30345 63052 31191 64267 31611 64508 29870 63384 30612 31102 63936 64263 29951 30666 63370 30661 29970 63150 64267 30354 63571 30148 30155 31027 63974 30275 30801 63942 63071 63711 63311 63483 62909 29843 30639 63098 62713 63191 30269 64338 62874 63236 29701 63101 30881 30491 63020 64072 64464 30317 30751 64208 62912 63190 31506 63009 31431 30532 31586 30017 63932 31195 30548 64217 63842 29903 62620 64144 63477 62879 30859 62571 63698 62566 63237 30263 31233 63530 62818 31591 31421 30373 30736 64118 64277 62994 31442 31606 63718 64218 64442 31736 31175 62664 31144 64090 63802 30048 63302 30803 30521 64393 30590 63738 31251 63531 63059 63603 64322 64175 62923 31597 64146 62585 63492 63059 30251 62638 29845 31085 62711 63884 29812 63880 63711 62699 62522 30552 30188 30801 63002 30975 63613 64242 63038 63090 30527 63391 30934 64389 30241 64066 29767 63887 63651 31579 29801 63725 29994 31603 64062 31286 63662 30903 63441 29886 63932 30723 31074 62588 64121 63307 31428 30604 30607 31100 30739 31172 30245 30787 63771 64129 64266 63600 63821 30549 62925 62483 64050 62744 29719 31184 64213 31125 62720 30831 63170 31425 29706 63664 63056 62665 30859 64306 64356 30643 63927 30764 31705 63117 62572 64353 63930 63537 29854 62961 64091 63937 29791 64427 62813 63538 62473 30940 62997 29914 63288 31192 63275 63564 63308 31727 31428 30803 64279 62988 62839 30795 62750 62574 62886 64497 62910 30561 63591 30718 64000 30525 64416 63414 63547 31010 64266 63618 31718 31416 63470 30806 29697 30965 30340 62589 62554 62981 62877 29791 62547 31223 63889 62908 31721 62600 63758 62810 30425 62552 63950 63621 30352 62833 62980 63292 63018 63102 31352 30708 64390 63314 63294 31388 63183 63284 63754 63681 62943 31245 64052 31505 31202 63355 63480 63546 31142 30721 64385 64390 31302 31114 30927 63274 63766 31051 64088 63876 62828 30626 64178 30068 63968 63044 62719 62822 31456 30605 29931 64307 63667 63517 30910 31145 63680 63981 30250 31184 30232 29942 63655 62559 63284 30303 63638 31166 64132 30195 62541 63287 30953 63083 31486 30573 63101 62941 62636 31184 31094 31106 62487 64142 64386 64151 63411 63758 63107 30465 30973 63839 63518 31436 31739 30544 62601 62627 63547 62949 30171 62615 30434 30183 63314 31473 30273 64224 31611 63467 31334 63449 64380 62903 30368 63725 63340 63467 63037 30663 62886 63192 62751 30025 62906 64378 30468 63370 31516 30814 62752 31000 63342 63532 30985 31330 62979 30127 30912 63590 63054 30929 30419 62722 63631 30064 30380 30748 63226 31693 64452 63446 62591 62883 29814 30599 29820 63248 30190 30979 62741 31280 64473 30659 30463 63683 31140 30389 63911 63000 30383 64221 29720 64199 30763 31639 30400 30740 30554 64096 63342 62667 62704 63259 30894 31151 64213 31377 31649 29744 30335 31274 62949 31687 63746 63902 62634 64121 30468 29744 31742 63478 30766 63679 31590 64243 64245 30917 63648 29728 63806 31437 63017 29857 64510 29939 31573 64252 63922 29970 30415 29843 30066 62823 64425 63186 31378 64102 30654 30009 63749 31149 30370 63265 29993 30642 31393 63296 31476 64344 64274 63013 62875 31297 30790 64108 63979 63536 63757 31454 63719 31431 62484 30130 63497 29940 31134 63807 63196 29904 63343 63766 62649 64007 31098 31663 31251 63426 30534 30328 63895 29952 63155 64302 29784 31721 64130 30994 31328 31080 30909 29851 63675 29725 30432 63424 30955 63227 63158 30126 64503 63000 29798 63820 30524 63611 63944 64072 30609 31056 31570 30922 30129 63871 31204 62738 31515 30076 63302 31591 63716 30163 63724 30125 62571 30806 30175 30451 30187 31611 30344 63780 30636 63017 64329 31353 30577 30362 64237 31299 31495 29946 63160 29807 31248 64075 64029 30401 30677 31185 63159 30623 63068 62774 64067 63281 63998 31416 63371 62644 63230 30457 64380 63626 29778 64202 64147 29933 30345 64305 29876 30709 62480 30309 31150 62861 64086 30455 62780 63072 30150 30361 62827 31514 63215 30433 30102 31623 30916 62565 63760 63427 29844 30503 64440 31610 64074 31356 63205 31513 64476 62774 63021 29768 63573 64001 64027 31276 63904 63178 31445 63429 31015 30383 30738 31597 30928 62927 63971 31006 63972 62996 30579 62950 30723 30658 31369 64202 30444 31657 63166 63755 63526 64382 64068 63722 63611 31363 62979 62505 31318 31207 63540 31441 63207 30316 63085 63668 62964 64342 64209 29860 31360 31444 63259 30562 62948 31471 31418 62782 30072 63132 62971 30879 31357 30864 31709 63416 31593 30926 31583 29794 29789 63183 62606 31457 30332 31470 63008 31475 63315 30242 30361 64313 62511 31310 29919 30092 31674 64160 62631 63687 29846 63673 29931 31363 30574 63986 63529 62697 30810 30230 31533 31007 31383 30942 63559 62757 29872 31112 30013 30756 31028 29845 30906 31352 63776 29890 63111 63398 30456 29964 31113 64143 62698 63867 62893 31103 31328 31724 64397 63203 30797 31371 30284 64420 30273 29889 62636 30074 31076 31022 63049 64455 62758 64033 31584 31306 31006 30017 63299 29771 62821 63689 63561 31264 29811 63641 63630 63959 31228 64249 62511 64193 29964 30327 30278 29752 29745 63299 63670 62713 30024 63123 63791 64368 64028 62479 62715 30025 31691 63569 62998 31403 29771 29853 62990 31313 30188 63217 62931 29764 63138 30992 63878 64347 30946 64162 30992 31560 31590 63191 31452 63161 31429 31646 30627 63087 63120 63774 30999 63815 63306 31208 30409 30538 64018 63314 63163 63849 30850 62733 62562 30582 31648 63202 63693 29919 63117 30087 63128 30427 30893 30833 31105 63125 63963 31486 63491 63706 62651 63765 62484 29803 64352 63614 63759 31152 31651 62848 63480 29700 63483 63018 30653 63087 64302 31150 29993 62916 30826 64025 64397 31161 63761 30088 63948 29962 62751 31175 63261 63521 64292 31720 63086 29939 63633 63768 29964 63568 63145 62469 29962 63514 30910 63409 63399 62523 64248 62623 63133 30921 31523 62651 31415 29793 30782 64439 63919 64115 31423 64391 64103 62878 30726 30826 30369 29974 63175 30594 31164 62523 30212 63669 64206 64379 30572 29859 31593 63912 63568 63544 63207 30730 29845 31380 63035 63482 62757 63970 63635 63263 31348 30306 30011 31381 30466 64309 30825 62880 31264 30462 64315 62962 31524 31273 63526 64045 62831 63610 62625 63014 63879 30054 64404 63308 30032 30296 31725 31605 62957 30837 30507 63454 29722 62943 62717 31175 30781 63293 30018 31179 64371 63487 30844 63536 63095 64287 30751 62980 64293 31573 62755 29904 30715 63819 62552 62707 30345 63957 29773 30427 30745 62808 30897 62689 29723 30460 31331 63116 63616 64012 64415 30227 62552 64227 63682 63939 31108 31191 31272 63944 30275 64279 64153 63545 30806 64305 63640 30244 64149 31436 31332 29822 63839 31707 29990 64268 64503 62471 63191 63625 30924 30362 62561 62695 63836 30265 29735 64358 62772 31169 29739 63746 63770 31212 31540 63688 30506 63803 31117 64444 30138 63679 62810 63224 30242 30595 62768 30389 30420 31552 63260 31319 64115 30193 64197 63001 31287 31556 63969 31458 64181 63670 31452 63681 64237 63024 29888 31091 62955 63948 63863 31404 63423 30364 30114 62632 62609 62818 63486 64231 29996 30771 31475 30803 30108 62755 64508 62945 64227 62591 63638 30378 30178 30507 62925 64233 63804 31031 62750 30718 30108 63534 63481 62721 29826 30656 30253 30719 62908 64291 30599 30695 30075 63374 31569 64221 30603 29947 30155 62750 63195 64039 62786 30322 29945 31704 30670 64071 30526 64412 64448 31659 30755 31397 31613 63570 31677 31054 63293 31144 29994 29807 64225 30537 31628 63687 31415 30738 31669 64459 63450 62597 31193 63164 30326 63890 31198 30637 63624 30546 62781 31079 30377 30199 63402 62948 30554 29864 31039 63066 62974 30079 63388 64085 64420 31396 30591 30841 31224 62508 62993 63062 30343 62727 30649 63958 31072 63684 30509 62816 62752 62560 30775 64287 64122 63517 62502 31742 30060 30493 63739 31728 30961 62719 64421 30464 29847 30402 30360 30782 62853 62491 63340 30273 31150 63685 62901 30475 29740 30360 30831 30597 30350 31198 30415 30275 31372 30863 62538 64140 63749 62767 31740 29943 30085 62990 29968 64200 63812 30718 62792 64169 63449 63413 62728 64081 30030 31335 31595 63061 62655 63872 63390 30565 63703 29831 31529 30296 62846 29827 63262 31300 63894 31714 31644 64440 31206 30794 63149 62693 62805 30743 62790 63171 30197 30999 63067 30215 30400 31073 63186 29752 62934 30033 63829 64247 63458 31587 63176 63192 62987 30403 30165 31232 31223 29927 30557 64121 63886 31382 31123 31191 30849 64343 63275 29851 31302 29892 63948 29737 29793 64437 30466 31157 30807 64485 63826 29788 63282 63794 63116 64014 62565 62738 31038 63666 62555 29857 63262 64334 31367 30481 63060 64435 30770 31284 62464 31003 30048 64121 62919 30063 30501 30378 31248 29904 62913 64157 63187 30944 63580 62794 64065 31154 31001 30282 63510 30198 31189 29904 62902 30880 30694 30485 30977 31537 63751 62645 63069 30392 63027 63918 30639 30746 30529 29909 30210 62689 30723 31356 62510 64194 62951 63850 30467 64387 31259 63317 30931 63167 64190 31596 63615 31099 31300 62587 31407 29873 29911 62739 63866 63971 63031 30400 63347 62495 30970 31620 29933 63761 30130 63886 64448 29814 64087 29902 64001 63209 64193 30929 63425 30155 63382 31026 64350 29736 30623 30982 31518 64465 29901 30582 62522 63620 30254 64407 31317 31091 31319 31539 63532 31072 31250 30500 63772 31315 64399 31387 63781 31707 31039 63830 31459 31157 30061 31257 30115 63004 63613 30501 31164 29756 63681 62594 31004 31200 30752 63233 64057 62717 30373 30449 31078 63141 31503 30808 31587 31085 30787 30885 31381 31437 29698 63406 30956 63300 63066 31488 63215 63436 31704 62608 30379 30526 64002 31189 30359 30450 31007 64072 63252 30559 62920 63825 63983 64471 62622 31240 63734 30357 62995 64408 62694 29839 63992 62902 29916 63718 63721 30603 30348 30923 31202 63413 31208 63641 64032 63960 63195 30520 29991 29982 62753 63085 29879 30370 29728 30496 63469 63321 31519 30384 29812 31438 31334 30774 63176 29860 64458 31436 31350 30954 64384 64373 63153 31345 63008 63853 63897 63723 64030 63984 62544 31509 62856 31374 64089 63011 30726 62848 64406 29842 30684 63950 31554 31554 30288 30264 30779 29787 63788 63353 64048 64412 62899 30661 30955 31034 30738 62624 30450 30593 31186 30336 64046 64093 63342 30996 30362 63195 62809 30516 62948 30769 30717 30429 64452 29844 30242 31398 62668 30640 63813 62749 31040 62472 30710 31274 31169 30721 62901 31313 63755 29730 30849 64367 64222 63699 31618 63187 63775 63381 30255 30482 64380 29966 64508 30142 31322 31573 30273 63486 62573 30863 62989 29885 64476 30486 31603 30566 29766 31541 30078 63045 63232 62952 62971 62720 30377 63665 63563 64082 64126 63099 63278 63419 31467 63609 63703 64097 63167 62799 63057 30113 63761 64278 30730 64398 31456 63212 62912 31249 31481 29718 30796 64063 64508 63248 62816 63724 64090 63148 31195 31201 30052 30146 63435 31220 31126 63621 29764 30553 30871 64390 31048 30409 64082 63665 30643 63072 64015 30812 29925 30664 29826 29807 63030 63315 63492 64510 29784 31147 29844 62517 63588 30774 30486 30585 64074 62471 63237 31433 63062 30675 31029 29898 63672 64241 64395 30105 63906 31624 63713 63304 63991 31500 31411 30658 63926 30035 62671 64268 63418 31740 63853 30013 31505 30106 64228 62572 29888 30621 31385 30444 62636 30485 62531 30161 63831 30010 62640 63711 64185 30155 30710 31084 64044 31183 31463 31038 63221 31355 31346 64045 30995 31445 63354 30373 64129 63044 63868 64244 29992 29829 29916 30790 30867 30988 63300 64464 29979 31500 31495 30268 63635 63335 64003 30152 63258 30355 64494 30534 64027 29745 30343 62546 30739 30972 63682 63961 63146 62981 64320 64059 30726 30391 62566 29998 63222 31715 62808 64277 30550 63858 63197 63467 29739 64094 30626 30328 30160 30575 30074 30902 30388 64229 63274 64387 30757 62573 64280 30212 31353 30063 64296 63226 30887 63636 63313 63489 63978 64476 64188 63247 64482 30210 63011 30635 29848 29841 63093 30594 63784 63892 29968 63785 63338 30774 63709 30731 29730 2139095039 2139095039 +1024 64468 31629 63972 30899 30337 29993 30135 64243 30106 30893 63212 31469 29960 63352 29912 62709 30343 62972 62668 31551 64235 29742 63597 63038 30608 31286 62548 63424 31061 30122 31573 31408 64447 63580 64171 63027 31239 62690 31110 29735 64142 63820 63092 31388 63762 30649 64499 30792 30132 31578 63242 64187 64020 62691 31614 64200 62939 31507 31564 63511 30735 30623 30405 63443 64244 63912 31656 64404 29858 63291 30633 64281 64306 62702 31285 63906 62684 30881 31709 64020 30551 62937 29897 64226 31628 63132 63426 31509 62789 31293 63372 63411 64386 62842 63607 63714 62837 64207 30422 30601 29755 63381 64008 63968 31059 31194 30316 31026 64147 30234 31211 31088 62686 30636 63882 63651 30950 64235 64433 30920 29998 29868 63839 63731 62711 62766 30424 62549 30240 62629 30790 64174 63045 30828 31682 30986 30773 63669 62861 62516 64341 31482 29703 31133 63030 63271 63897 63116 64134 64395 30829 62653 62762 31194 62900 30508 31534 64270 64495 30611 31138 63364 29772 62755 30959 29717 31458 30395 31479 30962 63614 63697 30300 30820 62959 30012 63721 63841 62548 64370 63123 63771 30186 64322 62953 63710 62888 29949 30796 63148 30690 62784 31621 63747 31583 31682 62982 64292 31507 63181 31640 62791 29857 63948 63902 63844 30883 64024 31153 63926 62631 62465 30396 31189 62963 30221 62593 31374 64138 31601 63694 63343 64481 30628 29745 30840 64407 30466 64099 30327 30723 30967 31026 63379 63893 63269 31639 63999 31304 62594 63240 30583 64061 62491 63501 62854 31257 62918 30408 63044 30458 31195 63534 63064 30859 30735 63705 31134 64292 29845 63731 30731 30415 63889 30034 62858 63762 62987 63511 64430 30543 63710 30959 30646 64018 29841 62565 30900 31035 30891 64458 62657 62675 62733 30149 30544 62980 63728 30352 64089 64324 30356 62517 29883 30257 64427 63099 30450 63203 63351 63890 63570 62896 31189 30297 31166 30164 63815 63351 63509 31304 62996 64317 30648 30707 64463 63100 63909 30103 63022 30733 63339 30193 29818 29971 31646 31637 63778 62905 29891 30831 31647 30794 62787 64000 29724 30420 63006 62491 30388 31736 63314 30203 30095 62801 63863 30793 62901 63189 63269 64281 63046 31137 30116 30549 63653 30572 63931 63318 31177 64483 63693 63001 63720 30308 29990 29892 63850 64397 30686 63289 30836 31248 31289 31038 31606 63602 64168 63884 63523 31627 31239 63622 62626 62635 29991 64428 62525 30341 64332 29998 63002 63263 64227 31685 30052 63960 30299 31147 63011 30933 62937 29726 64227 29802 63297 31152 30706 30543 31207 30676 64184 30811 62943 31374 30453 29961 63040 31025 62565 30281 31539 30136 30759 30131 63442 62897 63588 31031 30463 31357 62581 30344 30452 31151 63014 30720 63201 62832 31230 30403 30006 62918 63478 30171 64101 63634 63461 63129 63081 29782 63353 63728 30160 62906 63067 31340 31697 64492 31169 63889 63176 31186 63239 30721 30526 31563 31425 31740 63188 29899 63667 64241 62940 62593 63334 30710 63109 31488 62678 30779 63813 64257 64441 30906 30068 31608 63372 29701 63659 31136 63361 63906 64091 30294 29825 31056 63305 63212 62956 64174 62744 63580 64023 63901 30370 63402 31044 30049 63389 30795 31523 30790 30539 30379 30028 63655 63926 63710 29948 29778 64145 30402 64409 31278 30120 31094 30069 29836 30876 30345 62539 63128 31503 63169 30664 63149 64399 64008 63639 63661 62698 30143 29975 63840 64109 29983 62695 62468 30576 64218 31307 29752 30894 63516 62859 29844 63157 31522 29864 30613 30315 64169 30459 31160 30489 64014 31508 63367 30266 63774 64232 30654 63634 62570 31407 30432 63282 31734 30297 30904 31510 63333 62484 30246 63990 29882 62464 31480 31462 63659 31241 30403 30357 62910 30681 31616 29920 30733 62799 31160 31684 31126 63949 63548 31500 30683 31163 29935 62504 64313 30084 64214 30974 31105 31629 63195 63798 30903 63750 30132 30486 31230 30598 63458 62618 31318 63170 30549 62509 63156 30951 30996 64268 31142 29969 29760 63350 30320 31591 62644 64203 64128 30767 62930 63149 63601 63860 64027 63066 31610 63218 30811 63708 30055 63116 63485 63153 31309 30445 29932 63275 29972 62751 62709 64404 63445 63325 30639 62705 64218 30193 29785 62695 31150 31308 30166 63869 63356 62606 30328 62819 31090 64030 31419 62648 31487 62572 62682 64234 62804 63093 64361 30938 64396 64126 63746 63465 63797 63172 63986 63872 64361 62474 31132 62835 29918 63275 30812 30723 29751 63742 31483 64128 63034 30191 63326 63284 64303 29990 30817 62930 64199 30146 62540 63637 63201 30848 63355 63978 63731 64009 29815 29830 30039 64446 63551 30899 63905 31114 63085 31506 29870 64099 30066 31470 62666 63245 31204 31554 31363 30032 63085 62922 31026 30352 31339 31304 63862 30984 62950 63459 63630 31452 31013 30428 64225 63815 29883 63295 29732 30966 30167 31161 30448 64103 64183 30982 30206 63403 30436 63793 63952 63023 31099 63378 64016 64465 62534 63969 30561 64191 30460 29775 31384 63659 63292 63767 31621 63001 64272 63288 63980 30189 30791 31449 29970 64145 30708 30526 30306 30700 30778 63645 31721 63148 64245 31363 63949 64216 63123 29885 31732 63856 64136 31505 64449 63516 63518 64021 30330 31060 30646 31387 31564 31182 31633 29743 29989 30779 30434 31645 30191 64496 31641 31188 31236 63762 31555 31049 63988 31467 30481 63112 31599 63225 30747 31599 64255 62983 29886 63896 31563 29858 30976 30070 63010 31008 30701 64275 63010 63400 30251 30011 64171 63838 29836 63528 63279 62658 62659 63277 30892 31663 31273 31682 30706 63469 30117 30864 63682 64105 31519 63957 63078 62736 31089 63684 30640 62771 63798 63730 63821 31021 62560 62804 30196 30468 62760 30584 63594 31161 30656 31459 63398 31662 63537 62484 64343 64174 63311 30463 30446 30574 31644 63103 62690 63362 30574 31054 31107 29799 31478 63370 62880 62695 63367 30447 63165 64194 63441 29876 62466 63400 64459 30725 63119 62734 64062 62845 63767 63341 30448 64084 62747 30757 62608 63783 31009 63564 29861 63925 64261 62905 64011 30449 30633 30613 30215 64503 64023 64243 31042 31112 29744 30841 62841 30727 62602 62792 63509 63953 63395 64139 31074 63812 64212 62645 30155 64033 30158 63030 30936 62952 62589 64105 31169 31145 64231 64198 30301 31046 63879 64325 31712 31392 62688 30346 64220 62820 31714 31288 30897 63405 31459 31706 63215 29808 62619 31597 63649 31024 62781 29750 63983 63431 63478 64292 63178 64106 31285 64331 30650 30728 30599 62641 63320 31188 30673 31022 64191 30474 29925 63583 31410 31378 63361 31448 63932 30451 62613 30082 29885 31245 63435 63707 30295 29828 63722 30387 29836 31743 63470 30381 64124 31229 62887 30317 31042 63141 30181 63802 62988 63657 29989 30387 30816 62874 64449 63950 64063 29727 63525 64174 62546 64320 30235 30101 63546 31730 30866 31616 31579 62647 63670 63949 64511 31365 31009 64220 64497 63889 63955 31606 29900 30875 30847 29852 64497 31375 63025 62787 62802 63744 31335 64306 64322 62602 63381 30998 31281 30222 29840 62798 31493 31643 30242 63218 63745 63964 31610 31728 63653 63592 64416 63311 30340 30569 29721 62469 31482 29893 31204 30295 63697 29861 29773 31279 31411 63086 29857 30526 62922 30947 62683 30826 31711 30086 29814 31016 31532 30509 63972 64345 62967 62920 62795 64113 31442 30252 63770 63045 30606 30807 31685 63265 62523 30875 31690 30509 31515 62680 31025 63659 31414 30217 30775 30907 64218 63236 62583 31251 63637 30769 62699 29925 30012 63208 64281 29901 30130 30160 30096 62634 30312 63327 63787 63169 63402 30572 31482 62733 30634 31131 64265 63365 30019 63565 63756 29832 63073 62628 62870 31739 62671 63068 31647 29904 31626 62901 63563 63658 30556 31016 30701 29705 64080 31057 30600 30518 30681 64322 62733 63598 64154 30690 62518 62703 63237 63887 64032 31237 62498 29943 30960 62760 30437 31342 30192 30055 62690 64107 30397 30509 30846 63870 30828 31504 31026 30990 30645 63823 31691 62833 63291 63477 62632 63268 62674 63866 30823 64036 29825 31212 63437 64266 63481 64041 31264 30470 64063 30555 31548 29875 63857 30843 31301 63170 30384 31385 30809 63240 64223 30666 29892 31116 31485 30264 63418 30433 63474 63621 30597 31016 30932 63819 64423 64292 30856 63930 30483 30934 30212 64195 63357 62634 63967 63347 62529 63435 64281 64064 63102 30307 64016 29744 63155 62637 63578 63250 31715 64120 30200 30969 31725 62527 30001 30290 64476 64214 30033 63485 30289 63688 31049 63717 63701 64456 31040 30796 62984 64088 63357 30371 30936 62497 30787 63405 63441 31265 63100 29855 31473 62847 63939 63585 62911 63837 62486 63705 62679 63471 29951 63666 63836 63299 63400 30487 30751 62581 30871 62991 63211 31151 31397 31168 63426 31538 29797 64222 29912 30841 31514 64480 30556 30709 63294 62562 30273 31068 31342 62957 64061 63481 64434 62478 63660 63465 30371 29710 63914 63535 63129 64218 30071 64317 30168 62875 63217 29965 63455 64309 63356 62863 64014 30736 30894 30551 63881 62804 30991 63320 29939 31074 63787 64231 30751 31221 30428 31571 31319 63737 31574 31473 63526 64213 63666 30747 30221 62679 29700 64214 63493 63244 29761 63001 63247 64491 30299 63830 62898 62988 63936 64182 63763 30259 30443 31448 63140 62659 62478 30213 62487 62526 30119 63839 63991 63815 62984 31606 63364 30166 31272 31362 31673 31300 30995 30767 30458 29945 31481 29805 63425 62998 64270 29791 31223 63966 30690 30622 62911 31503 64362 30738 29768 30166 63168 31615 30548 63151 63145 62986 30170 30932 63132 30362 62598 30296 62696 29789 62794 63275 30017 62472 63395 30264 62934 31626 64066 31413 30332 63248 63726 63009 63308 30076 31430 31719 62504 64328 63736 63082 63613 63835 63528 64090 62501 30755 30826 30202 30131 31626 63681 30129 30341 62512 62936 63994 62522 30057 29851 63147 63139 63053 30163 63586 30315 31183 31321 64267 62467 30561 30264 29736 63629 30617 63807 30876 30891 31321 64293 30740 31283 30675 30347 29912 30526 31054 30632 30905 31198 30491 31128 63890 30735 30277 31068 29992 30200 64215 64448 31651 30546 63984 31180 31073 63002 63443 63185 30245 63919 29931 29949 63310 62730 63603 62849 30366 30419 31045 64495 31261 63950 30530 63777 62671 63005 64274 31521 30746 30191 63225 62880 63691 64264 63588 31546 64094 63830 30877 29911 63883 63693 30953 64485 63237 63493 30455 63737 63394 29714 63914 31235 64039 31345 63380 62621 30997 64381 62950 64283 62997 64115 62650 31628 30533 31629 64210 63366 31140 30859 30875 63924 64263 64393 29776 64275 31513 64315 30137 63112 64260 31433 64265 63605 63476 31248 63756 63799 63516 63538 29812 30822 64026 31538 62980 64015 30726 31360 62824 62845 29850 31532 64259 31718 30035 64086 31570 63675 63015 64004 62546 63566 31492 62873 62506 30922 62778 63495 31723 62863 63571 31021 63025 29803 63451 30349 30926 29897 63114 63391 63287 64375 64374 63693 29858 31493 29927 64349 31041 64157 29884 63944 63960 31133 31015 31736 62786 30528 30027 64396 62797 31357 63676 64075 30654 29708 30104 31270 63878 64050 31289 63663 31348 31724 63890 31444 31013 64035 31091 29885 63469 63895 64311 30026 30154 63908 62550 31227 30033 31146 30381 64483 30365 30402 64059 64191 30423 31154 31184 63578 30856 63163 31645 30315 62804 30425 63225 30266 63746 64498 63976 30095 29786 31066 64498 63382 62574 62585 62700 63824 63311 30711 63861 62977 30905 31562 63094 30330 64007 30472 31187 62829 30804 30475 29723 63310 64286 30994 64466 31717 30018 30253 31413 29964 64358 64228 30781 30652 31078 63121 62792 30895 64077 64413 30292 31724 64203 62846 63716 30215 63770 31710 30164 29988 63535 63672 64025 63459 31390 63767 30190 63780 31593 64170 63501 31734 63322 64479 63529 63091 64127 31528 31453 30176 64296 63736 30301 30526 64028 64090 30138 64125 63827 62588 30358 64117 63842 30995 62963 29829 29779 63331 63197 30458 30250 63452 31465 31662 30853 63087 31438 30786 31367 63654 64421 31287 64320 64266 31548 31446 64275 62863 63147 29905 31244 63873 64398 63933 62940 31071 30299 63128 63120 63563 29746 30739 31109 62983 62789 30137 31216 30222 30513 30982 64158 62997 31394 62510 62968 30205 63672 30365 63197 30787 64050 63141 30822 30223 63218 30060 63186 63876 63606 31455 63374 63030 62876 64229 29914 31176 63159 64073 30496 30683 62817 63259 63816 30362 30912 30676 31106 63912 30799 62680 30792 62617 29752 31013 30642 63739 63683 64190 30855 63324 62786 31420 31311 63556 63322 31234 31201 63124 31412 63895 31343 30008 63245 31553 62888 31214 29947 30041 29832 30117 30841 31123 29706 30541 62830 29921 29921 63046 62841 63621 63955 63449 30743 63089 62692 64111 63974 31499 63335 64427 63960 63988 63372 63541 64362 31567 30901 64278 30682 30622 63775 30795 63268 2139095039 2139095039 +1024 64034 30747 31173 31237 30410 29936 30468 64156 30138 30652 30873 63070 30593 63564 30343 62903 63053 63123 31171 31313 30311 63746 31374 30271 62504 63405 31026 63413 30727 64193 31359 62829 30283 30175 62521 29935 31619 63335 30216 30519 30505 31469 30689 29846 30998 30227 64000 30081 30932 31457 30699 63935 64005 62566 62793 63625 30072 64170 30237 29968 62665 30625 31015 29721 63086 63821 63156 62590 30983 63363 63750 30021 29845 31170 30963 63881 30969 62531 64293 31451 30856 63729 63838 62544 63564 29745 63743 30771 63122 31716 62521 63327 62691 64463 63432 31718 31221 63149 63001 63149 29933 62744 30520 63743 31645 31002 63910 31668 29864 63622 63776 63059 64263 30437 62759 29764 63786 30149 30868 63015 62872 63330 64055 29783 63408 63486 31275 30730 63137 31134 30484 63809 63120 30656 31735 31028 62835 30894 63549 64260 31695 62809 62590 31524 63713 30103 62490 63362 62966 63051 64481 63646 62911 63313 30451 62765 31583 30493 64118 30381 30408 63809 30758 31515 64075 63718 63134 29960 64256 31521 62598 63054 30829 30871 31422 64484 63541 64308 62558 63759 30026 62539 63903 63998 62662 63789 63522 64488 31324 30168 63696 30124 31187 29964 30875 63045 64015 64112 62477 62751 64350 31521 30327 31358 63498 31426 31065 30081 64380 31050 62993 64099 30907 30495 62576 30942 30211 64329 62609 62663 31733 63733 31080 63648 31474 31269 63552 63132 30012 64501 62727 30085 63055 63115 63602 64313 30958 63392 64477 29932 62830 31181 29950 63521 62484 31342 30342 62960 63985 29839 31634 63251 64031 63475 30006 63015 63364 31171 30489 63709 31119 63309 31375 30303 31346 63070 30179 63122 29786 64001 30646 30400 31169 62886 64136 62622 30367 63843 62984 62644 31413 64310 31026 31481 62468 64043 64359 30118 31684 31520 30237 63836 63060 62898 31144 63127 62554 31135 63954 64458 62515 31399 63015 64055 63970 62473 63107 31463 64453 29950 64014 64159 63061 30037 31601 62585 64108 62852 63384 62771 30167 63763 64167 29999 31438 29922 31526 29791 30107 63730 30284 31285 63627 64091 31319 30556 63780 63162 62523 31727 64029 31181 63121 30354 29971 30085 62623 63742 30364 30590 30196 30067 31616 64473 29778 30918 63392 31093 30960 63692 63675 63627 30196 31311 29976 64073 30126 30842 30827 62623 30841 30819 31153 30029 64096 62861 63987 64145 63533 30911 64502 31614 29822 62765 64072 63064 63002 64379 31722 30628 30541 62753 29854 31260 64032 30352 31011 31534 30428 31075 64150 62520 63098 64511 63548 30977 63316 63930 31699 64149 29714 30506 31635 63676 62823 30736 29992 63452 63360 63653 63368 30600 64483 62645 62684 29730 29790 31447 63767 62685 63595 64099 29824 63488 62549 63567 62705 30012 63711 63716 31171 31218 62569 31060 62943 63759 63204 29705 64051 31368 30678 31535 63532 30102 31196 63927 63989 63986 29767 63548 31245 63551 30260 31501 64210 62978 64415 30375 64034 29809 64283 31234 30698 64262 30453 63815 63053 30460 63082 31167 29981 63723 29908 64367 30566 62953 29966 30678 30372 30112 30794 31360 30329 64048 63583 64203 63236 64287 63729 30759 31364 63668 30713 64418 63983 29758 29913 30263 29992 63127 62981 30761 62736 64484 63965 63455 30552 29728 62837 31092 64192 64451 30857 64138 64217 64338 63631 30996 30377 29852 64129 29824 30951 31382 63031 30418 30595 63107 64306 63612 31211 31231 29704 31730 31241 31299 62935 63594 30463 31428 31431 64257 63008 30807 62510 31523 31612 31657 31087 63488 29735 62994 63187 64052 62788 63729 64039 30234 31071 29786 31574 30985 30128 63852 31394 62948 64181 63990 63062 31420 31177 63136 29789 63187 30892 63549 63853 30904 30447 62845 63055 64024 30714 29758 30738 62666 64119 30632 30458 63960 31661 62474 63406 31486 64271 29852 64136 63847 63430 31314 64054 30242 63336 63571 63786 63787 63348 30302 63522 29876 63482 30159 30797 62901 63994 64501 29830 29741 30587 62527 30909 31261 30471 63214 31446 31020 63106 30263 30197 62586 64183 30264 62876 30785 63398 62799 31154 62529 63744 63020 62471 62848 62486 62896 63351 31276 64306 30094 64453 29698 62506 30348 31117 30932 30962 64044 63002 30428 63784 31094 31324 30786 62674 30768 64290 30662 30812 64252 62487 31726 31319 62545 64226 30623 31086 62708 31220 31192 63633 63931 31608 62967 64163 62519 31405 31714 30231 30011 31107 31740 30090 30459 62575 31564 62992 30715 63533 62757 30941 63237 31227 31601 30013 30249 63930 62670 62814 64085 30353 30140 64310 63586 63892 30571 30404 63745 64150 29873 64009 30682 30075 62935 62681 30417 63685 63460 62888 64280 62513 62579 30325 29923 30724 31620 31412 62980 63159 62763 31260 29749 62526 62636 63603 31119 31493 63387 63930 30797 31614 63631 30495 30193 63773 31403 30724 63936 64194 63954 63355 62985 31149 63984 62824 62876 30943 30164 62601 64081 63090 64406 31549 63431 63397 62620 63553 30142 29970 63689 63091 62562 62731 31665 31213 64209 64405 64273 64483 64344 31031 63680 63978 62491 64379 63186 63114 62759 31294 63040 63576 63720 31347 31424 31601 63761 29926 30780 31279 64403 64241 64174 63364 30662 64181 63647 30221 30515 30586 63571 64259 30727 31234 31401 30856 62718 30303 62954 62898 30045 29785 62886 30672 30400 30091 30586 64191 30462 31672 62730 30762 63106 31346 31568 62582 64489 64396 31455 63134 30978 63359 64209 63742 63503 29784 29971 31168 31494 63801 30203 30734 63353 31087 64089 29800 31640 63457 62502 63233 30053 63877 63255 31006 30303 62863 62805 62976 64466 31532 63858 63291 62612 63249 62643 62739 63717 31358 30155 30585 63679 31242 30133 64364 29829 62710 31576 30094 63253 30108 63951 31602 29798 63992 64393 62565 62551 30631 62616 30535 30916 62893 62485 62783 31050 31735 64426 63424 29959 64100 30209 31201 30219 64375 63115 31238 63419 31152 29845 30175 31463 31367 30502 30295 31238 63055 30719 30501 62642 30849 30754 30277 29899 63797 30242 29885 63483 31156 30479 29885 62845 30732 62804 31000 62654 64458 63483 63226 31721 31394 63290 31524 31553 63862 62795 62909 30926 31194 64109 63800 64046 64231 30412 63603 62834 30007 31027 31452 30253 30211 31693 30474 64440 29752 63375 63256 62854 31207 62566 62663 63421 31633 62669 31553 31330 62718 63479 29884 63724 62601 64071 31469 30235 62535 30051 31317 30547 30377 62692 63958 30824 64320 30820 64182 62590 63213 63831 31370 31419 62790 63746 62491 30258 64073 31230 62845 62829 30053 62769 62844 29717 31642 62868 64139 63075 31484 62522 30711 31228 64382 62643 63048 63323 30739 62810 64311 31164 30098 62845 63431 62868 62616 63875 30031 30476 62657 30056 30213 64211 30151 63242 30415 30267 30161 63597 31486 30556 31673 64450 63347 63004 30355 64256 63776 62628 30788 64476 63920 63963 29766 29773 64258 30914 30834 31382 30637 30284 30103 63815 30907 30607 62692 31280 64269 30855 62555 30218 63330 62938 31344 31326 30790 62964 63998 63261 30261 63192 63300 30808 31484 30520 64152 30398 31203 31197 30707 63070 63903 64509 30211 31359 64119 63228 31452 64096 30976 31550 63286 64132 64383 62999 29824 30697 30864 63147 63277 62843 30553 30734 62632 62484 62507 63359 31520 29946 29931 30197 63833 29722 31246 30621 31260 30951 63288 30073 30708 30193 62676 64384 30069 31155 30653 63524 29911 64371 63085 63509 63932 31201 63287 62522 30034 31495 62534 64185 30363 30064 30328 63524 62629 30024 63294 63670 62806 31455 30608 31691 30246 31159 29769 29819 30547 30411 30955 31555 29871 30943 63063 64354 30035 31031 30527 30154 63670 31397 30911 30397 29837 63435 31265 63937 64105 29840 63176 29866 62780 30511 63206 30139 30350 63474 29984 63740 30147 31055 31289 63802 30564 30696 30177 29980 62944 31534 63490 63768 63007 63029 29869 29920 30767 64081 62785 63662 30064 31488 31127 62695 30184 63985 31589 64298 63307 30697 62584 62586 63783 31640 30995 64238 64164 30966 63389 64399 64327 63394 30847 62785 29884 29971 29888 30894 64141 64138 30026 63795 62946 63203 64400 30329 64223 30075 31725 63179 64385 30949 31644 29878 64226 30778 63815 30643 29974 31389 30849 62862 30841 62513 63334 30936 63942 63970 30358 29740 31233 30012 30926 31627 30852 30582 62876 30990 63814 31488 29782 29804 63564 62698 30838 29894 30505 30344 29775 62570 30326 63811 63522 30283 30662 29823 29946 63291 29926 62597 63251 63880 63682 64315 63382 62821 30174 30473 29907 30496 30211 63801 62657 64433 64297 63847 30659 62662 31347 62748 62630 29811 63872 62543 31495 62894 62639 30574 31195 63379 62476 30720 63284 62746 31689 63158 31367 63965 63380 30280 31118 64206 31606 30012 31545 31171 62504 62677 30218 31662 63936 63754 31433 30037 62579 63362 64269 62969 62766 62891 63888 64158 64155 62943 30205 31179 31121 64361 63809 29835 30297 30711 64504 63678 63777 63997 62724 63461 63288 62860 63278 30651 30483 64130 31294 64336 64023 30926 63343 31412 63930 64372 30310 30260 63836 62541 62500 30170 62785 30783 31332 63269 64467 29890 31240 30055 63742 62747 31426 31649 63078 29829 31605 63767 30251 30274 31152 62891 63115 64406 63595 31324 31441 30458 31738 31727 30821 63418 31710 64103 63292 30413 31494 31630 64451 31033 30858 31071 63894 31690 30058 29782 31336 62465 29901 62840 30856 31621 64240 63724 63334 63350 63773 63721 62739 63195 30240 63769 64233 31535 64204 31704 63426 31072 63170 63063 64000 63515 63204 30506 31317 30748 64353 29827 31707 31389 64095 63467 31374 62827 64300 30454 64309 31431 31296 63594 62580 64056 30111 30719 30350 31247 30870 30478 29863 63038 29989 63655 63388 30592 62743 29876 30514 64187 64152 30883 62937 29726 64163 63552 29772 31724 31478 30407 31242 31011 30398 31676 64155 63871 30046 30368 31701 29773 63766 63740 64376 30222 31121 62930 30639 64059 62547 30509 63476 30876 63369 63607 29700 64395 63429 62491 63920 63937 62575 31593 30536 29837 31289 31518 62653 64001 64346 64151 29918 30010 30720 62778 63520 62700 31371 62938 30143 30701 31659 62765 63027 63402 31348 31133 30563 62726 30027 30164 29934 62773 30220 64106 64456 31181 62860 64279 31612 63124 29819 30333 30412 29893 30083 63945 64413 31570 62791 30471 63043 62588 63383 63589 31641 30569 62780 31692 30433 29852 29811 31424 62834 30456 31712 64026 30318 63247 63560 30812 64022 30031 63896 31123 63878 64041 30119 64474 63830 30484 30840 62516 64486 29803 31055 30287 62695 62512 63389 62520 31642 62779 29892 63126 64250 63458 31347 31404 62704 31168 62973 29981 64478 63388 30800 30798 63548 63513 30659 31313 62737 30100 31519 62899 63065 62754 64445 64268 62588 62557 63805 64404 30716 31138 30342 64385 63563 31376 30353 62573 64453 30538 30045 62745 63484 31306 31436 63819 30241 63230 30349 30143 62966 31493 62752 29825 62655 30342 63101 64458 31504 63465 29992 30811 63540 31436 30149 64345 30102 30817 31587 31152 29863 29704 31234 31526 62643 63475 63349 62975 30041 31557 63781 30575 62868 30804 62532 64263 64128 63010 63493 64368 30575 63603 30961 63232 29856 63605 30322 29830 64511 31563 63657 31222 63080 30734 64466 30769 31508 31722 63148 30814 63125 31426 63772 64403 63829 62955 63790 64150 62833 31646 30330 63569 30809 63938 63122 30978 63583 63621 31435 63476 63586 30550 31462 64027 30678 63471 63279 64151 30426 63472 62804 29999 62568 30673 63104 31260 31092 63915 29834 31577 63712 63597 30775 64332 63708 62858 29977 30939 63584 64040 31158 30225 29993 31441 64155 63280 63560 31070 30601 63907 30504 62782 62919 30506 62873 30594 63737 30366 64249 62961 30093 63950 31595 63593 31615 29860 63798 30806 31370 31096 63134 31083 30592 30069 63151 30377 63670 63724 64346 30457 63515 62972 30781 64275 63353 31348 63777 62549 64055 30746 63766 31171 62721 64106 63956 64410 63280 30237 64254 63303 31172 29993 64425 31365 30116 64111 31316 62588 63560 64174 29952 63394 64199 30699 30455 64272 30900 29917 64114 63919 62696 31042 30635 63063 31080 31289 30713 63549 30350 62493 64121 63575 31245 31691 64389 30083 29885 63733 63704 63059 62825 30699 30773 30480 64412 63850 63760 63698 30380 31494 63857 63292 30224 29783 63237 31220 29961 62951 31334 63243 29952 30988 63482 30670 63619 29964 63029 63159 63745 29977 31253 29749 30913 31129 62685 62868 63710 64339 31090 29866 63930 29860 30444 31009 62703 64487 30648 62644 31608 64277 63622 63628 63702 31188 63599 63896 31426 64427 63385 63887 64353 63039 29876 31309 62930 62655 31418 63054 31187 63879 63596 30035 30035 64312 30811 31574 31282 31182 63022 62846 31308 64485 63986 64382 62572 62596 30477 62589 31535 30935 64234 62554 63141 63726 30351 64221 30914 62779 62643 64353 63765 63496 30167 63883 63396 30337 62574 63410 31103 30431 31611 30611 2139095039 2139095039 +1024 31628 29991 63014 30486 30194 30706 64160 64340 30067 30551 63721 31617 64407 29826 63307 63406 30417 30359 30054 64508 31507 63015 31538 62831 63922 29828 31214 63991 30061 62567 31477 63068 64252 63066 30693 30518 31363 30371 31684 30936 63507 63683 31542 29825 64113 30078 30235 63352 30519 31657 63275 64260 29785 30272 64043 64506 62733 63749 30178 29734 31231 63829 30690 30934 29749 64252 62757 62721 31173 30676 64175 62994 30708 63381 30993 30608 30550 63984 64495 62668 30395 30066 63716 63042 29844 31554 31727 63689 63287 64403 30312 62755 64356 62848 31649 30684 63767 30305 30743 31739 62531 31341 63791 31270 63995 31598 64232 63200 30069 63545 30519 31119 30738 30170 30592 31303 30074 64270 63902 30950 62672 64188 31185 30055 63940 30665 64105 31647 62801 63135 62742 31188 30591 63655 63356 30712 62963 29866 30072 64254 64184 64013 63809 63925 62940 63922 31177 63268 31200 30608 29751 31295 63769 30577 30822 64506 30032 31162 63168 30407 62786 30241 31273 63599 29981 30857 63174 29954 63251 31409 63679 63219 30989 30777 30096 30760 63146 63415 63731 62621 30552 31294 29734 63460 29933 30243 63505 30259 30642 29859 62506 63029 63832 30537 63309 62618 30109 63961 30036 31255 30759 31538 63366 64124 31578 30221 29796 63632 30959 30402 62966 30412 62723 30177 64257 30600 63405 31488 64344 29800 62770 30697 63593 64373 63303 63496 31570 63910 63361 64249 62775 30184 31288 30107 62652 31513 63480 62833 64004 63708 62615 31645 31350 31484 64492 63397 31701 64305 64237 64214 63674 62775 31139 31687 64073 30288 31277 30789 29956 30954 30478 30036 30133 63775 29702 31364 30940 31574 62640 29953 31482 30069 63973 63501 63223 29997 63323 30625 31030 30697 63754 30450 64312 31115 30824 63101 29741 31143 62940 63623 63968 62930 62524 62757 63977 31666 29925 30323 64340 62752 63705 63094 62580 31437 31682 31223 63603 64126 64087 63619 30555 63557 64239 64066 62593 31685 63441 64234 63779 31659 64041 63615 63881 30946 63385 31607 62697 63692 63782 30448 63207 64080 31573 31592 62633 30968 64290 63187 29960 30284 62656 62803 63241 62488 31688 30383 62887 63629 30237 62658 63745 62466 62830 29827 64399 63110 63841 63395 63201 29758 31642 63011 63365 64135 64459 64366 64275 64144 29874 29937 30619 30110 29962 30686 63901 62556 31023 62792 30321 31540 31371 63804 30893 64038 31004 30756 30970 30899 63693 64172 30796 30685 64451 63349 31347 64169 31082 31599 64399 31081 31076 63557 31507 29744 31452 31222 63684 62723 30343 63575 63292 30460 62958 62876 30977 64048 29793 30616 31389 64464 31421 63818 30780 31497 30289 31488 62570 63919 30962 62910 30273 30540 30939 62879 30633 29937 63720 30361 30921 31351 62873 30174 31381 30851 30557 63694 64232 30592 64377 30427 63137 30291 62847 30688 30367 62776 31378 62887 30890 31251 30287 63768 64283 29882 64101 30594 30298 62815 63171 30056 30621 63513 63103 30849 30005 64167 29727 31567 31632 30247 30631 62987 31049 30868 63040 62710 30416 62608 31100 31347 30583 62698 63992 30080 30212 62578 31072 31189 63782 62949 29816 63764 63926 64158 64069 30306 63602 62565 30355 63759 63459 63025 31280 31714 63681 31197 62620 31114 29907 63931 64099 31278 64087 62754 30045 29927 64346 30787 63840 30912 63428 64494 64204 30181 29795 63261 64343 64231 64387 29739 64025 31348 30425 64020 63994 29870 30722 63661 29703 63536 31382 64108 29825 63648 31654 31264 62756 63170 30349 62764 31507 30757 64472 29726 29855 31120 30217 63418 31439 31334 64172 63530 30578 64418 30023 31092 30166 30717 63221 29891 31322 31200 62805 31353 63167 63808 62629 63391 31581 62567 30616 64089 62547 63818 62669 62626 63204 30526 62569 63106 63435 64510 63411 31220 29918 29780 64467 30026 31631 30107 63807 31088 64325 30541 31111 30596 30761 63558 31106 63151 63329 31367 63286 30924 31677 30447 62757 63168 64317 64406 30289 31570 63089 31028 64423 31462 64154 62511 64246 29749 31183 30481 63421 31601 64310 29702 29785 63174 31112 63544 63802 29881 63382 62630 63271 30535 29931 31056 63116 29973 62655 30871 31681 30205 62736 30131 30510 29970 63211 31261 30322 29798 30055 63204 64350 62775 31113 30750 30393 63512 31629 29929 31131 30205 30609 30524 30316 64503 63731 30911 30398 63258 63035 30787 64252 30594 30771 64198 31317 30782 29887 63778 62945 63046 63170 31376 31566 31431 29995 30421 64397 63256 29703 29847 30320 31508 63474 31008 62613 31058 31448 64498 63355 64470 63161 31402 31600 30231 29845 31463 30044 63368 30330 31042 31047 30254 30340 31032 30941 31385 62549 63706 63435 29965 64416 62645 64038 30856 30716 63536 30223 64108 30371 62497 29850 31441 63447 63288 62664 63623 30964 62885 63994 30872 30649 31505 62769 62685 31203 30375 63462 64479 63137 63380 31205 62921 30186 30772 30064 64430 30915 30412 63051 29819 62902 63394 62757 30157 31074 29892 63217 63157 30270 63936 30456 31048 30603 63754 31648 30279 31735 31557 30459 31398 64450 30436 31160 30306 62512 64194 31450 31379 30690 63751 63976 64118 29887 31451 63651 30561 31447 30807 63955 31240 29914 62583 62600 30506 30824 64499 62828 31376 63927 64337 30286 29909 64154 30007 63188 63245 62466 63214 64475 31226 30544 30164 63351 31474 31645 30676 63688 30811 63911 31004 31041 31702 31279 30446 30503 63734 30371 63239 63420 64337 62683 31113 62945 31415 31316 63796 31628 31404 31457 31401 63146 30121 30083 63360 30256 63960 63559 30145 63996 31369 31287 63656 31069 30734 30439 64092 63073 62613 63154 30741 30864 62646 64266 64389 63208 31432 31406 63048 63269 30226 63710 30341 63785 30671 63257 64440 63225 31600 31013 63653 30809 29720 63838 63464 62992 29838 62694 63006 31347 63052 64369 63576 30192 30464 31554 31688 62605 64156 63517 63614 30127 30517 31080 63153 63035 63147 30199 62944 63139 31317 63052 31570 31387 30445 62473 31462 30810 31653 62906 62816 30663 31541 31051 63326 30134 62938 31474 63499 64303 63187 62512 62641 62937 31330 30657 63420 62853 29834 64047 63596 31390 64295 63969 31165 62874 63809 30460 64203 63669 64089 63065 29769 63522 63207 63679 62680 30433 62660 63831 30683 30502 64237 64275 62947 63908 63778 29973 30086 62816 63496 30920 30090 64220 64150 29789 30604 31013 31690 30191 63283 64204 62962 63877 64080 64076 63576 30681 30524 63881 31622 30357 63990 62954 63631 31437 62969 31296 64256 63367 30236 31286 64463 63887 63788 63610 29939 63135 62952 29842 31513 63527 31732 31392 63482 30794 62641 29920 63619 31352 31491 63416 31578 63766 31183 62464 62469 63583 29953 30134 31203 30909 29925 63129 64156 62604 63887 63453 30370 63854 31307 30942 62820 63570 30289 64063 31146 64112 63927 30591 63930 30292 62769 30378 31539 30348 62535 64454 63404 30241 64348 63142 30504 30194 31111 30750 30452 64173 30399 30124 63092 63771 62794 62485 31229 62466 63701 30579 63461 30810 62896 62752 31319 63166 30878 30532 30402 63621 30400 31187 62667 63733 62771 29880 63672 31329 31200 63886 30350 62884 64093 64407 29982 30841 64187 63506 62565 31350 30562 63066 63933 31209 62815 29957 64314 64310 29726 30399 62919 64473 63805 64021 64160 29900 30994 30426 29778 30066 30864 30004 63194 31143 63537 62576 63261 63485 30828 63376 63715 64506 62753 29832 63077 31657 29798 30088 63635 29984 63894 30866 31243 63075 63475 64083 30918 29976 64007 64023 31013 62557 64452 62508 63450 31162 63006 31697 30279 63345 31029 63069 63394 31541 62501 63687 63418 30440 63409 63897 30597 62727 64069 63370 63314 63316 63538 30195 62572 64193 64041 63844 31589 62951 31294 64445 64084 62732 64143 63837 31012 63411 63635 31290 63126 30314 63749 63767 63647 62605 63421 63426 63574 29851 62920 30979 30416 30808 29727 63746 63797 31606 64077 31293 30040 30181 62932 63424 31517 63653 62642 30764 64484 30455 62961 29762 29996 29928 31476 63668 62772 30091 31572 29801 30163 62704 29908 30705 62952 62947 30251 31678 63793 64454 63352 63516 64011 63045 31579 30569 31599 63705 62984 31288 64317 64057 63124 29977 31546 63141 30083 30548 30548 62950 30885 31027 31579 29993 64317 31560 63285 63645 31539 31468 63443 63009 31679 63797 62620 64404 31232 63198 30183 62895 63365 31174 31230 30858 63464 30599 62742 62652 31384 30685 30484 62468 63982 31726 30345 31558 64225 30845 63871 31722 31348 63444 31117 30444 64325 30781 64071 30468 64302 31532 30037 62506 31562 29773 64107 64489 62877 63886 63571 62553 62843 30938 31703 30296 30196 63507 62515 64247 63187 64414 62812 64161 29799 63639 62540 30435 63799 30142 63357 31047 63739 63005 63955 62547 63166 30905 31122 62517 62629 62474 30852 31090 64391 64209 30654 31420 63117 30470 30521 31095 62580 29843 30185 63102 64328 64167 30583 62741 64266 63762 30448 30302 64124 63550 30252 64211 31541 30283 63697 63281 31129 63264 64429 31368 30192 30477 63838 31377 31116 30096 31474 30779 31208 31611 63337 31436 30841 64009 63676 31067 62598 62469 30347 30189 29801 30631 64448 30806 30983 62822 63733 63457 31383 63090 30657 31422 63548 62987 63248 31743 31493 30204 31663 30296 31485 30461 64075 31694 30520 30889 63607 64053 64077 64272 31709 31655 31185 31547 63158 63599 62981 62661 30603 63534 31361 63121 64411 30147 64258 62639 30289 62989 63497 31720 63169 63311 63345 62942 30668 29968 63434 31118 29988 62957 31071 63408 64051 30449 30274 31065 64180 29883 63909 64471 30265 31617 31122 62978 29764 64333 29801 63564 62730 64325 31159 30202 63726 64426 30150 30859 31097 31316 30838 30205 64133 31419 30228 30376 63124 63792 63237 64460 62657 63146 62670 63850 30203 63784 63152 31093 63562 31151 30546 62563 62800 63068 30452 63634 30294 63404 64109 63867 31609 30261 31129 29980 62972 30706 30181 62551 63305 64101 63377 62771 64100 64076 30433 64270 31707 64258 30789 63903 62997 30367 30359 63473 31274 64078 31329 30671 30910 63040 62489 31738 30092 31028 64097 64061 63752 62843 63113 63523 31549 31680 63685 31221 31613 30990 62976 64023 63836 30648 31670 29792 29862 30311 31508 63049 63881 63156 63124 63360 30314 31161 29705 63640 62799 63470 31623 31570 31714 62889 31176 31521 63514 31589 62520 63475 62732 30004 31126 31575 64025 63939 64060 63772 64383 30085 31417 31459 63236 63972 62482 31690 64088 30453 62983 29878 31107 64438 30970 30551 30227 63271 31044 63426 29973 30000 63312 64121 31405 63281 63870 30460 64237 31693 63964 30310 62523 30144 30810 62556 30314 31274 63429 64098 31622 63615 63908 62814 30388 31414 30458 63827 30293 30999 63452 31704 31079 30312 63784 30854 64292 62514 63271 63097 63126 64157 64498 31134 30743 64145 31540 63921 62910 63936 62854 63747 64511 30488 63736 30837 62781 62711 62858 31256 63608 29787 63304 31116 30605 31300 63192 31603 31446 31123 29808 63348 62693 64430 63876 62553 63128 64310 62882 63640 30327 64253 31666 30570 30843 30175 31222 62779 62597 63545 30299 62955 64302 64299 64409 62764 63591 63330 64391 31346 30663 30981 63796 30777 63970 31660 63621 30913 62522 64242 64073 62677 62714 31239 64467 63002 64229 62840 62837 30038 31287 63351 30355 29800 29957 30206 30205 30346 31263 30400 31337 63379 31486 30832 31106 63153 63934 63107 62743 63905 31478 29765 30348 30286 29900 63759 63997 62567 62872 31133 30009 63253 31295 29852 64476 30969 62633 30351 64212 31324 63945 31008 30359 63048 63927 63978 63297 30281 63814 30422 31394 64277 63637 64386 30687 30216 63463 31068 63745 30091 63623 63308 62743 63388 63103 62684 63896 31500 63498 30891 30613 30830 62624 30647 62652 63137 31241 64110 63440 62862 63642 31543 64123 29881 30853 30300 64361 30374 64371 63496 30533 63174 64435 63122 30925 30124 30470 29745 64475 31093 31168 64333 31078 63239 63217 31698 30918 62890 63581 62874 30840 64339 30916 30653 64128 31663 64233 31657 63695 64043 31118 31459 30808 30697 62476 62552 63384 30612 30781 62533 63729 30627 63185 63385 30291 63237 29800 30511 63495 62816 31038 29944 62863 63820 30523 31260 30990 30467 30810 62960 63788 30193 63075 64024 63554 63340 62661 30577 63137 63639 30151 30120 62742 30627 30276 29738 64412 30740 62712 30401 30432 30100 62478 63274 62867 62464 63972 63724 31535 31465 64222 31439 63459 63971 64324 64403 31325 64432 63065 63963 30079 63900 64247 63143 29958 31379 64120 64026 30089 63967 62603 64493 62849 29848 63550 62825 62671 30122 31653 29927 62677 62630 31041 63852 30222 30277 63680 62689 63712 31262 30501 31148 63957 62818 30697 63279 30195 30446 62811 30782 64168 30085 64372 30061 62976 30529 63953 30191 30840 63388 64031 30615 64386 31381 62956 62838 64376 30695 31049 30656 62466 62832 31680 62951 31273 30392 31172 2139095039 2139095039 +1024 29719 31091 62628 30274 64014 31691 62821 29861 64147 30073 30683 63532 64074 63224 29982 30795 62719 63886 63980 29817 30435 64015 63228 31113 29765 30726 62716 64301 64207 62475 63680 30551 63800 30118 31359 30738 64113 31626 62510 29812 63780 30385 64148 31157 64295 64067 30348 29889 31064 63116 31491 63864 29949 30700 31363 62674 30256 64174 63931 63213 30370 63852 30485 31036 30684 31146 30329 29955 30440 63508 31254 31321 63653 31453 63103 31154 30667 64313 63315 62680 62708 29891 30327 62477 63891 31344 64361 30906 64344 63194 29911 31736 30933 29899 63047 30214 62784 29890 64323 31070 30375 62654 63097 31257 63890 30243 63173 63312 29913 29930 31240 64460 31704 63989 63171 62479 30485 29772 31298 63132 63654 64316 63319 63866 63695 31404 62925 62781 30565 31724 62545 63403 30813 63246 63967 64428 31218 30079 31252 64074 62873 31642 63753 64281 62948 63233 30228 63166 63271 31329 62693 63565 31088 30495 62696 30000 63242 29824 63221 30127 62501 62970 62913 30687 29746 64008 63848 31262 64376 63039 30392 62595 64277 31045 31721 62537 31467 63871 62630 31015 62871 30882 31737 63198 30921 63112 31363 31324 29905 30337 30065 64125 63175 62599 62940 31242 62740 30793 63551 63096 64173 62595 30016 30469 30096 64075 64063 63924 30824 30982 29793 62651 62778 31148 31289 63692 63732 64180 62521 30262 30783 64165 62633 30930 63975 63223 31363 31367 30912 64358 30689 62939 62490 30651 63854 62616 62493 63879 30582 30964 63951 62556 31278 63520 63294 31199 62574 30043 30439 62826 29711 62701 31282 30054 63272 62621 63972 30712 31532 63057 63989 30133 31365 64370 30740 64205 64323 64390 30843 29935 30039 31033 30035 30503 62476 30395 63214 30314 31007 31179 31052 64108 63672 30364 62778 64372 30400 63137 31665 29892 63740 30701 31721 63760 62729 30794 63605 63552 31317 30369 62708 29958 30076 64152 30355 62983 31312 31416 29779 62823 30059 64043 30957 63714 31100 62932 30965 63710 31163 64334 30514 29942 63515 30254 63400 31595 31371 30972 31315 63164 63370 64468 63264 62740 30892 31640 62655 62638 64268 31201 31230 63231 29779 64014 62724 63989 62780 63762 64287 64384 62642 31470 30117 31059 63679 31183 30528 64355 30769 63526 63890 30283 29987 29924 63986 31514 30985 63721 63314 30055 63025 30267 29963 30348 63594 63909 63390 30276 30754 63591 63710 63843 62980 62795 31477 62586 63535 63080 62988 62710 31174 29733 31420 63819 31393 64043 63445 30217 63188 29773 30406 30424 31513 63135 30112 30197 64057 29876 30770 63037 31312 30740 63980 62748 62535 63509 63017 29697 30723 30309 30408 31015 30207 63030 63190 63405 63170 29709 63124 29855 63698 64089 30950 63188 31504 31452 63621 64347 30644 30890 63605 64509 64235 62469 63260 30886 63478 30779 63931 62930 63740 62547 30082 31458 63470 63917 31681 31173 63543 62467 63117 30364 29831 63624 31690 63783 64150 63269 63711 63429 30829 64369 31242 31631 31142 64346 62789 30482 64096 64048 64459 30559 63917 30898 62586 30196 63634 30507 30150 62749 64328 31315 63786 62659 30229 29919 64490 63797 63503 30065 30048 62912 62946 63101 29932 63728 30721 64043 63199 31437 62549 31378 63248 64089 64079 30974 31362 29974 30119 64003 63845 30257 29794 30518 62879 62658 64325 64266 63020 30683 31133 63607 63555 29760 31653 31663 62642 29800 30626 62670 64383 30082 64368 30943 64288 31257 62570 31317 30184 63637 31356 29948 63741 30024 30724 31570 31530 31193 63234 63916 63154 63580 31663 31621 30548 29725 30386 31350 30417 31378 63640 63359 30889 31605 31193 63674 63317 63825 62957 31141 29771 30695 30347 29753 30593 63157 62571 30881 29985 30701 63280 30187 31058 30777 62784 63193 64254 29996 63241 63430 63328 64317 64270 31015 63863 63477 64027 31464 62733 62672 63006 30561 63123 63273 63998 64425 30254 64215 63433 63383 63001 63993 30655 63584 30636 62525 31522 63556 31429 31219 63425 31071 31269 30496 64014 30382 30436 31521 62840 64425 31204 30421 30757 31627 31455 30573 30742 29993 63301 64198 64028 63513 30166 63063 64212 63183 62501 62557 29837 63138 62916 63166 30164 63958 63412 31493 62600 63308 62690 29989 30817 30185 63124 30063 31363 30616 30573 30889 64190 30867 30638 63923 63610 30688 29951 30232 63836 30831 29717 31566 31648 64218 63659 64328 63787 31291 64043 31144 63822 30810 64117 63336 63208 29878 62519 29870 30458 31529 63349 31265 31367 30638 30659 30589 64348 31257 63528 31231 30889 62825 29713 30693 31721 64196 30577 62828 63673 63641 63823 31056 63391 30201 30402 62615 31533 31269 30606 64465 64139 30358 29704 30508 64468 31464 29870 30825 30836 30629 30211 63999 64307 31464 31471 31516 63277 31384 30061 63302 62860 64307 64233 64483 30666 30083 29780 30027 31454 64008 64011 30079 30668 30239 30412 29716 30897 30424 31042 30906 63798 64509 29796 62649 30933 30547 62966 63239 30704 64347 63119 62829 30644 62471 30866 30594 29708 31183 63389 29989 30099 31056 63345 31469 64258 62643 31387 31494 31724 63076 30591 64380 63772 63799 29801 31494 62817 62746 64001 63462 63884 31193 30847 62684 31480 31181 64434 31440 63952 31403 64254 64000 64071 29779 31597 63780 63412 63490 63262 31738 63982 30843 64330 30284 64154 63421 63915 29724 63962 63242 30098 64354 30081 62628 31507 30644 64132 63664 29886 30191 31726 29730 30531 63874 63547 64442 30310 30676 62593 31376 64505 30248 62682 62668 63097 63258 31714 30403 31435 31189 64033 30816 30369 30515 64116 29932 63306 63942 63057 63747 29905 64219 30223 30126 63869 64328 30812 62974 29934 31098 31120 30687 63701 30632 30452 31146 30998 63603 31398 31484 30779 30791 62652 63659 29872 62502 29833 62709 63651 30388 31124 31716 62552 63834 30221 31652 63302 31585 30905 62514 30138 30652 63649 63275 64320 63454 63581 63636 31148 31669 62527 30101 30335 63533 64423 31115 30853 62866 63734 30462 63501 63770 30974 63995 63141 64505 31001 30561 63930 62770 63640 63519 63442 63838 62975 63381 63759 63721 62851 62522 29941 31003 31186 63528 31590 31585 62822 63929 31511 30875 31067 30439 62690 62895 63283 30112 31613 30416 64058 31732 63930 30556 29965 62958 62519 62566 30017 64027 62774 30782 64176 30341 31128 30926 30374 64110 31338 64118 64449 31741 64307 62486 31195 30844 30697 31044 63368 64130 62874 63639 62812 62837 63975 63723 62754 31426 62847 64204 31097 31594 63122 30508 29759 31551 63029 63479 31419 30364 63259 29996 30222 31311 62773 29779 64410 62755 31237 62602 63385 31179 62844 30016 30725 31652 63657 63544 29904 62654 30565 30423 64361 62542 63465 30515 62947 64496 30129 63043 30895 63374 30571 31063 30300 30502 63927 29766 30389 63506 63665 30953 62659 31648 31326 63371 30624 63134 64211 30425 63069 30334 30842 63631 64190 62638 62584 31442 62756 30751 64409 64421 62958 62535 31534 29776 63683 31022 30138 62842 63694 30917 62646 64439 64294 30235 30418 31415 62815 64279 31134 64031 63504 31250 63638 31373 31050 64221 29762 63545 31703 30791 63868 30029 30480 64436 63958 30510 63374 30894 31733 30489 31194 31721 31381 63178 62634 62569 62679 31503 64288 64420 30241 63296 63414 30593 63238 30575 63956 63020 31673 30181 62934 31508 31492 63712 63365 29794 29769 63567 30831 30313 63666 29756 64454 31392 63696 29774 30566 31431 30403 29890 31662 64369 62901 63078 31122 64213 29790 63932 30437 64499 31481 62920 63544 62595 63797 62539 64075 63533 31221 30983 31324 29868 30679 31003 62788 63894 62687 64026 31390 62852 64504 63555 64275 63026 31496 30488 63684 64451 63981 62584 30265 62589 62592 30966 63245 29835 62655 63247 29803 63706 63960 30602 30700 64186 64325 62796 63031 63497 31724 63894 63773 62864 30935 30000 63072 63566 29839 64234 63247 30700 64444 64015 30182 62887 31007 63872 64339 30116 29952 63468 30464 31181 63705 29911 30041 31404 62972 63731 62655 63672 31031 31509 29883 63443 31226 63704 63686 64405 31589 30271 31414 63726 31083 63784 31542 63564 31323 30809 62985 31340 64429 64069 30356 30689 63008 63159 31125 62848 64163 31367 30028 62915 63740 63208 30514 29840 63766 62817 30148 62727 31058 31203 62662 63114 63950 64317 64089 30401 63744 64082 30711 30260 30942 62966 63251 30444 30031 63606 30054 64511 30984 31160 63297 30889 62789 63676 62506 63696 63532 30960 30410 64281 30372 64135 29743 31155 64252 30114 62686 30622 64058 63606 30030 30834 31124 64307 30318 31235 62966 63728 30074 63294 63558 63484 31697 63204 30725 62545 31183 31706 62823 31393 30563 62649 64451 30938 30488 30971 63870 29958 63366 30876 30922 29931 30990 30036 64125 63414 30489 63499 30852 62551 62587 64310 62892 62609 30542 29722 30835 62967 31277 30963 30591 29922 29923 30371 31421 30650 30438 30243 64340 30380 31291 62901 30422 30564 64027 64228 29923 63489 64456 64493 62637 62960 64128 63373 63139 31581 30471 31741 30977 62923 31710 30604 29734 63371 62886 62567 63341 63594 64053 62889 63710 31690 31699 64396 30721 63455 63936 29812 62893 63620 31161 64091 30649 63793 62552 64301 30286 31037 63703 30846 64134 64466 31455 30287 63268 62611 63704 29841 31614 30575 64335 30010 30831 30221 62883 63326 31074 64345 31203 30585 30110 30062 29698 64008 31649 30799 63923 63198 62587 31370 29741 30309 30625 31440 64483 63344 63203 31008 29841 63810 63453 31217 62930 29725 30994 31679 63238 63406 63283 31096 64128 63899 63799 62934 31184 63996 31460 62911 30341 63472 31200 63565 29920 63903 30214 64343 30858 63678 63895 30325 31660 63225 31300 63356 62917 62812 31211 30604 30539 31170 64367 30114 62594 62903 31263 63234 29952 63577 62582 62726 62631 63410 30945 64314 63121 31067 31511 62902 30550 29711 62552 62815 30010 63040 64326 31160 63678 63120 64096 64222 64262 31734 30250 30690 63276 30130 30024 31054 30247 63208 30314 30639 30213 63896 64479 31720 63507 63609 29990 29914 64454 63697 63359 62830 62947 62748 64159 63617 63509 29812 30205 30135 30491 63947 31440 30842 62501 30932 63412 62903 31335 64306 30795 30906 29944 29736 31540 62765 63879 30151 62902 63012 30119 29943 29796 63705 30108 31455 31474 63149 29916 62563 30457 63172 63483 31211 62705 31368 63253 31467 30404 64198 30907 63959 31238 31072 30991 30887 62582 30564 30996 64127 31571 30571 30129 29775 30012 63311 30682 64268 31171 63346 30677 31555 31001 30525 30667 62969 64239 30412 30594 30491 31311 31444 62711 63273 31330 63615 30097 63735 30339 30730 30150 31438 62503 62569 31667 63212 64484 30041 30392 62919 29986 29906 30873 30011 64337 31152 31508 30719 30518 63302 30084 62875 31679 30675 63722 29969 30554 30211 63427 30830 30919 62603 29761 62655 29712 63928 30005 31366 63669 31558 62857 31648 30513 31357 63759 63366 62876 30475 29929 31312 29722 63676 63362 31483 63021 30185 30843 62575 31291 31475 31741 30151 29740 62934 62844 63931 30396 63541 30922 30065 64400 30330 30454 63183 31131 29954 62515 62988 30877 30069 29929 64235 29703 62944 62746 30274 64391 63181 30023 63101 30013 63751 31034 30221 31281 31507 31546 31603 31146 29883 64171 63895 62686 64212 64042 31228 63485 63516 30986 62567 62726 64017 30790 62811 29978 30269 63879 63655 64094 63518 29902 62862 30016 30022 30434 64160 62656 30747 29889 29713 63762 63020 30234 63819 63362 30558 30157 30094 29755 31172 64299 31722 62636 31569 64259 30003 29756 63548 30978 31070 30146 31168 30346 64084 63731 62889 63182 63369 30017 62593 31466 31135 63503 31087 63679 29815 30925 30562 63356 63310 31658 29901 64362 30002 30718 30649 30159 30402 29809 63299 29766 62567 64347 31353 62494 63488 30990 31318 63593 31068 63580 64036 29774 63366 30827 30045 30135 29758 64405 30592 63796 29896 30564 62934 31089 31533 63809 63226 63930 31517 63037 62811 64441 31549 63948 63583 62990 30341 30080 30076 63688 64333 29698 31132 63983 31144 29796 63079 64169 62877 64420 64181 63376 29729 30239 63642 63247 30338 63328 29732 31420 63429 30425 29949 63166 30550 30067 64312 30831 63834 31297 64435 62946 30471 62983 31626 63323 63474 30899 30440 30230 30736 62697 64414 63151 63828 63689 31132 62650 31315 31237 31177 31700 30090 64375 62890 63060 29913 31140 30693 63709 31151 63037 30460 30823 30459 30193 64330 31583 30207 64412 31580 64349 62895 30310 29919 30409 64336 30799 63017 63091 64083 30226 64011 30025 31262 31357 64020 62912 63219 31585 29787 29866 31625 31009 29950 29930 31162 31289 63572 30291 64122 29978 63393 31629 29860 63177 64336 29710 64198 64486 63070 31246 29994 62573 30941 63253 63609 30080 31686 62640 62773 62670 64357 30378 62816 31378 62555 31639 30845 29793 63114 62652 63652 64499 29705 62654 30700 64059 30805 64090 30305 30732 63066 63129 63922 0 1357120344 +1024 30174 30507 64482 64495 30859 30288 63082 30786 63637 29758 30076 62575 64201 63321 62803 64142 29790 30507 30726 62643 64207 62904 64188 30835 64035 30770 63284 63341 31015 62786 62863 64094 63072 63071 63995 30147 64153 30517 30067 30694 31348 64318 29891 30171 29922 30684 31593 63069 29889 64147 63743 62762 30688 30643 31352 29952 64017 31228 63621 31274 30741 62676 31538 31234 29716 31636 31092 31192 31174 63556 30179 62498 31128 62977 30889 62687 63475 30319 30991 31542 31086 30776 63082 31574 31521 31518 63874 63845 63747 31235 62757 29929 30846 30732 30915 64468 63634 63254 30178 31421 64158 63067 29716 31195 62963 31141 30794 62759 64303 30605 30260 30748 31102 31285 64327 30684 64258 31291 30233 30670 63718 64024 62619 30017 31516 30793 62594 30113 64080 63496 31698 30199 30981 31440 64165 30540 63010 63410 30049 29922 62654 31405 30990 64227 63766 63227 31640 30427 30473 30128 31633 62574 30086 62969 63241 30928 62887 64351 30021 63066 31404 30661 64511 30763 62847 30947 30494 63620 62721 63338 64217 63326 30959 31103 62786 29973 30545 62726 31030 62514 63869 64215 64127 31645 63069 62895 31163 64426 31471 62930 29709 30875 64395 30382 30978 64350 31245 31612 63763 63112 64181 31688 30823 29990 31220 63410 30250 31405 63770 63593 63583 31274 64074 30988 62729 31359 29895 30561 30851 63120 63610 64114 63447 64502 31142 64159 31519 29739 30540 62513 30593 64391 31260 63029 63197 63919 63362 30915 30079 31579 63300 29944 64322 64348 30756 30267 64469 63492 62846 30435 31653 63092 64424 31020 31559 30517 62853 30323 63012 30314 31365 30123 31340 63265 63540 62796 29974 30049 30088 62525 30385 62733 30902 29806 31100 62942 63346 64196 63141 63988 31441 29915 63832 62674 63406 31566 64249 30731 64359 31372 31408 62809 63587 63821 62809 62515 62866 31524 64508 30582 29827 31162 31645 30181 63477 63051 62759 30288 63304 31360 64492 29860 63324 62935 29810 30683 31318 64346 62756 30160 29711 30117 63419 63872 31701 64203 64198 30271 30692 63542 31318 30543 63314 62636 29769 64295 29717 30312 64266 30815 63162 30477 31357 64409 64205 63771 64311 30117 63789 31163 64459 62816 63280 64171 63309 31571 64133 29893 30160 30801 31010 30113 62660 64141 62700 30899 63242 63105 30821 29827 30194 30615 31431 63410 31366 30276 29998 63901 31353 63687 62467 31703 62906 63539 30291 62648 62704 64360 30955 63870 62797 30269 31300 62850 62905 62965 63454 64009 62592 63595 30577 62497 62466 62600 62982 63313 63213 64291 62545 63113 62479 31660 30413 63047 30410 64123 30648 62611 31368 62689 31022 31218 63814 31422 31263 29814 64510 62636 30065 63356 63492 63391 30922 63346 30419 31102 63901 31684 30630 30299 29889 31414 63411 63865 64500 62489 63346 30757 30128 64335 63247 29942 64179 63358 30754 63684 63300 31615 63568 63261 62744 31126 30209 63493 64371 30189 30047 30948 63470 30625 62882 63651 63085 30524 30439 63356 30782 64307 64023 30261 31730 63911 31724 63678 30385 63865 64310 64015 29760 64195 30327 63908 64322 31743 30489 30670 30482 63917 31122 30151 62745 63470 63561 64256 63906 29995 31266 62710 63323 31174 63220 63144 64066 29941 30911 64226 63409 30702 63517 64105 64065 31043 31722 31426 64333 31344 62589 29866 63212 29849 63099 30004 30443 29764 63211 30709 63313 63505 63751 64493 63073 29837 63290 64177 31437 31194 30259 31569 62904 63502 63037 30164 29819 63151 63006 63253 63125 31297 63500 64381 63111 31698 62529 31032 63355 31715 63002 63986 63566 31293 31152 29722 62573 63093 62675 63393 29736 30264 30577 63726 63242 29717 62637 30373 62883 30976 30875 31407 64278 31200 31658 30737 30809 31290 62633 31460 63905 64314 63275 63666 64463 29711 64050 63914 63445 64047 63149 63820 30340 63944 62799 63125 29809 62963 63886 31557 31538 63166 62746 31442 63872 30991 63946 29974 62482 30159 62700 63004 64437 30405 64098 30050 63966 30598 31411 30669 64178 31540 31677 31705 30422 30801 63253 63555 64015 31707 30642 64176 30224 31692 63707 31021 30329 64044 31386 30236 63878 30489 30331 64087 30529 62638 63222 63520 63255 64141 63433 63751 30323 31234 64469 30872 30421 30488 30898 64171 30971 64474 62625 30664 31055 63330 64036 64253 30735 62624 31385 63483 63598 30398 62616 30126 30752 63907 63949 62914 30903 31481 30600 29879 30299 63748 62697 62594 30847 30885 31339 29999 29782 63650 29722 30874 63544 30810 31509 63322 63018 29882 64437 62826 30394 31469 30382 31563 62723 30403 62787 63733 29748 31252 63722 31150 62475 29790 31300 31120 62585 30805 63127 64093 30643 31269 64364 62761 31650 63518 30729 30790 31348 62747 62496 62687 62662 63337 64018 30741 30322 62598 63768 63723 30913 63807 31399 30816 31651 31335 64374 64169 29890 30915 63344 62499 63444 63205 30632 30044 29769 31311 63903 63745 64060 63934 62691 30519 30557 30397 62589 62847 62650 64321 63424 62701 64414 62948 63129 62612 30752 30781 64135 30060 31424 31456 30646 31409 30938 63878 30090 29787 30248 63407 63679 63539 63876 30281 62593 63087 62788 64267 30490 31579 64356 30016 62703 31273 63620 31528 63685 62825 31328 30989 63199 63869 62591 63784 63095 31008 30906 31267 30005 64332 63004 64278 63349 63371 63112 30425 30248 63573 30866 31499 63132 30895 30242 63804 63342 30642 63216 31253 63411 29851 31320 30226 62929 30186 31089 30679 29972 31370 30920 30181 63809 64476 31679 29901 62638 31151 62594 31149 31227 62622 30025 62730 29938 62492 62793 62789 63744 31181 64187 29741 31440 62871 30003 63998 30959 30144 30808 30674 29979 63267 63498 31405 63470 63278 62570 31588 31018 29903 30530 63749 29787 31192 30064 64260 64444 62503 64458 64257 29789 30862 62700 63269 62767 31003 30563 63162 30473 31669 30808 64265 63419 29725 29834 31150 30482 63375 64278 31491 31239 31433 64361 30120 64141 63748 30206 31127 31545 30368 63185 30778 31615 31732 63241 62628 30184 29713 31359 31736 31192 31359 29978 31640 64468 62800 64202 31125 62595 30814 64504 30453 62522 29905 30232 29702 31220 63527 62696 31556 63917 62926 30606 31173 64252 31261 31564 30124 30476 31664 63233 30159 64393 63668 62607 30456 31278 63319 63661 63855 62677 30621 62969 62803 31152 63913 63117 63153 31507 63903 29853 29822 31418 63522 30449 63037 63850 64316 63831 30738 62566 30944 64225 30553 30838 30100 29891 31623 62874 63397 63686 63020 64457 64239 31110 64153 30894 64437 64426 63345 63002 30613 62821 31353 62544 30779 30221 64247 64049 30567 31551 64447 31028 29850 30484 30798 31490 62918 63123 30599 63265 63258 62657 31201 64058 30302 31674 62519 31584 63248 63882 30433 31618 64180 30886 63066 64170 63456 30877 30630 30201 64454 29746 63185 31411 62571 30324 63177 64308 30700 64369 31723 29772 30652 64161 63263 63192 30737 62773 62931 31026 31521 63169 62500 31216 63754 62609 29866 64141 30326 64468 30420 31376 62577 63381 31717 30721 63156 29703 30339 31276 31391 64011 64509 64485 30464 63812 29722 64511 63596 64508 63822 31714 63134 31182 31475 63271 30455 63879 30865 64054 64389 31056 29856 63778 31608 30574 31627 30686 31694 63373 62922 30207 62897 63576 64274 64500 31611 63525 63247 63313 62936 62586 30319 63317 31387 63977 30738 63349 31163 63255 63425 30387 62913 31087 63931 64147 63682 31074 64286 30606 30299 30167 30707 62523 31254 30401 64022 63631 31507 29714 63619 29698 63695 64184 63630 63225 63011 63349 31729 64244 63717 63580 64382 30446 63438 30048 31309 30425 63816 62943 31343 63861 31262 30693 30182 64220 30583 30765 64375 30060 31738 31667 62812 31498 30075 64254 31545 29931 63892 64339 63815 63627 30804 64364 29769 30426 62671 62778 64185 31115 63335 64293 30617 30775 63223 30255 29784 30548 31385 30119 31276 31649 30526 30857 29956 30271 31481 31738 30069 63919 31641 63551 62831 29716 31229 30461 31431 30572 30218 29698 62641 63617 30146 64237 63799 64126 62764 62469 63110 62834 30612 30872 64065 31736 31095 62630 63954 30503 31074 30587 30900 63443 30285 62901 63522 62724 31668 31327 30061 30358 62474 31512 30383 63589 31127 30709 29964 64125 62973 29747 29773 63836 62867 30369 31073 63536 30124 62829 30127 30928 64333 63059 63762 29922 30544 31496 62472 64291 31669 30003 62982 63321 31702 30559 62646 62889 31612 62767 30429 31025 64063 63358 30807 30139 31549 30458 30256 62646 63553 30657 29949 30214 64432 63309 31725 64240 63060 62709 63869 31074 64215 63408 30603 63846 30677 63796 29742 62658 63834 63632 62643 30126 62573 31523 64008 63860 64268 31045 63697 30425 63772 63683 29866 31040 29923 63047 63226 63553 30990 64009 62888 62718 30585 63879 30115 31089 62916 64203 64411 62749 62916 29797 31625 30175 29896 64139 31462 64081 30772 30557 29860 63580 63095 29881 30767 29915 64438 62924 30254 63447 64036 64195 31078 31267 63793 30695 29998 63988 30910 63701 31097 63631 30412 31136 64163 63618 31722 30536 30842 31645 30145 63881 31020 63596 63695 31711 30987 64272 64115 30942 62865 31477 29836 63987 30429 31110 63733 64492 30023 30095 31115 63883 63433 31361 63624 63330 63379 63185 62783 64012 31359 31474 63350 62575 63102 62471 31417 31301 29984 31254 31725 30875 31521 64377 29909 62488 30431 31689 63463 63555 30108 63611 62808 30007 30070 31348 63737 30982 63880 62642 63572 62519 64257 63514 63685 29761 29856 31526 31474 31642 63957 30828 30245 31422 62509 30046 31062 31466 30838 63211 31538 31671 30950 63219 62514 62944 31609 63033 64179 64073 63037 31341 64042 63000 30736 62486 62632 64376 30176 63662 64182 63139 30017 64071 64206 63184 30317 63430 30847 31239 63783 31466 62501 62824 64462 30669 63979 64277 30181 29811 63716 31679 63767 30230 63632 31592 31223 30499 62949 63818 64346 30373 63997 30270 31197 31690 64312 30449 30862 63362 30262 62920 30483 30798 30542 63275 30607 64467 31212 31740 63342 63838 31604 64277 62823 63900 30242 31170 31098 31728 31229 63109 63747 30613 63903 31670 31405 30727 30008 30106 62645 31701 31301 63328 62476 62834 31528 63032 63260 63659 63171 64062 31600 62712 31076 30366 30678 31091 31076 30984 63489 62508 64473 31412 62883 30758 30013 63622 62707 64301 62974 31738 30419 30318 30878 31120 63179 30104 63204 64295 31307 62757 29819 63534 30440 30547 31013 31431 64239 30780 29768 30943 31283 31579 63073 62971 31575 30740 31057 29889 63691 63966 30715 31157 30160 63119 63195 30809 62501 30716 64288 63369 29920 30305 29833 31283 30447 62874 30841 63975 30509 31265 31488 63428 62643 29997 63319 62881 29825 62848 31209 30366 30810 63526 31383 29766 63680 30358 64097 63525 30935 30095 31246 64022 29812 30417 31079 31507 63879 31689 30395 31371 64488 30108 64110 63256 30132 64191 64002 31449 62559 64473 63633 31699 62794 31281 62794 29718 30491 30695 63114 30028 63170 30200 63375 62647 31306 29848 62496 63168 63135 62947 29895 63566 31222 62921 30098 63878 29875 63372 62785 30830 63057 63154 63925 30033 64349 64484 63085 31568 62677 29851 63167 63965 30578 63613 63087 64156 63064 29756 30546 31321 30394 63607 29949 64246 30182 64055 31612 64280 30243 64103 64245 63532 63781 63649 62798 29819 30281 31305 63213 63386 62912 31588 30657 30510 31715 64337 30880 63081 30467 31250 64136 64186 29994 31131 30048 63729 63613 31177 63200 64072 62655 31412 63784 63274 63979 31244 29745 30418 30035 30102 29980 64405 64156 63104 63057 31088 30189 64117 64222 31590 30363 31736 63492 63806 63375 31523 64419 63814 63840 30274 30519 31317 31176 63894 63358 62984 63218 30568 63462 63203 31268 31611 30095 63117 63620 62631 30295 31280 29874 63130 64092 30443 31432 30255 30774 63614 31596 62947 30713 64320 30237 64457 31287 29808 64110 62724 30154 31217 29734 62611 62675 64177 62530 63121 29807 62859 29764 31715 64415 31387 63982 31296 63459 62515 64157 31202 30399 63719 30961 64066 64158 31022 62535 62833 63230 63766 31284 63932 62477 63730 31461 29719 62637 63173 63957 62852 63999 63724 29962 30827 29857 62590 62853 31296 30533 31296 63851 31576 64431 30017 30651 30946 63186 63151 63846 31653 30272 64355 30413 31493 63405 63613 63201 63070 30597 62842 64474 31543 62610 30472 63867 31251 30707 64031 63671 31404 30844 31405 64469 63403 31532 30577 63885 31011 63710 63315 63701 30008 31339 30868 30442 64349 62794 31669 30449 30431 63986 62924 64115 30524 31589 62561 30676 63355 63719 63337 30625 30911 62889 62861 30612 64489 29772 30369 62579 31426 29855 31727 64078 64253 62958 63312 31024 64251 63005 63508 30473 64325 30221 63454 31374 29925 63371 63469 62651 30762 63856 62866 30601 30681 63982 30999 63189 30569 62926 30370 29961 63707 63090 30190 30412 31405 64166 63475 30215 29933 64385 4286578687 4286578687 +1024 63054 63818 30454 63425 63321 63230 63215 30178 63088 64462 63094 31311 64142 63553 64347 63337 30091 63674 62630 31690 63625 31097 63147 31169 30603 62574 63128 29782 31131 30164 63043 31064 64491 63040 30554 64143 63853 62695 63809 63441 30006 63042 31531 63229 31221 31394 30674 30729 62820 63106 30178 62573 31666 29995 29820 31111 30595 63912 63420 63367 30248 30859 31264 30137 63588 63767 30501 30174 30424 63047 30521 62627 31252 63912 30614 30819 30150 62979 30800 63860 62740 62956 62490 63614 30770 62570 31444 29835 31393 63917 30661 62533 31342 29829 63543 63461 30095 63288 31569 30752 62808 31154 62779 31700 63879 31017 62634 30507 63228 31609 31391 63693 63743 62782 30239 30419 30877 63992 64451 31707 30379 62683 30668 63331 30635 29843 31110 63276 31120 31365 30432 29903 29711 29978 30944 30717 62799 62472 63576 63110 64298 30103 30377 63330 62485 30886 64423 63238 30871 63290 62870 63112 31066 30848 62498 29763 62938 64111 30040 62570 29908 30453 64178 30283 62700 30742 29699 63845 31234 63406 31532 30878 63459 31355 62473 30853 30594 64417 63368 63134 64000 62909 30254 63285 62522 30054 30248 62507 62566 30391 62973 29972 29824 63271 63782 31445 62567 30807 30686 31731 62499 31550 62625 62469 62576 63151 63802 64286 63196 30046 30513 30588 64036 31210 63459 64227 31282 30339 63912 31047 31511 63052 63742 63086 63904 30004 31301 30216 62574 31422 63672 30435 31303 62937 29718 30999 62938 63721 62863 30019 64080 63285 62818 64053 30072 30024 62743 63160 64065 29881 63336 64368 62794 63490 63575 63700 31291 62788 63217 30725 31164 62503 30610 64176 62674 64185 62984 31399 62563 63092 63401 31275 30934 31073 62999 30851 62811 63919 63361 30833 31506 31517 63151 64122 30847 30899 62771 30548 31011 62610 63366 30359 30062 30305 31315 31572 63941 63548 63246 31176 62560 31172 30665 63381 62637 64437 62519 29851 31568 62843 30997 63470 31463 63712 30022 30261 31058 63543 30416 29768 63046 30582 63510 29906 31144 31233 31429 30851 30016 30918 30244 63485 63587 30110 30284 30168 29890 64063 62784 63308 31350 30684 30144 62601 31093 64236 63644 63846 30912 31024 30737 31344 31073 62940 30197 31101 63327 62691 64329 30333 63725 31187 30816 64010 30402 31583 64128 30569 63295 63621 30469 29717 63130 31519 29752 30157 63292 62494 31573 31186 63367 31062 30819 64322 29799 64094 63612 31720 64260 64327 63634 31129 62800 63259 31460 31130 63065 30190 31411 64336 31344 31031 30961 63200 31593 63420 30638 62753 62634 63170 62751 30377 31339 63652 63270 63322 63529 31090 31333 30278 30531 31341 30250 63785 63397 30680 31144 62848 62840 29828 30180 62778 29752 30229 63937 31363 63634 30449 64468 64106 64493 63163 30602 31260 62789 31079 62870 29829 30970 30815 63241 30457 64505 30767 30007 63389 31275 63385 31639 64439 31608 31277 63516 31373 30331 31510 62905 31520 30532 31345 63933 29961 62909 64455 30387 63510 64398 30344 31428 30966 29908 63782 62745 64254 31140 64481 30695 64184 63789 29805 31733 63384 62653 62472 62680 31248 30212 63185 31135 63974 63982 64140 29847 29726 30819 30085 64508 63393 63320 30426 30996 63934 30434 31356 30686 30674 63358 63018 64179 64275 30746 62658 30925 30401 30490 62504 30967 62931 30755 31029 62653 30266 31372 29916 63307 30130 29958 31593 64414 63158 62704 30762 31193 63466 62773 64464 63570 63601 63947 62896 64002 63243 31595 31334 30250 29942 63041 31264 64120 31590 30154 62567 63325 30794 31379 29792 31608 31131 29744 64218 63272 31039 30698 30946 31135 62717 30765 31154 30713 30073 30197 64163 62840 63047 64282 62705 63275 63655 29800 29831 63925 31104 31484 30473 29703 64415 31123 63279 64508 30425 30501 64086 63531 30210 30669 63329 63651 30232 64302 63647 31295 62993 30905 64464 30802 29918 64152 64152 30149 30033 63370 64134 29851 30638 63969 63370 30419 63905 63227 63317 31485 63889 30072 63735 30091 63373 62997 31239 62643 63035 31424 62502 63436 30222 31088 30501 63899 31410 31111 62776 30586 64434 63707 63900 30824 29948 63224 29932 62743 62721 63341 31039 62828 29754 31006 31665 63742 63467 63514 30170 30999 30014 63197 30182 64320 63089 63534 62502 63823 30079 62621 30822 63997 30403 30278 29757 62792 62464 31522 62653 31454 63008 31279 64305 64071 63047 63770 30494 31241 30218 64110 62923 62539 31522 63202 31401 62955 63858 62808 29762 63693 64356 30914 30931 29955 64055 63889 30911 62571 31235 62927 30209 63512 31038 63370 31312 63975 63213 63147 30208 29978 64285 64309 31169 31137 31547 30033 64509 64377 30440 64173 63878 31578 31014 30889 29756 63514 64190 63258 64150 63477 64306 63462 31473 64317 30081 30731 64028 29897 30812 31624 64463 30420 31586 31172 63054 64481 31701 30299 63785 63794 63006 31365 62948 31380 64020 31537 30609 30194 62716 29849 62668 62540 31329 63501 63629 30633 30925 30694 64342 31013 30518 31434 30614 64035 62664 29934 30548 29980 63619 62671 30434 31712 31085 63981 30841 30275 62935 62579 63625 30393 31588 30169 62894 64306 62910 64502 63454 63871 31527 31705 30020 63993 31703 62893 63766 29868 63896 62876 31651 62821 64130 30186 63236 63496 31239 30435 30411 30626 30675 29957 30743 63089 29804 63489 62840 62936 30392 63957 62713 63380 30901 30547 64334 63562 63597 62679 64255 64335 64115 30059 30050 30530 29984 31372 30258 31413 63874 31338 30766 30527 63575 62733 31415 63755 30912 31606 63971 62913 63257 30754 64336 30829 63444 31219 30489 62854 30057 62625 63025 62855 63709 63579 63468 62889 63285 64061 62958 31636 31314 63724 63259 63989 30954 62574 30253 31622 62562 30607 63323 64434 29955 62837 31289 64357 31368 63807 62636 63855 63447 29773 63772 30864 31147 30004 31023 63642 30503 30466 64216 62800 30298 63641 31743 30961 29718 62647 30296 30087 62839 63387 30407 63116 30314 29872 30467 63276 29789 31407 62764 63557 30287 29886 62813 63233 62471 30662 30581 30955 30807 30445 63998 62613 63413 30459 63170 63186 30257 63867 62684 30667 29724 64296 30448 63174 29712 63908 30376 31669 30639 31024 29974 30861 29866 31471 63957 62775 29941 31271 30088 31076 29869 62785 62579 29796 63035 30277 62962 31668 31042 30178 63126 63344 64328 62998 31121 30267 30739 64283 30264 64039 62973 30009 30327 30133 63811 30217 64145 62773 63978 63099 30049 63805 64246 30957 31614 31302 64270 30410 63230 63180 29697 30084 64330 30692 63686 63181 64466 31735 63941 30736 31000 31408 29910 64188 31730 62982 31019 30672 30607 31516 31419 30157 62856 30887 63674 63751 29719 31107 29948 63186 30284 62694 63000 29736 29842 63889 30424 62895 31232 30931 62956 30139 63739 30151 62544 30749 64135 63676 30540 30466 30519 62622 30987 64432 62859 31504 31603 30611 31518 30595 63543 63013 30336 63852 62472 30517 64117 29726 31291 31218 30241 31613 31555 64228 63288 62573 63218 64238 62501 63079 30543 63866 31705 31006 64192 63629 30158 63992 30697 30815 31643 62863 62611 62608 64119 30212 30099 62828 63750 63593 31703 64071 30693 31643 64039 62891 62473 30171 62921 30873 31645 29948 63956 63009 30257 30707 63815 63966 62535 31033 63631 30670 30220 64317 30329 63461 62598 30314 62767 62540 31742 62617 31378 30807 30707 62971 30412 63570 31022 30579 63329 31200 30685 30750 63126 62876 62529 29869 62935 30458 63835 62643 31110 62473 64063 31101 62646 31098 30922 64053 63170 31483 62956 29754 62752 64381 31143 31152 63228 62678 31429 31281 63370 63996 30869 30925 30576 63126 63150 62640 31507 29711 64383 63939 30679 63724 63423 63369 63600 63484 31550 30826 63134 31671 63110 30207 31061 63346 64129 62610 31488 64326 62613 30767 62851 63311 63365 31383 63055 31139 31733 62968 31287 30733 62481 29936 62752 63326 31403 31001 64238 31529 31467 64212 62663 63810 30576 62720 30051 30099 63061 30852 63792 64038 30493 63881 62832 30369 30886 30136 30848 62825 29822 30780 30049 30195 31681 31714 31130 64339 64240 31205 31246 29961 31519 29955 62625 29792 62829 63355 62540 30175 31266 31218 63472 63823 63836 31162 29834 29918 30834 64413 63049 30283 30958 64133 31511 63200 63805 64010 62998 31582 29833 63817 63051 64476 30044 31048 31445 30707 62537 64452 63368 64358 64492 31162 62705 30455 29930 62716 29816 64056 63290 63332 30754 30370 63612 30389 29839 30846 31178 30488 30848 63508 64132 63909 30249 30051 62883 62965 63852 64008 31440 64058 63061 64463 30192 62642 31512 31157 62656 62716 31589 62993 63356 30088 30163 62570 63959 31294 63949 31704 31171 30722 30970 31236 62829 63166 62793 31132 64211 30403 62664 64257 63192 30966 64411 30606 62913 29883 29712 30357 64005 64287 29887 30434 62849 30036 64161 30183 63367 31259 64285 31479 64061 64231 62850 63440 31511 31120 63214 63655 63030 63684 63264 63335 30941 63100 31351 62827 64391 63049 31350 31122 30535 63425 63689 62945 31709 62943 30019 63408 30016 63818 64210 30567 64306 30576 31648 29702 30526 31716 30496 31146 30642 30046 30880 30098 29970 63225 63916 30570 62631 64430 64110 30422 30944 31103 63360 31218 30249 63051 31021 62639 63552 29902 63417 62578 63248 62590 63815 30138 62753 64214 30578 63694 30791 62905 30969 29770 63212 62693 63159 63247 63936 31140 62641 64108 31660 31110 30126 30637 62627 31703 30784 31072 63804 30694 63911 31655 63448 31548 30515 64442 30062 30284 30706 30691 30016 31343 30603 30396 30751 62812 31650 30391 30084 63976 30025 31154 64245 63875 30115 30811 63282 31223 63106 31259 31158 31141 63848 63532 30786 62963 29825 64093 31060 29823 64487 63911 63114 30391 62885 30714 30839 62872 64068 62583 64346 63444 62615 30457 31172 30147 63202 64059 62705 29939 64472 30665 30911 63599 31306 31567 63493 30622 30479 30948 64324 63191 30815 30778 29822 31439 62705 30171 31001 30315 31647 63245 29899 63746 30234 63470 64446 29776 64070 29848 63929 30117 63130 64450 30384 31703 63645 30335 30716 31125 31070 31417 30353 30109 31149 64404 30076 29802 63621 63506 62772 29946 64285 31188 29785 63191 63647 63931 30532 30940 31220 64092 64028 62885 31055 31702 63406 63217 63296 62861 64476 31121 62714 31635 30952 29882 63149 63757 29936 63815 31573 30059 63140 63064 64028 62629 62889 63371 30729 62668 63424 30673 62934 64130 63743 30599 31564 30573 31532 63625 63332 62863 62723 63967 30386 30780 63582 62650 31233 30546 64418 63622 62708 30536 63380 62466 62649 64229 31360 62715 31307 29953 29995 30055 63098 63164 31006 31646 63822 30340 63628 62634 63879 30133 64118 31238 30040 30587 29711 63131 63439 62673 30861 30824 30071 63313 63455 62904 64078 31407 31115 63875 30676 62519 30053 62711 30920 62566 64173 64095 63183 64030 62685 30365 63601 30136 64481 63643 64461 30121 63167 64020 62582 62643 29763 63657 31011 63841 63780 30235 31207 62712 31510 64393 63710 30663 29992 31055 64125 64220 64103 63989 62529 30382 30842 31200 30909 63717 63283 30728 64140 62867 30283 63641 64386 31716 31489 30016 31617 31639 64339 30524 31466 63056 30585 31580 30581 29833 31609 62688 31052 63289 31004 63220 30065 62638 63614 30556 63425 63390 63799 64097 62825 63130 63380 64056 62529 30574 29716 30092 30762 29819 62833 63583 63307 31351 30321 63852 29993 31462 62579 30421 29889 30558 30997 63619 31477 31565 63391 63514 29814 63956 29736 62878 63356 30865 29856 63072 31087 29700 62605 31162 64388 30956 62564 64488 62535 64080 30891 29897 62560 29766 64249 63988 64304 63070 62739 63974 31147 31442 30891 63987 62921 29822 62943 63172 31711 30429 63517 63474 63581 31640 31479 31359 30885 29879 64115 31641 30516 31321 62551 62897 62956 29918 30222 62944 62588 62499 63547 62805 30910 30318 31213 62716 31686 31126 64380 63435 31279 64463 29710 63018 62599 62734 62986 64063 63427 63770 63779 29748 63806 64206 63137 30020 30630 62641 64201 62951 29791 31255 64101 63023 62610 30538 31473 31686 29734 62997 30839 62894 30075 30174 64166 63533 62703 30830 63581 63733 63078 30444 63297 30135 31475 31310 63505 64163 62800 62793 63064 30550 30564 29879 30701 63456 30293 30618 31129 31073 30821 30302 31008 30154 31041 63747 64031 31198 63537 30033 63734 62800 29906 30341 29762 63207 62729 30731 63085 31095 30720 64441 29991 63990 31381 30902 30504 64072 31497 31743 30857 31600 63329 63717 31613 64480 62992 63416 64433 30678 63377 30925 30504 30634 63231 63179 64511 29825 62923 31619 64080 30128 31280 63263 63428 30626 62659 62939 31032 29913 63958 63798 30372 30226 63475 31387 62941 30098 62623 30928 31285 64019 31218 30627 62873 64276 30092 63116 64109 63137 63430 63591 30859 31477 63120 30734 30006 62805 62510 31188 30630 30320 63105 62548 62800 63469 63398 63983 31353 62822 63371 0 1345639725 +1024 63496 62734 62547 29924 31195 63551 64488 64409 62640 64188 31072 30271 29827 29834 29896 30889 62532 30570 31529 30028 64323 64378 63691 64282 31531 29807 30949 31355 63213 64111 30916 63444 63127 62512 64147 29703 30100 29845 31496 31228 62885 30776 30745 63838 30330 30512 31557 30606 63171 63145 63847 31058 64388 63692 30719 63426 31403 62651 64074 62766 29806 62492 63854 64251 31229 63098 30571 30884 63072 31003 30409 62557 64502 63329 62757 30594 29764 30059 64028 31113 30914 30876 30968 64351 30714 30302 31711 31094 63698 30668 64130 30659 29801 63507 63170 64353 31722 31346 31396 64300 30166 63064 31387 29820 31556 29853 62537 62969 64340 63905 30897 62737 29761 62607 31669 62954 64467 30016 30937 62872 30354 63337 31511 30472 63938 30170 62871 29867 63740 64131 30757 30416 30790 63755 31030 30114 30638 63360 63407 30814 30143 29763 62500 31095 31738 64455 62689 64233 63881 63809 31373 29955 31629 31123 29725 31578 30967 62637 63403 64394 31505 62476 64458 30592 30515 30859 63457 31245 30918 64238 64430 64081 30716 63094 64181 30869 30083 64025 64497 31474 30782 62685 64107 31109 30509 63955 62578 63136 31514 62642 62847 64071 31615 64246 30892 31010 64111 64221 64448 30067 31640 62936 63565 63898 64159 31296 30572 30451 62806 63831 62564 30933 63783 63277 31540 63504 63483 62674 63669 64504 30970 30301 62807 62939 29796 63525 31207 63143 30264 63822 62701 62954 30245 31325 31097 31682 29824 30007 31128 62959 64417 30314 30080 30593 63119 31370 31050 63844 63154 30513 63696 63425 30606 30552 31422 31014 31364 62628 63465 31211 31328 31445 62903 30876 63763 30001 31377 62875 62662 64018 64325 31241 31525 63937 64363 31337 30882 30626 30698 29793 64487 31219 30674 63760 62468 63047 64282 31621 30434 31354 64386 62982 62477 29704 64147 31040 62554 30374 29836 31359 62558 31647 63592 63323 31412 64127 62839 31065 64316 31275 64195 31357 63517 63375 29801 63850 31187 62691 63083 29836 62578 30944 64304 30559 63907 64251 30522 63516 31362 30999 62577 30077 62884 31282 29997 29971 30131 63888 62897 63858 29711 62813 64025 31443 62512 31715 31417 31723 31433 30123 64316 30371 30131 64028 29711 31718 30525 31391 63271 64507 31142 31012 62921 63286 31603 31538 64408 63905 31336 64317 30413 64373 30241 63589 62639 63314 31072 63815 31702 63550 30496 30436 30003 30971 63069 30876 62558 30588 31205 63157 31589 63979 30760 30095 63126 64434 29908 30179 63963 63583 31638 31058 31078 62629 30807 63157 31021 64243 29711 30466 30336 30111 62944 31542 30160 62785 64309 62580 62467 63172 31332 30319 30962 31232 29988 31470 31579 63303 62681 62764 31655 31073 31109 30805 63914 64147 62953 29890 30374 63653 30178 31596 62572 30932 64256 31214 62735 30206 30591 63794 63695 62471 63131 29946 30001 63303 29901 30021 63778 29838 31545 31320 31340 30996 62659 63877 31311 29725 31595 30588 63335 62674 29858 30272 30527 30724 62607 30171 31701 63096 31544 31428 63419 62671 63089 29836 64271 64084 31370 62552 63941 64312 31018 30791 63867 31514 64011 30961 64357 63852 63849 64271 64048 63598 31192 63720 63334 31105 63099 31543 63823 30207 62936 63722 63113 64482 31514 63391 62813 30043 62980 29933 62466 63632 63881 30166 31715 30289 63934 62709 31159 29742 29782 29819 30555 64426 31387 31530 30231 31094 31495 29799 63944 31025 63913 30402 62595 31455 63680 64018 63739 29846 63274 63354 63236 29766 30793 63896 30058 63264 30332 31692 63478 63725 64396 63888 64262 31509 64511 63306 63313 31381 63229 63460 30405 30701 62773 64385 30549 31199 63992 31578 31023 29993 31307 30585 63192 63491 62542 30638 64460 30014 63536 30996 29922 30874 31583 30228 62671 30477 62638 30194 62965 31415 62917 29862 30855 63603 31259 63441 30754 63615 30271 29761 63161 62585 30950 31537 31612 63038 63429 31420 64144 31204 62819 64407 30139 31632 29752 62997 31564 31734 30083 30986 62720 63299 30613 30952 31738 62510 31252 64229 30244 63115 29697 30223 30175 63994 31455 30634 31338 63609 62659 62757 31380 63226 63255 62911 64309 31483 29973 62762 31308 31365 64266 63859 64325 30737 30307 63633 63512 30076 63764 64327 31391 30703 31551 30992 64401 64374 29938 30048 30381 64347 30526 30053 62931 30453 62857 62829 64491 63570 30801 62972 31558 29733 30120 31316 31740 64398 63040 30688 31653 31279 31144 63980 30622 29935 63649 63961 62625 63434 31734 63201 64486 31630 63142 31721 31413 64118 62541 64368 30041 30901 30429 30770 29884 62665 63043 63606 30193 64306 30533 63910 62532 64391 30167 63028 31718 63846 30109 63298 30643 64488 31155 31541 63808 63828 64400 31210 64388 30317 30414 63597 31070 30943 30606 30429 62912 63843 62648 62495 63934 31647 31566 30065 31218 64161 31644 29907 30106 31449 63375 62669 30332 63190 63578 63044 64415 64504 29710 30437 29968 63425 64041 64017 30846 31646 31123 30127 30439 29889 62547 29814 31652 29979 63500 30953 63805 63671 63662 64220 63926 31399 63943 64242 64188 62692 29982 63121 64346 62651 31106 31634 62489 30729 29777 62958 31595 62776 30072 31383 63186 64301 64364 29778 62991 31124 29986 29744 30309 29979 30154 63176 30140 63333 30683 30462 30214 63818 63622 30820 30572 30253 63799 62937 30285 63198 30780 29851 63716 30316 63110 29755 63137 63013 64265 29758 31267 30987 62563 30668 31233 63096 30490 63587 62873 30438 63448 30782 30604 30168 30337 30595 31098 29879 64077 30506 64380 30663 31211 64476 30898 62596 30879 64048 30252 63587 31000 30092 30740 31390 63696 63692 30356 31720 31071 31064 64460 30482 31420 30326 30805 62506 29852 31148 31021 62709 30797 30019 30995 29747 31280 31525 63166 64054 63786 30786 30307 30146 31305 64129 31583 62825 63938 62809 30572 31710 31279 31615 63511 30460 31697 31385 62492 30705 30513 31254 62642 63717 63676 63522 30363 29756 64119 30025 31537 29877 63945 31301 64318 31497 31708 63124 62505 63185 30570 30084 63738 63371 31657 30268 30229 30118 62840 31028 30680 64228 63979 62864 63160 64214 62623 63970 63344 64242 30106 64047 30460 62548 29865 63331 64273 64088 30612 30138 64441 30389 63146 63923 63764 63996 64194 30041 62920 63911 30449 64064 63585 31319 29712 31605 30499 30399 30629 31226 31309 30211 63636 31020 30284 62641 29759 62916 64312 30960 64404 64366 31617 30042 63933 30873 30074 30590 29966 30284 63986 31717 62878 30423 63696 63355 63433 62550 30508 63555 31004 63131 30866 30846 29849 62737 64424 31079 30907 30275 30289 30011 63551 31450 30343 63809 30019 64401 31042 30447 30452 31147 63559 63889 63512 63908 62919 62606 31014 30684 63211 30675 62499 63520 63915 64321 29956 30754 64172 31077 29895 30324 31546 63804 30218 63270 31579 29731 30195 63402 63923 64406 63668 31546 30755 29710 31707 62514 63274 30328 30799 29781 29718 64456 30428 64319 64122 30502 63837 63589 63754 30263 62651 63346 30317 30330 29917 30250 30565 64498 31659 30396 31522 64503 64496 31441 63822 31692 30666 63397 63137 64379 30407 29744 62712 62818 30461 31588 29993 30137 62828 29925 64239 31126 31569 63103 64066 30702 29749 30714 63990 63224 30386 30233 64029 63464 63864 30545 29989 31021 31399 62572 30953 31622 62811 30959 30206 63156 62755 30315 63196 63252 31047 63884 63373 63942 63894 29784 62987 31054 62656 30182 63246 63526 30209 64462 29820 63407 62682 63650 63997 62837 31169 30250 31378 30974 31192 29890 30319 64015 30273 64468 62738 31244 30948 30416 63119 31569 62638 31476 29796 29918 64319 29735 31515 30734 31033 29814 63998 63859 63445 31117 64113 62662 30806 30294 63826 62694 63087 64308 31594 62623 30305 62466 30621 62964 31676 31616 30645 64177 31478 63270 63374 31694 30629 30842 62985 64082 64244 30574 64293 30884 62568 64062 30217 63482 31316 31045 30848 62692 63004 30574 29798 63278 30404 31599 62692 64492 63826 64282 63544 31015 63532 64392 64039 62875 29863 31216 64103 63802 63884 31078 64407 63883 63000 63955 31183 62795 30039 63407 64211 29766 30233 63555 31636 63318 63924 64465 31360 30902 63895 64487 29974 63388 30202 30214 29909 64188 29847 29943 31661 64167 63261 30485 62974 30802 31731 31420 30472 63585 64099 63489 31370 30716 31635 29936 63422 62894 29822 63967 31522 63667 63923 64233 63224 62726 31100 63607 30316 62915 64370 62951 62811 62869 63888 30664 64220 30700 31214 30769 30528 29920 29969 29952 63311 30427 31002 30023 63482 31257 63730 64283 63864 29801 31157 29972 63783 63130 30036 64070 30049 63439 30571 64333 30580 62626 63262 63736 30741 30240 63816 63340 30880 62765 64300 30704 30239 29987 64311 31691 62773 31623 63911 64092 30400 31213 30859 63577 63196 63801 63116 62764 31355 30291 31215 31587 64495 30789 64000 64480 30981 31302 30555 30498 30403 31557 62713 31213 64095 63009 63410 64074 64231 64022 62718 63830 64149 31706 64222 30813 63475 31170 31306 63665 30556 30337 31153 63432 30368 63341 30530 63115 31651 62798 31433 64076 30049 63184 31252 62728 63351 63992 64016 30129 31434 63400 62671 63300 63421 64414 31530 30479 29836 31652 63084 63032 30804 63894 63343 30703 62571 30745 63400 30111 64172 29712 64357 63105 30559 62973 63565 30112 64343 30647 62737 29944 29842 63185 31016 31092 63428 30854 64178 63269 29989 29767 64338 63830 64263 31665 63934 64159 30424 31122 63727 62726 63347 30433 63941 30187 63957 63263 64444 31718 63066 62583 63299 63323 63584 63724 31284 30939 62857 30567 62539 30136 62693 29882 63708 30931 31121 30767 29878 63915 63102 30841 63039 64197 64118 31090 63722 62658 63162 62732 31676 31431 30898 31500 30304 64375 30541 30839 64098 63194 64316 29895 63116 30360 30834 30500 64184 62619 62531 31049 30573 30754 64366 63264 29887 62695 29703 62655 30879 62995 63220 63139 62564 63625 63912 64099 63302 63042 30628 63961 62693 31110 30660 30423 30868 30780 63361 62800 30204 62950 30788 31630 30765 31014 31132 29730 64404 63292 31718 31570 63530 63555 63307 63800 31482 30192 62609 30489 63637 64167 63053 63542 30103 29790 63765 63518 31234 62864 63147 31441 29890 63766 30221 63906 63284 30501 64351 62638 30358 30834 30755 62921 30407 64452 64354 30918 29787 30752 62495 63238 30133 62836 30954 63175 30898 63339 64216 63725 63380 63707 31575 63691 62586 31208 29847 62819 29980 30336 64414 29777 63299 31070 63409 30356 63864 30441 31494 31087 31571 30020 30866 29993 63947 62573 29789 30347 64019 62869 29834 64462 62593 30673 63404 64463 63752 64293 63571 63766 63862 31525 64472 30262 63547 64286 31628 29866 63080 62986 29706 64500 30961 64082 63441 30308 30176 30158 30018 64341 62532 64343 63602 64037 29972 31084 30156 31397 30105 31664 62962 63916 62731 64380 30950 64110 30779 63942 30666 63529 64143 31560 63472 62925 30619 63770 64085 30346 31555 63363 63154 31320 30227 64475 62616 30954 29879 30394 30598 64125 29866 63523 63482 63868 29758 30736 30793 62945 30513 30216 29740 62738 30500 31179 64188 30401 31075 64486 64005 30186 29744 63737 31061 64355 64281 29833 30353 62480 64073 31625 62686 31329 30629 64117 64057 31001 29813 31582 30949 62640 30625 30310 29884 62868 30836 31548 31536 63344 63335 31569 30783 29885 31063 62897 64393 30740 31135 63483 63315 31374 30155 62991 62859 63236 62996 62827 30342 30227 62552 63879 30263 64503 31010 31617 63627 30923 30271 62659 31191 62933 30040 63159 30302 63973 31720 31409 62602 30493 31221 62524 62472 31101 62556 62756 62535 63596 31355 63220 29698 30880 63775 29918 62550 30294 30767 64033 29789 31668 29947 30425 30747 63820 30475 31685 62517 62646 31166 63232 30916 29701 63224 63864 30927 64053 63013 64282 30230 62908 64445 29844 64407 64421 30870 29734 63387 30917 64220 30667 30033 63007 30887 62590 30960 63038 62690 31112 62916 30587 30985 64259 31235 64477 64180 64153 63507 31374 63643 64176 63726 64318 31468 64310 30790 30814 63342 31217 29823 31560 31350 62647 63831 63574 63278 64349 63990 31043 63416 31275 63208 63650 63229 64273 30015 31619 31089 63484 31364 64296 31723 63242 64192 63645 63432 31420 62800 31399 31561 31055 31275 64483 64277 30150 63851 30078 63229 63958 63051 62544 31612 62763 63561 30168 63108 30100 29855 63826 62985 62870 64274 62757 62555 31690 30602 31211 62813 29969 30788 64329 62550 29787 30021 31265 30587 63684 64279 62846 30466 30104 30345 64305 64020 62492 63678 63217 31002 30483 64420 31287 30549 31673 63126 31397 30184 29860 31040 63895 63350 64148 30952 31332 63269 64024 63826 30641 62997 30000 30953 30280 31318 63485 31204 29896 62742 63064 63815 64366 64126 30620 31299 63247 63924 31512 62603 29767 30203 62686 30855 63849 64429 30210 30849 64356 30902 29817 64253 64056 31691 63997 31124 29934 4286578687 4286578687 +1024 63960 30348 63672 63489 63137 30951 30885 30748 63289 31269 64324 29704 63441 31628 63018 63769 31237 30805 30882 31453 64122 63015 63045 30375 62680 63049 31549 62553 63578 30532 63276 63439 63170 30687 31291 63896 63309 30645 30357 29987 30753 63967 63517 63987 30556 29770 63576 30853 63087 62487 63061 30613 31575 64155 63970 31477 63098 31135 31507 63248 29879 31533 31510 63875 30023 62704 63738 30345 31483 31603 30342 31287 30599 31023 30282 64199 63897 63322 64135 62730 30747 30730 64357 63142 31624 30909 64395 63239 63161 31349 62778 31135 62592 31365 63856 62548 31145 63223 64061 62657 29834 31593 62470 64288 63873 62495 30727 63117 30802 63597 64297 64008 30959 62715 29923 31046 30750 31579 64467 31180 64099 62514 29797 64074 64241 30012 30572 30323 30509 30651 30692 31386 63130 64359 63115 31084 63135 62685 29910 31335 62950 62608 64452 63325 64296 62530 30561 30540 30701 30245 30379 63277 63401 31674 31710 62927 64197 30815 62684 30332 62964 63317 30747 63490 30339 63055 30888 63789 63946 31083 30184 63491 30335 62835 31688 63819 30007 63505 31027 30736 63808 64248 30486 30801 63006 29860 30162 30346 62716 63304 31367 29942 30574 63466 63697 62716 29868 31546 30314 63288 30745 31618 63716 63157 63435 63253 29815 63563 31142 63362 63829 63336 31198 63053 30579 29811 62879 30751 29879 31078 29823 29796 30085 64073 64149 31548 31563 63370 63095 64088 63421 31728 30801 31083 30556 29753 30596 62515 30616 31032 63107 29871 30005 64220 30857 31249 30308 31352 31560 30106 62519 30709 62966 64315 63074 31535 64427 63259 30744 29870 64078 30066 62537 62906 64036 29944 63585 63286 29751 64360 63231 30263 62806 30254 63513 62733 64385 62815 63090 30487 63487 63745 63686 64197 62702 63059 63749 62852 63317 29765 31158 62715 29950 31732 64153 64443 62476 63380 63286 30338 30713 63073 63300 31278 62719 30572 31039 64439 63778 30042 63664 29885 62998 30516 64217 64298 63506 63622 30887 30660 62810 62996 29966 62824 62554 63562 31448 30666 30529 64334 29807 63630 62953 63085 31375 62608 63171 63282 62982 30250 63300 63014 62857 62907 30333 64022 30694 30346 64134 30173 62767 64303 64092 30214 62744 63824 63668 31125 64054 64142 30817 31310 62581 62681 62909 30603 30736 31565 30561 62680 63757 64425 62792 64356 31592 62538 31441 30551 63937 31089 30802 31204 62690 31321 30971 63250 30437 63334 63354 63573 62674 30834 64332 62547 63791 62800 31052 63614 31439 62830 63437 62981 31451 30673 29706 30572 63635 30093 63315 29761 63339 30782 64461 31263 62510 63171 31172 64093 63798 31547 62691 30350 63678 62719 64206 30865 30214 63831 63447 62718 31228 63812 63095 63403 30900 63887 62966 62702 29864 62680 64251 63818 30170 64176 29982 31153 62475 29884 30809 62762 63679 63859 29766 31528 62731 63570 63393 31610 30653 64274 63385 30234 31570 63559 30998 31312 62855 64297 31513 62965 31721 31270 63682 63264 63447 31491 64110 31056 29706 63372 31695 30933 30513 64418 30939 64259 62681 64130 63832 63909 63375 30025 31398 62669 62564 64333 64303 63096 64481 62560 31404 63410 29996 31242 64115 31491 63127 63358 29854 30610 31097 30376 64095 63435 63489 30442 63887 29705 29961 63226 29920 64271 64202 62511 30992 63095 31075 62709 63942 31451 29962 63480 64310 30399 31120 30219 62488 30490 30102 63195 64468 29770 62839 30968 29807 63932 64240 64440 63858 31695 30771 62785 63135 63295 30246 30942 63616 31357 63884 62673 63855 63188 31145 31035 29705 30120 30246 63597 31550 63267 30383 63628 30010 63594 63974 30128 64164 64206 63079 30661 62861 30716 30890 63175 62778 30859 31645 63440 62719 30755 30126 31184 31426 30387 29910 30504 62672 63748 30150 30280 30807 63990 31594 63799 62584 29910 63263 63169 63695 31685 63278 63662 63073 31719 30022 63916 29847 63524 31506 30477 30052 64325 63240 64020 62578 64424 64072 30954 31498 62489 64106 63632 31076 63485 63559 63662 29943 30334 63072 30118 64011 31219 63553 29881 64012 63885 29823 30768 63169 30103 63210 63318 63015 63613 64440 64143 30069 63830 64105 63573 30434 29913 31119 63692 30419 31369 63544 64063 63646 63369 31607 63823 63481 31282 64190 30571 31589 31350 64468 64381 30324 30117 29786 30643 63691 63963 31338 63309 64497 30629 31301 64450 63669 64294 63252 30967 30878 31437 64403 62990 64177 63732 62673 64248 64386 30719 62953 64090 30716 31149 63113 31123 31190 31654 63970 30790 62908 63593 64174 63243 30563 63408 30758 30264 30745 29994 62851 30452 30748 29970 29960 63887 63644 29809 63688 30560 31372 30872 30351 62517 62983 30090 62642 31520 64227 30747 31204 63950 30016 31057 64427 62734 63946 63371 30915 64370 31660 31511 30906 63232 30935 31724 30383 63200 31137 30484 63214 31309 62508 63745 63333 63761 63914 62995 31244 30373 31417 63697 63988 63056 63266 29910 62922 31334 63575 64068 31440 30717 63704 30031 29992 30464 62803 30366 62495 62716 31147 64419 31567 30544 31578 62830 63590 63293 30962 63948 30963 31675 30363 63902 31618 63320 63296 30209 63023 31368 30001 30052 62676 63193 63603 31161 31214 64261 29840 63141 29914 30955 63555 64371 30244 62515 62627 30419 30791 30402 29919 63193 64157 63741 31304 29840 64125 30344 29750 63565 63771 31707 64497 29765 31729 31391 29977 64178 64200 31358 64443 31311 31446 62551 30770 63533 30458 62659 31594 31372 29774 64452 31445 31536 30661 31512 62944 31393 29786 29961 29834 63382 64103 64485 30495 64445 31194 63739 64346 63315 64272 62959 62658 63146 31203 64434 30747 30024 63368 30856 30495 31134 62821 63586 31517 31522 62933 31423 62842 63203 63358 62487 31485 30800 63863 63771 30172 63048 31708 30720 31674 29731 30296 31023 31138 63577 30868 31525 31173 31049 64496 63738 62994 30120 62755 30803 63938 62794 30888 31262 62749 64438 62720 30868 31439 30474 30722 30037 30936 31120 31256 31217 63141 64502 29818 31578 30890 30020 30336 62983 29961 64345 63371 29910 63613 30917 63888 64188 62578 30965 64029 62480 64470 30704 30400 62503 31529 63257 64141 64266 30787 30895 29805 31722 31245 30201 30587 64097 31711 31120 64320 62504 30682 31216 31605 63958 64093 62731 31167 62744 29777 64373 30769 30349 29704 63365 63649 64395 62935 62697 62639 30574 62660 62799 30941 62795 31601 29880 30509 63306 64266 62520 29958 31369 64349 63885 64316 64196 31266 64066 30511 64320 63552 30221 30158 31137 30874 62724 31491 31276 30993 62854 62601 63381 64316 62483 63946 30767 29902 31392 31410 64357 30098 31614 63369 30755 64054 29905 63591 64308 30291 63702 63670 29783 30979 30508 62842 30066 62942 64004 30866 30469 64431 30107 30258 62993 30803 31540 30043 29936 30285 29794 31169 64123 62827 31264 31124 63383 30390 62812 63440 63847 62959 31210 29788 31357 63933 63793 31503 64458 29951 63533 31063 63832 30825 29844 63138 30847 63798 62747 30963 30569 30717 64264 63462 31173 30077 29880 62894 63299 31422 62711 31103 30649 30993 30769 30797 30239 30606 30947 30995 30878 30844 31633 63207 31344 29730 62703 63306 30926 30270 63691 31218 64099 63287 30703 63180 63104 30179 63775 63298 29980 62737 63565 64183 63281 29945 30376 30850 62789 62836 30029 63716 30538 30451 63284 63681 62623 31633 31597 30923 31084 62976 62634 31545 63689 62884 29808 30053 64340 30350 63922 63755 62515 30114 63887 31455 63439 63927 62863 64014 63094 30280 31221 62492 31501 63214 63569 31356 30642 30689 30270 30826 31002 31611 30933 64109 29935 30631 63099 31138 62805 63961 30902 30448 30578 30027 63715 30609 63346 30918 63848 30666 29973 62760 63481 31342 29763 29944 64156 30896 64367 31101 31485 64251 29795 30059 31161 29961 30699 31574 30997 63660 31687 30469 63653 30897 63713 64228 62897 63472 64491 62727 62885 30230 62717 62602 30582 31632 30414 63018 63668 63161 64355 64498 30364 30194 31339 31312 63577 62988 30186 31032 62554 30757 63396 31046 30227 62551 30037 64495 31591 63903 31183 63661 30357 30327 62680 64458 63441 64314 30564 64352 30708 30839 63471 64098 31229 64292 30822 30864 62924 62530 62606 62877 63853 30770 62942 63754 30823 63789 63874 62466 62633 31039 30244 63362 64071 30760 30911 62787 30293 63418 63769 62568 64211 62718 63510 29765 62977 30149 62801 63905 64095 64372 62722 31117 30831 63122 30369 29874 62973 29841 31043 64306 29808 31548 64327 64033 29701 63400 64056 63915 31559 64413 29947 30083 63369 62725 62999 30945 63878 31540 30469 62598 64181 30252 64236 29729 31531 63292 30764 63562 63260 30158 64214 62969 29876 63149 31263 31590 63590 31711 62551 62483 64258 62812 64426 30836 63336 31049 63655 30834 62779 29886 31246 64467 31682 31414 30228 30985 63625 64308 31083 64214 63023 30648 64320 29909 64474 31369 62583 62914 64050 31009 31457 30318 62667 62913 63163 62539 63551 30921 64359 29701 63485 31104 31737 63768 30388 31264 63388 30575 30056 30510 63218 64001 62579 64198 63065 64491 62975 30250 62892 31046 64489 29705 31685 62949 64387 64177 63199 30066 31621 62821 29713 64314 31103 30375 30212 64484 63581 30850 64217 31405 31328 29991 62937 63606 64092 64313 62476 62893 30308 31080 30388 63358 30122 63046 64469 63828 30746 31505 31006 64416 31614 63084 30028 63949 62724 63268 63340 29947 30202 29874 31553 30200 62838 63646 63265 63964 62713 62726 63430 62608 31585 63045 63024 30163 64376 31199 30219 30604 63690 30715 30014 64376 30961 30794 30155 30052 64295 63639 64292 63972 30661 31032 64275 30164 64431 63175 62509 29867 30204 30988 31109 31651 31480 30492 30717 30101 63021 31622 30039 62628 30414 63444 29729 63684 30060 30425 62780 31047 62625 30962 31428 31703 30619 29917 62962 31448 30881 30882 31032 30357 63047 63814 64026 31206 63214 30705 64431 63656 64106 64165 63996 63360 30565 63930 31126 29704 62780 64045 64186 63004 62958 63169 30035 30993 30150 29833 30652 63404 30727 62722 63635 31267 30929 62949 31743 64176 63850 64260 63194 63443 64279 63541 30776 62509 31027 29837 30059 30138 63361 62844 29733 64385 62656 31267 31446 63924 62465 30657 64123 30113 64166 31537 30173 30520 31221 64453 64487 31091 31080 63317 64128 64135 31181 64218 29978 31496 31476 31676 30270 62812 30797 31524 29842 30718 29715 29752 31583 30465 63969 30593 31740 64152 31524 31620 63373 30301 31635 30394 63805 63181 63880 30230 63695 64030 64316 64465 31732 64506 63231 63159 63192 63529 29728 29772 63058 31566 30908 63212 62686 29725 30558 31200 30212 31541 31060 63610 30209 62747 31353 62666 30562 62892 31201 64157 30606 30615 64163 31466 31082 31553 63839 31153 64319 63979 64200 31102 30228 64109 62890 30215 31089 31729 29869 31450 30419 63216 31519 30305 62478 64489 64265 63560 64026 64159 64377 63990 31263 31552 30796 30215 64224 63565 30895 30813 64309 30116 63063 63462 31488 30589 64000 30516 31243 63866 31394 63945 64367 62466 30154 62764 31105 30350 30371 31315 30246 30562 62608 30896 30501 62780 30653 62624 30435 30072 31386 31409 62794 30838 30173 31062 31351 62841 63275 63637 29912 63196 30371 62806 63839 30782 30857 63096 62732 31084 29819 29896 62713 64027 63346 62682 30458 31274 30909 63301 30517 30439 31537 29979 63900 64118 31003 63722 30603 63940 64075 31574 30728 63860 63331 30881 29730 63662 64360 64322 30435 31606 31074 63294 29719 31233 31291 30496 30707 30796 64011 62526 63328 63559 63842 63760 31644 63652 30704 63343 31670 30841 31552 64198 64140 63454 62688 63691 62651 64011 31686 30169 62944 30955 63368 62892 64274 31430 63048 63890 63078 64477 63781 64123 31227 30790 63214 63267 31636 31180 62800 30093 31309 30072 64402 63440 64008 63090 64153 30554 62761 62841 63205 63461 29945 64214 63145 31553 30082 62589 31281 31347 30777 31370 31348 30382 31391 31268 62557 31360 30866 30841 63035 31566 30469 31631 63167 62537 64331 31023 30478 31667 31352 30353 64314 64015 62805 31077 64188 31604 64301 64094 31027 31359 29732 62864 63903 63482 30105 29743 31732 30382 29721 62657 30771 31735 63814 31708 64172 31530 64047 31211 63003 30678 30927 30105 63942 62954 29860 30446 62926 62503 64436 63707 30985 31193 63533 31437 31251 30660 64231 63067 29797 30439 64365 63474 63436 30452 29940 30968 62849 63812 62770 63952 30847 63643 62577 31562 30476 31668 30963 30207 63127 29854 30781 30662 30828 31362 31049 64365 30011 30315 29789 62784 31337 31243 30449 30856 31052 63695 30590 31416 63193 29770 63998 63339 31332 30679 62875 30648 64267 30921 30882 30764 31675 62641 29821 30026 30389 63067 31317 30374 63560 63698 63174 31122 63841 29903 31458 63057 63580 30164 62551 31230 30973 62840 62613 30862 64176 63834 31521 31595 29904 31005 64050 30392 30517 63865 31656 31724 63537 31262 63050 2139095039 2139095039 +1024 30601 64032 63754 64072 64250 30829 29713 64134 30120 29972 30638 63664 62769 63787 30665 63642 64200 63971 64057 63640 30100 62887 63131 31233 63760 31056 63959 63334 62813 63498 62675 31116 29887 30978 63453 63087 63764 30123 64440 30410 62529 63500 30722 63654 31570 62908 29763 63639 29830 31377 29810 31554 31727 63954 30985 31511 29953 64016 63494 31061 31229 62820 63616 63463 62805 62745 30026 31017 63304 62762 63633 30686 30541 30807 62890 63741 64025 30191 63916 31239 29938 30389 31611 64467 62837 64098 62864 31500 62624 63290 63903 63230 62920 30892 62635 62755 63422 30581 63915 62938 62864 30391 31525 63839 30760 30749 63017 63924 63680 63317 64373 31088 29790 31126 64473 62484 64051 62825 31458 64264 64260 30471 31619 30479 30131 31396 30099 30070 63703 63725 31536 62705 63154 31060 31198 63425 31338 30185 30585 31109 62724 63696 30901 64438 64087 63961 31494 31687 62830 29786 31387 63424 63316 63151 31583 63904 64247 29708 30018 64222 62832 31116 30047 31620 30389 63480 30917 31687 30356 31409 64075 30347 64306 63827 64321 64170 62845 30457 30002 62900 30921 30123 63649 62826 63819 30462 63843 30319 64162 31631 63741 30834 63695 63556 64495 30644 62796 31201 31462 64453 63448 64262 63820 29868 63845 64323 31465 63010 31076 30905 63408 30852 30625 31003 30272 31073 30309 64066 63945 29868 31222 31724 31733 31706 30705 30533 31316 29930 31643 63466 30983 30143 29880 63717 31201 64330 62884 31150 30279 29957 29919 30537 31523 62804 64380 30681 30569 31652 30619 30154 30790 63948 29790 62644 63501 29999 62527 29776 29752 64266 31710 31000 63534 29730 63840 63709 31308 62479 63380 29918 64104 62821 30986 62840 31627 29984 31433 62627 30686 63705 62483 64337 30402 64501 30919 30385 31562 62557 63750 64394 31716 62887 30455 30942 63867 30998 30559 64136 30534 63400 30708 30303 30131 62813 31342 31308 31233 62768 30726 31120 63005 62920 63228 31707 63048 63748 62921 30929 63703 30070 31075 63198 31419 30999 31573 30999 62659 30659 64423 64101 64116 30420 63736 31317 62906 30041 63447 62961 62710 30773 29874 31151 29853 64164 31498 63504 31677 63914 31570 63790 63853 62686 62663 63616 63144 30925 63230 31476 30160 62563 64367 31671 64094 62645 63670 63083 31565 63955 64399 62633 29758 31469 64149 30727 30674 31674 63016 31604 31063 63474 30887 62801 30648 30288 64231 30067 30151 64203 63505 30403 64250 64148 63231 64289 29770 62932 29880 31669 30643 31703 29841 31206 63775 31712 30628 64190 31740 64363 30815 31680 63485 62987 31418 64486 62584 62648 30719 31567 30495 64109 64125 30317 63687 63319 62594 64212 62596 63991 63680 29899 63897 30388 31103 63278 62958 31526 30751 62615 31521 62598 63058 62927 63400 31083 63590 64191 64177 30771 30201 30986 31210 30701 30025 63878 64181 63074 30440 29707 64056 30635 29747 30345 31700 31440 30654 30403 63194 63280 63312 31342 30238 63273 30442 63212 29859 31479 30958 64225 30377 63039 63221 31687 63051 64293 64407 64104 30650 31197 29995 30428 30766 30950 63847 62695 63931 30534 30469 31019 29977 62988 31632 30605 63309 63405 64386 30228 63841 64286 62726 64073 62630 29876 30460 31002 64368 63522 63560 30933 29806 30723 30100 31208 63445 30830 62561 63435 31356 30180 30139 30472 31082 30926 63430 63032 64283 29972 31709 30886 30893 64351 63478 31069 64104 31105 63796 64208 63195 63107 63980 30348 62610 63333 30945 29752 63957 62710 62509 63791 30620 63480 63885 30804 63493 62998 63000 62627 29862 62902 64285 64338 64028 30757 62611 62843 62779 30425 64452 31303 30549 31580 63243 62678 63039 64464 30360 62581 30292 30846 29849 30446 29950 30195 63092 62696 63688 64211 63969 31112 62984 63214 30262 62474 62960 29940 63718 30453 64295 63756 63180 63504 63687 63881 63102 31023 30017 63256 29994 63898 30974 31732 64365 29795 30953 31061 63535 64392 64052 30997 62920 63145 64229 30614 30277 64329 64478 29940 63310 31741 63240 30902 29805 30479 29789 30152 63730 31261 63758 63452 63394 30280 63265 29892 63736 63186 29773 62501 30691 30872 30198 62996 31651 63330 31608 30325 64323 30213 31098 63645 63616 30346 29967 64051 30717 63137 63291 30317 62561 63219 30962 30189 64376 30956 30292 31011 30746 29981 62500 30299 62808 31654 31356 30726 64508 31401 31741 31616 30020 62812 64168 64181 30896 62941 64423 29970 30048 30494 30511 31563 63817 62861 31604 30884 30008 30334 30412 64497 64185 63699 62547 64078 31548 64407 62584 29797 63392 31723 64029 64299 63180 62921 64024 63540 31709 29709 62722 62574 63033 31722 64052 31357 31403 30177 63212 30218 30314 31196 31392 63900 30153 64281 63608 64380 31222 63291 30987 30330 31389 31739 30626 30930 31262 63663 30096 62641 29861 30816 31435 62736 62651 29765 63790 63397 62885 31238 30303 64132 62793 31320 31239 63170 63196 63225 31289 31274 30167 30826 63504 63414 63822 62530 31428 30970 31392 30246 63032 63495 62545 31630 63620 30932 63387 64121 62618 63192 30635 31625 30785 30302 30672 29987 30636 31526 63661 31464 30341 30144 30753 64417 64470 64107 30349 30893 31286 62680 62875 63518 62702 31691 62840 31097 63243 63521 63316 63853 63925 63018 31625 29775 63403 31221 63274 31264 30534 64097 30000 63116 63098 63943 29999 63686 63444 62580 63271 30596 63852 29877 63218 31372 64466 31124 30841 30182 31406 31235 63948 30668 30821 29702 31185 31628 31324 64366 63044 63233 31724 30700 30618 62601 31409 64325 63422 63189 31280 62542 30794 64089 31266 63571 31720 30316 63190 64304 63194 29918 62711 31408 62995 64462 63760 31485 62630 63125 31311 31265 62675 31677 31460 31632 63985 29733 31666 31028 64340 63365 31649 64185 31226 30031 64473 63653 30063 30084 64458 63678 63761 29873 63718 63849 64470 29822 30618 63653 31408 62961 31080 64023 30732 30152 31423 30796 30589 31011 64014 63109 62937 63917 63713 31404 64370 63581 62823 63016 31149 64383 63220 29966 63429 30191 30171 30697 30355 30756 30072 64015 30947 31235 30993 29804 29758 62762 31364 62992 30969 29968 63782 64192 31522 63527 62599 62576 64096 31272 62993 29859 30543 64148 62882 63513 30767 31210 30643 30021 63143 62761 31726 30203 31084 62910 63353 31345 30237 30650 62711 64366 29875 63252 31453 64425 30561 63968 31458 63293 30750 63211 29949 30258 30343 31035 64131 30774 63907 30966 30208 63311 62576 64469 31421 29839 63506 31609 31655 62788 64412 62722 31538 31197 30090 63006 62975 31272 30871 64244 63396 31514 29965 30146 31657 63021 29745 64340 30534 29711 63456 30631 62922 64204 63167 62731 29862 30669 30920 31161 30874 63300 31691 30887 29870 62902 63092 64505 62902 29747 31331 63529 63921 63281 63102 63977 63046 63803 29974 30881 30483 29977 30895 64189 30816 31106 63657 30041 63050 30274 30147 63652 63647 64143 62567 62967 30528 30913 30130 30922 30207 30258 30013 62610 64227 63808 62864 63486 63068 30068 62809 31377 30625 64300 64304 30753 29713 30855 63816 63068 63467 64428 62647 62494 63300 30134 31049 29789 30815 62714 64123 63616 30027 31274 62471 63919 64104 63435 30425 30455 30314 64273 62785 63823 31671 30393 63472 29923 31461 63571 30982 30250 64322 63440 31310 31507 31739 29925 30711 29887 31379 29845 31595 30031 62483 63834 63487 62685 63984 29807 30858 64496 63719 63233 63250 64018 30751 64327 30727 64265 29721 64183 29729 62559 29922 63979 31300 63689 63376 63949 64295 63154 62731 31015 63188 30708 62775 30554 62769 30954 30908 30843 29758 31550 31341 62937 30574 31738 62802 30392 29725 63661 64252 30989 31021 30965 62804 29714 30656 63662 31281 31438 30154 31172 31186 30695 30844 31302 62583 64399 31611 62780 63884 63085 30695 30426 30023 62561 31054 29925 31543 63953 63729 30185 63610 63941 63649 62494 31644 64433 30052 62990 30824 30405 62866 29949 31660 30460 63436 64028 30400 63392 64178 30177 64059 31465 63063 31426 29746 62825 63654 30137 29894 63827 30165 62560 64133 63137 31359 64215 63227 29999 64084 62545 31525 30337 62479 62464 63882 64025 64314 63333 29747 64283 31359 30477 30203 30509 62573 63993 30997 63284 64436 63913 30215 63597 31723 30325 31163 30567 63796 64348 64192 31095 30756 63145 63053 64476 63797 62822 64168 63001 64156 62839 63943 31129 30224 64230 62644 62862 64293 63334 64504 62575 62909 62955 62612 31312 30952 63944 63121 64315 64274 30723 63728 62739 31521 31325 64010 31584 64201 62589 31710 30092 63178 31265 30242 30510 62676 30505 31385 31320 30006 30750 30251 63260 63467 63586 30848 31319 63652 64037 63478 63647 31196 62525 30036 62676 64160 63374 64478 31552 29822 63403 30784 62809 62683 30235 63555 30054 63322 62692 62738 63831 63543 31401 63651 63145 64244 30929 29786 30638 30000 29718 63110 31321 63240 30208 30299 31008 63323 63042 63159 30141 29812 63226 63861 63052 62703 63972 64172 31546 30229 31241 63767 62935 30537 64214 31458 63040 63659 62731 63804 30153 64187 62696 63653 31301 62669 64444 63591 30521 63589 63447 30742 30817 64431 30051 30124 64257 63093 29999 64344 62945 63152 64056 31532 62531 62962 62725 31502 30371 62672 29879 63878 62844 63677 30457 64254 64394 29948 30809 31179 31447 63065 30271 31585 62478 30407 30016 63174 29979 62525 64373 63348 63807 63333 63759 63689 64085 31319 63696 31498 30749 62507 30109 30135 31205 30221 62482 63031 62802 63152 30576 63784 64245 63489 63729 64099 63074 63844 63986 63094 30407 63794 30781 30901 30232 31010 63683 62527 64069 30035 31301 31323 30507 63696 63588 31128 63752 30407 30475 30373 63561 62637 63011 31257 64076 63063 31200 29967 30035 31715 64439 31045 31595 63737 31228 29803 62677 63741 30465 63674 63330 31638 30992 30294 64471 30195 62702 63965 64453 30499 30418 30531 64344 64251 62466 63403 31295 31070 63730 63022 62817 63404 63145 31064 31298 29770 63992 31675 62738 63585 30277 63305 30396 62688 64423 30314 63205 29801 30310 30067 31464 63839 62909 62480 63294 31160 62464 64078 29845 31390 63167 29954 31311 64160 64251 31080 63640 63226 64024 29857 31402 64253 64356 64186 63428 29741 63662 63264 31547 64448 31112 29763 63283 30528 63572 31156 31420 29792 30299 31277 62601 30497 64467 30682 63732 63552 31303 63234 63430 63233 62628 62590 64504 31338 29779 30949 30604 64092 31113 31461 29721 62843 63071 63329 29964 62599 29842 63300 63385 63368 31656 29951 31200 31468 64208 30968 64252 62915 29970 29934 29728 63047 31364 62771 30151 62579 64086 30513 64212 63274 63094 30157 63350 30440 29802 63534 63598 64143 63482 31621 31520 64019 63514 31495 63802 63369 30118 63990 63699 30404 63526 62512 63224 64179 64422 63875 62531 30988 62689 63281 31362 63991 62902 64322 29781 63785 64067 31504 62921 63952 29821 63227 63360 64096 31292 62967 63918 63208 30450 30653 63558 63010 29955 30854 30227 31085 29987 64104 63453 63175 31410 30672 64048 30463 30901 64025 30335 31565 63821 63068 62537 64145 63000 62917 30800 30723 30710 64311 63557 31342 64411 63118 30806 63919 31426 63871 30312 31386 31620 31268 31028 31249 63401 63208 30488 31113 29825 64223 29984 64158 63973 30144 63538 30188 63701 63113 30699 30177 63070 30026 30359 63367 30566 31139 64243 64093 29786 30520 63138 64388 31364 64054 62560 30310 30302 62510 30538 30137 62503 63492 63572 64457 63175 31036 64106 31348 30843 30262 30184 63754 64287 62802 30464 31025 30413 31534 63708 62693 31072 63366 62975 31269 63623 63145 63061 30609 63956 30428 63883 30805 63767 30187 62466 62690 64254 63658 29974 63011 29750 31426 29848 63795 63004 29711 64363 31122 30382 30310 29988 30076 62606 62758 64095 63435 31054 31165 63141 62662 62649 64198 63047 63227 63615 30466 30635 63661 30062 30363 30388 63000 64079 64470 62959 30223 64101 63904 31519 62541 63042 30558 31597 62929 63520 63178 31431 30646 63146 31646 62661 30389 31549 63766 62946 63655 30922 64113 64452 62588 31575 31581 31310 30669 63209 63399 30477 64235 31540 63547 63251 31414 63405 30763 30994 30033 62476 63851 63501 63441 63859 30633 30997 63933 30580 63237 63656 31231 63119 63773 29959 30934 63771 62956 62781 31159 63475 31530 63506 31676 30743 63981 63088 64439 30688 64152 62566 29914 30103 31384 62939 63134 30137 31330 62723 62779 31593 62484 62825 31392 64339 64094 64140 30269 30868 63546 64364 30534 62530 63205 30253 31001 29994 30087 62604 63978 64369 63332 64296 64481 30694 31284 63784 63511 62498 31040 63883 31136 31400 31068 30267 62864 62847 63552 63321 62865 30839 63684 31108 62714 62814 64482 30131 31485 63613 63639 30177 64314 30377 63843 63046 63534 30143 62838 63718 30580 64075 64165 30863 64239 64017 30225 31368 31482 64267 31549 30471 64025 62525 63701 63676 31627 30980 30460 63543 2139095039 2139095039 +1024 30662 30528 30092 63668 31311 29804 29816 63666 30097 64203 63521 63890 64322 63230 30093 30106 62701 31468 63839 63772 30594 63388 30729 63085 30982 31544 30837 63512 63825 31546 64507 63742 64425 63910 31419 62500 29975 30672 63452 30642 63648 30210 63486 31555 63250 64283 31453 63486 64183 63249 62530 31645 64069 31549 62645 31246 63765 31118 30122 31469 31227 62519 30929 62745 64218 31178 63991 30824 63142 30923 31434 62991 30332 62824 62843 30932 63722 30870 31230 63407 63792 62550 63659 64146 31107 62787 63374 29762 30633 30106 31671 62983 30424 30603 63933 31233 63351 64192 62510 31399 31524 64393 31417 29906 62591 64136 64426 63603 30301 64385 31455 30336 64367 31110 62711 31395 29797 30060 29709 31473 64058 63420 62849 64136 63343 31727 29805 30742 63454 31015 31633 30699 62933 63303 64430 31170 64500 64351 30574 63834 64406 63417 64273 29886 30007 64096 30502 31612 31159 30732 30417 30380 63011 29786 62821 30771 64311 63087 63027 62567 31221 30951 64361 62966 30132 29701 29769 62663 64505 29957 30106 62954 64445 62790 64154 31645 30842 63304 64379 30737 30071 31701 63463 30627 30403 30425 29755 30678 30295 63541 30209 30708 64267 64478 30145 62944 30067 31400 64394 63621 63362 31158 64335 62531 63671 30653 30056 63621 30763 63063 29976 63501 30503 63248 62478 31406 63538 63529 62538 63184 63512 29905 63573 63776 63527 64375 64137 62903 30522 30235 62832 30424 29753 30873 63118 30324 29967 63106 62884 63300 62696 64286 62986 64086 30688 31700 63555 31585 63481 62470 64421 63761 29934 64220 63212 30297 30204 62937 63126 63758 63749 63699 63599 63783 63966 63132 63405 29755 63915 31295 63265 64260 31133 31198 62760 62564 63185 29756 63604 64211 63885 63207 64064 30435 64416 31063 63536 63425 31496 62629 62578 31554 31360 63081 63183 29805 62616 30159 31370 31635 63000 30040 30174 63683 63391 63719 30073 62613 30574 30846 64143 30952 30295 64470 63199 62928 63861 30725 31721 63148 62706 30429 62785 62775 63700 63094 63802 63761 64033 64004 63907 31529 30349 62914 63718 30441 29810 64178 63294 63372 62916 62947 62599 31041 63372 31506 64294 30327 31007 30644 29882 31609 29954 63854 62758 29936 63065 64492 31673 30130 29872 62639 31453 64481 63214 30417 31498 30138 30810 31226 31104 30332 31636 31409 63488 62653 64354 31629 63103 62774 63304 30168 30920 31547 64142 31073 31137 30027 31645 63171 29781 63589 30238 31516 29823 63272 63656 63467 64408 63670 62520 62926 31159 30134 63724 30404 62518 30116 31107 30187 30041 31422 63463 31352 31486 62888 30066 31334 63383 62871 30928 31671 62977 31704 31076 30726 62833 63346 62958 63222 62816 30365 31564 31623 62911 63217 64494 29740 30292 63031 62960 29890 31504 30161 63344 63070 64068 63942 63572 63082 31091 64189 62846 64166 63310 64415 64361 62809 62628 63062 63079 30934 29979 30767 30339 30738 30812 31537 64451 31270 30155 29865 63026 63417 62742 30350 30312 31676 30379 31737 31481 64032 63748 30387 31236 30143 63982 30791 31610 64171 29894 63278 63665 31138 64451 31003 64014 63257 64403 62483 30603 29719 63376 31159 63733 64346 63260 64228 62505 63907 64116 30793 64480 31667 63103 62965 62651 64237 30074 63908 30042 30981 63864 30728 30029 62596 63797 64017 62948 63921 30005 31431 63721 30860 63533 64194 30401 63271 63639 63471 30366 30768 30291 64148 64482 30017 30770 62891 29882 63029 63197 29746 31332 62984 63074 30005 31168 31050 63923 31612 63489 31725 30199 30410 31104 31270 63520 29899 63568 31416 64029 30527 63274 63545 63870 31616 30407 30266 63721 31270 63053 31558 62672 64134 31649 30298 63278 31166 63723 29813 31480 29938 63892 31034 62683 63403 31696 30959 30156 30904 64460 64014 30150 64360 64149 64283 30430 63246 64323 62953 29941 29969 63911 31413 63055 30678 30520 29719 31324 31385 30591 30930 30741 63024 30287 31509 31290 64022 30135 30356 30871 31007 31738 30749 63559 29824 64479 31220 31732 64383 31318 62986 31013 31675 63342 63148 62550 30198 62686 30807 30244 63595 62622 64108 63075 31053 30827 62555 62705 63235 63875 63683 62988 63044 31456 62601 62753 63065 30987 30708 63146 64328 64325 30799 63591 31474 62487 29749 62487 30833 63264 29985 30839 31636 63787 31071 64387 30651 63441 63749 62722 31071 62658 63043 29896 64031 29778 30817 62768 30401 30817 63024 30519 62701 62806 30489 29710 63081 62782 29832 62570 31184 64328 63733 30242 30173 30270 31656 30834 31194 64008 30682 30904 29812 64097 29965 31223 63925 31204 63921 63544 62670 30460 31539 31258 63999 63696 64065 64251 30684 30642 63003 63072 31716 29724 62802 62820 31265 30465 30770 31011 30645 30001 62916 31627 30195 29715 30258 30765 31731 64155 63021 63421 63622 63028 30602 63332 64032 64504 31410 30071 30189 30958 62922 63667 63738 64314 31071 63618 63839 63138 63359 31453 64167 31648 30359 30830 29878 63362 30741 63419 30081 64508 63268 64260 31168 31194 63177 30298 62987 30839 31394 64097 31407 64228 64491 30980 30796 62926 62800 30186 62524 63124 63433 63472 64148 62652 63367 63122 29858 62464 30140 30894 31514 63042 30576 62590 31576 63445 30821 30501 29815 63111 31448 64060 29892 29859 30901 31443 29886 63377 63388 31743 63417 31582 63222 62499 31448 31339 63708 63964 31472 30539 63809 31703 63625 64471 29982 30402 31347 64038 64171 62720 63477 31043 31426 62505 62705 64501 63007 62541 30805 63557 63533 63616 63400 63979 63598 30654 64331 63573 63854 63403 63705 31230 62820 30288 62748 62988 64408 30398 29947 62937 30270 63411 31463 64131 31224 63431 63065 63964 63163 29790 63036 63848 31192 64024 63336 31655 63186 62668 62471 63661 30611 30849 30352 63159 63926 30818 63070 30333 29929 63994 30689 64236 30703 62879 30038 64106 62726 30228 62516 64266 63340 64110 31391 63662 62715 31398 30629 31227 30830 31102 31723 63459 63013 31125 64024 30005 64410 62834 62521 30583 64329 64479 30691 31659 63040 29876 62498 62926 63105 62473 30150 63495 63961 31676 62651 31239 30760 63665 63866 31722 31512 62479 63529 63451 64142 30723 63455 63697 63502 30788 64436 31063 30799 63038 30936 63700 30158 29916 64141 30250 30835 62986 30674 63344 31203 64505 29821 31401 63273 31368 30406 29759 30654 63669 29991 30394 64195 62589 64300 63556 63836 30478 63729 64391 31665 30446 31357 62657 31301 31717 31169 30471 30873 31284 63684 62566 31623 29898 63545 62666 31312 29776 31443 30662 63168 29904 31183 63065 64270 29757 64502 62492 30559 30190 31513 63721 31369 30274 64479 63381 31544 30384 31093 29800 64068 31407 63830 30580 62480 64469 31621 31361 63449 29955 31403 31261 64098 64354 31663 62491 62830 29974 63481 31112 63658 31628 30796 31708 30639 63746 31643 31124 64230 31488 63731 64122 63694 30587 30820 31163 64196 64473 31502 64435 31422 62624 30507 63274 62656 64292 29863 30710 64340 63864 30171 30863 62902 63474 30944 30097 31295 30417 63298 30551 62931 64078 29787 29906 30868 63937 64469 30659 62806 64276 63835 31197 64443 30411 30683 31033 31015 30895 30829 63303 64414 63061 31540 31393 30608 29975 30158 31329 63780 31302 30603 63812 30391 31426 31360 62570 31371 62793 63607 63624 31670 31722 63297 62621 30063 63949 63767 64188 63550 30172 64446 62827 62659 64246 63526 31704 31520 63213 30357 31205 29728 30496 31732 29834 63351 64082 62555 63800 63192 30248 64326 31252 30220 30001 62771 63547 30874 63301 30357 64231 63684 63736 30780 30486 63813 30161 63180 30583 30097 30111 63399 29970 63123 30184 63835 63473 31339 31435 29791 63598 30769 30561 30843 62701 63461 30872 63040 63370 62636 29991 64462 63307 64266 30721 64227 62487 63528 31125 30163 62642 63480 30978 30361 30413 63365 64195 31717 64034 63835 31627 31415 29909 63057 31368 63817 29767 63161 64123 30014 63956 30056 63933 64509 64068 64032 31491 62630 63990 62850 29708 31639 31396 31386 63791 31310 63325 31552 30470 31343 29753 31242 31105 63323 30350 64425 64221 30699 31397 30717 63951 63684 62803 63046 64162 30553 30539 64158 64209 30505 31652 30325 64151 63412 30483 29967 62982 30860 31716 63486 62729 30722 64478 29736 63440 30129 64295 29992 63364 29891 29746 29862 63671 30741 63475 31271 30973 63294 63260 63115 63072 31432 30462 31388 30103 30619 30889 62778 63760 31663 62652 62968 62527 63363 30848 64132 29960 30541 31180 62677 62841 30495 62682 63484 63982 29896 30845 63630 31403 30527 30860 30053 29770 29826 63085 30019 30723 30188 62971 64187 63914 31235 30267 29899 31664 30342 63047 62887 29929 63791 63860 63459 64107 64116 62605 30986 62502 29793 64004 29787 63455 30414 29863 63000 30488 63492 63659 30176 63005 30368 30350 30923 30616 63367 31333 30148 63402 30619 31510 64498 30203 62989 29862 63638 64419 31322 31459 62901 30660 63942 63705 63226 31418 62476 30533 62539 64333 31287 64142 31697 31367 30249 31691 30392 63488 63621 63887 30491 31269 62606 63879 62545 63778 63151 63320 64135 64063 30064 64163 63747 31364 63388 31284 64158 63105 29894 31247 64401 30692 30185 63829 63159 63807 64215 31341 31166 63903 63482 63201 31518 63958 31309 63825 30933 63881 31434 63527 63347 64442 63395 30038 64166 63610 30363 30569 30789 30277 63905 64445 64336 30492 63106 31182 63803 30968 63825 30529 63844 30693 29777 31362 63924 62988 30907 63393 31454 31460 62825 30405 30195 62846 63697 63154 29833 63880 31323 63056 62762 64431 30955 63999 63392 31005 63178 30620 30089 63874 64165 30730 64131 30478 63723 30599 64034 30676 63651 30668 64287 62691 31037 64169 62888 30983 64254 29772 30364 31273 30237 29965 31321 31063 63434 30327 64450 30888 30954 63723 63707 30460 31142 31046 30714 63212 63324 63065 30100 30207 62831 31285 30793 62501 63689 62657 64419 64412 30192 63032 62944 64197 30172 30157 63507 62699 31037 30501 30587 64046 63347 62764 63554 62797 62783 30042 30661 30199 30634 64085 30107 30923 30834 30675 64172 30971 30363 64371 31579 64049 30190 63857 30372 31545 62744 63127 31199 62657 63700 63822 64406 31523 64317 30774 62941 63849 62604 30338 31605 63192 31657 31015 30974 31646 63263 63225 30424 30416 63792 31393 30118 64416 63133 63695 62973 63617 31218 30414 63516 29934 31001 64116 63400 30254 64492 63722 62642 31636 63635 62514 63574 63183 63321 29916 63205 63152 31214 64002 64141 62922 30131 31344 30066 64337 30576 63103 30180 62798 30575 29956 63666 31714 62985 63183 64438 31198 62541 63601 63914 64480 30230 63417 30677 62663 63643 62967 31740 64481 62721 30825 31003 62643 62910 30961 64352 63154 63407 31101 63970 63442 30067 30233 63979 63732 30984 63588 63120 29733 62962 30463 31562 31070 31497 63817 63989 64157 30182 31491 64255 31673 31573 63065 30886 64184 63778 63595 63912 63205 63856 30129 64428 31652 31587 63496 30271 64162 30953 62977 31190 64329 29859 63551 31474 64230 30911 63354 63764 31706 64015 63173 31549 64254 62722 62765 63380 62825 30122 31089 30122 30705 63239 62705 64140 29806 63785 30327 62979 63204 62799 64098 64068 30414 31455 31171 62896 29895 29904 30151 31365 30419 31683 29776 31696 62484 30089 30294 30121 62501 62732 64229 63470 31337 30019 63737 30855 63106 62778 64300 64323 31001 30063 63242 30483 31379 30382 31444 30971 64026 31565 30603 31124 63079 31499 63042 30945 64284 62577 64177 31524 30982 64247 62576 31414 31299 63561 30863 62542 63615 29785 30059 63977 31640 63838 64347 63366 30352 31496 64344 31677 63526 29819 63578 62889 64005 30617 29751 29884 63205 63259 31205 31504 62837 31101 31416 31604 64213 31646 62520 30061 30489 30593 31674 31253 30578 63795 31065 31217 62500 62464 63228 64164 31176 64361 63564 30182 29987 63142 62908 63598 30262 30029 62933 62692 31637 63063 31742 29782 62530 31268 62898 30406 31567 62955 31594 31264 29712 63769 30471 63077 63486 30135 31643 63121 31073 30240 31338 63239 63078 63419 63848 31295 30643 62718 29772 31270 30558 30352 30838 30904 30286 62742 30747 31243 30384 63746 64510 31692 62897 63712 62906 63940 30481 31290 30497 30643 64466 62980 64402 63014 30019 64160 30621 30265 31249 63036 29860 30150 29969 31462 29884 30200 31221 63507 31197 31673 29833 29911 31455 31436 63659 63689 63103 63786 63286 63069 31369 62869 64390 63729 63920 31626 64216 63073 30999 30685 63723 29947 30912 64253 63465 29942 31351 29946 62790 31266 31488 31571 31408 31355 64003 64291 63512 30952 30302 31174 30115 64476 63517 29915 30304 64185 63003 62873 64193 63380 63839 30451 31099 63862 29780 63455 64088 64506 64082 63529 62500 63574 63724 31330 62957 31348 31533 63752 64119 63036 63894 62606 30876 31499 63977 30176 31227 30611 63622 62974 30089 29853 30985 30718 31349 30484 31691 30834 30299 29893 2139095039 2139095039 +1024 63960 31359 63204 64248 30533 64146 30782 30382 31405 30015 30091 31134 64245 31059 30626 29721 64131 30326 64277 31737 63634 31174 64311 30691 30033 63598 63256 63021 63278 63241 30806 30943 63010 30183 30843 64347 64190 62816 30989 30259 63569 31480 30990 30324 30007 29742 31093 30431 31308 63465 31350 64159 31561 63817 30852 64421 31341 63626 62984 62907 63936 62486 63183 63160 62780 30249 30316 30590 31593 64013 63859 63705 31267 30859 63425 63866 64340 29965 30276 31671 63951 62914 63505 63121 63139 62588 64228 62948 30552 30348 63480 62626 62619 63146 63800 62762 63036 31731 30291 31081 64010 29777 63238 31084 31740 30425 30150 31312 62861 63158 64176 62970 63059 63075 31204 31458 64480 29932 29715 30366 62626 62824 63837 29757 30501 64441 63888 63411 62678 30016 31368 30682 64265 30664 30330 62664 30718 63285 30379 31701 64489 31701 31119 31381 30907 31733 63161 63701 30933 29736 63847 63682 63674 63584 62508 30790 62662 63310 29763 64230 30502 30221 63033 64020 63943 62539 31103 62559 64497 64275 63794 31169 30582 63744 31290 62883 62514 30679 64084 30257 63286 30561 30689 29810 29734 63651 62760 29762 62560 63105 64280 63795 64236 31075 29946 62933 63158 63655 31383 63666 31424 63265 30251 30642 31545 62670 30562 29854 30259 64041 62924 63461 30705 62755 30182 31295 30425 30578 64060 31406 29763 63228 64257 63557 64295 63139 30650 31474 62536 29947 63610 62777 30616 29997 64385 63555 30845 30407 29832 30097 31566 30171 62650 30776 64375 30529 62878 31296 30507 62997 30188 30692 63928 63299 62804 31254 30459 31723 64348 63224 30593 31031 31421 62783 62941 64194 30617 64036 31232 29813 30326 63145 62626 29832 31580 30753 30870 29773 62580 30591 30013 31707 62547 63858 62582 63711 63257 31548 30250 62578 64086 30792 31234 64400 64211 63593 31083 63781 30518 63559 62476 30447 62907 63781 62874 31125 30173 63254 62973 30073 31461 30584 62731 62592 63198 31072 64077 63551 30031 64451 30526 63916 64333 62567 31409 63882 30150 29789 30938 62550 62947 63421 30741 30224 62567 64239 63266 63732 63728 63450 63998 64171 64270 31003 30720 62537 62888 30496 62524 31126 30034 63372 64505 62940 63662 30386 30732 63091 62739 30211 63055 63503 30019 63181 31357 63847 30402 63571 30537 31490 62779 63637 62813 30301 63884 31463 31355 29728 30743 31200 62990 62616 63817 62847 31712 63619 31588 63976 29763 30710 64293 64127 30139 63908 31257 63513 29773 31450 63673 63607 63297 31193 30946 31691 63472 63688 29709 62740 63380 62518 30436 31737 63516 63976 30110 31556 63702 30640 63980 30182 31064 62952 30177 63521 31609 29736 64067 62937 31567 31585 31105 63064 63601 29707 63141 30507 31286 31418 29828 31101 30566 31728 31092 64215 62488 29738 30467 31072 62525 30743 30642 63062 30356 63980 30173 31096 62622 62653 29747 30230 62840 63362 29860 63257 64327 30289 31365 30395 64078 63964 64187 31711 62551 29826 64400 30308 31724 30116 29728 63217 64156 64256 30320 62730 30548 64237 62518 31092 30873 29966 30469 31418 30739 31071 29798 62526 30113 63384 30416 31029 63907 29901 31359 63649 30116 30062 63355 62892 64255 30845 62667 29916 30556 63557 62792 62746 62778 30713 29806 31287 64501 62568 63753 29896 31725 31640 63318 29885 63556 30661 63563 62921 63857 64247 63280 63696 30408 62614 31316 64076 64114 62521 30830 31628 31333 30828 31584 31234 30370 30381 62997 62667 30451 62955 63906 63499 31685 63177 31137 31456 64402 31705 63320 30946 62898 30366 63386 63403 63907 63798 63250 64256 63716 63466 64472 63304 63528 31545 62526 62546 31437 63852 63968 30003 64076 30928 63614 31390 63006 63926 63434 63492 31098 29738 30122 31454 31111 63906 63827 29916 64106 31626 64438 30630 31161 62552 30745 31528 30504 31380 31228 30192 31555 30884 29958 29826 29849 63618 63251 31626 63962 30145 63871 63709 64435 63791 30561 62819 63676 64462 31030 31340 62509 63715 29949 62746 30222 30677 64031 30453 30889 30965 64036 30957 30711 29745 29781 29927 30046 31286 30501 30063 30942 29890 31493 64079 30003 30428 64258 30412 63223 30448 63105 30753 30620 64312 31460 30048 64453 29938 29845 64419 31626 64074 63986 30437 62770 64077 31576 62945 63180 31005 29892 30854 30802 30792 64073 63860 31733 64496 31367 30457 31445 62696 63078 30183 30364 30725 31505 30195 31067 29725 63945 62502 31337 31093 31388 30924 30527 31675 29882 64305 63838 63819 63150 64199 62504 63511 31169 63187 64463 62495 63766 29961 30735 62586 62964 63426 31394 29804 30792 62965 30592 31200 63262 63714 30198 62701 63536 29720 30650 31497 64089 30926 31180 31421 30038 64013 30303 31697 30433 31109 30482 62949 64361 64465 62913 30518 63099 62978 64237 62782 30344 63235 63583 63201 31130 62504 63751 29942 30758 31358 63701 62604 62877 30362 31546 31166 30624 30703 31731 62554 31481 63887 30750 31425 62696 63041 31271 31280 62775 31438 63122 62644 63560 63936 63473 63614 63729 31280 31091 31081 64347 30807 29818 63760 30538 30344 64051 64005 64469 62676 63535 30538 29721 63853 31517 30260 30538 30561 30774 30428 63439 62581 31616 62918 64482 63904 63497 30468 63190 62670 30090 63062 31107 29805 62531 31122 63517 29944 62839 31488 31497 30438 63533 30161 62791 64351 30773 31468 64306 31096 64341 31139 29768 64268 63133 62598 31115 62808 64449 30629 29923 31282 30855 29768 63364 31151 64366 63322 30564 63980 62839 31709 31378 30289 30322 63475 31525 64428 31322 31058 30215 62576 62759 30835 63899 31627 63586 30402 30747 63825 31361 31700 30979 30524 63954 64315 62508 63520 29827 63617 31454 62694 30739 63260 29926 31741 31503 62474 63240 63373 62728 63853 62499 64461 30865 31343 30732 63559 63060 31168 30803 62540 30345 30757 62619 62787 63339 64224 62927 63342 63860 64253 31037 64465 31070 64097 30191 62691 29932 30014 29746 63382 63170 64006 31691 63598 30825 64489 31129 30258 63268 30804 63176 63043 29746 63846 63633 30665 30435 63534 64231 31729 31493 63488 31252 63650 62466 30703 31195 30864 30158 30602 30758 30144 62990 30151 31052 63931 31002 30507 64239 30600 63639 30401 30336 31460 30356 30753 30838 29845 64437 63152 31092 63206 31399 30089 29770 63581 62958 30873 64255 30438 62841 31699 31335 31541 64019 30593 31689 62875 63292 64440 30654 30397 30578 30508 63615 62546 64052 30906 30897 31622 63829 62661 29747 63502 30468 63353 31266 29836 31054 63424 30504 63003 30565 63033 29966 64472 31019 30597 62737 29840 30564 63533 63954 30854 30356 31488 63501 31675 62839 30457 30590 29960 64376 30269 63388 31177 31050 30733 30774 30536 30927 30150 62629 29977 62954 30257 31343 63001 30573 31434 29817 62492 30967 62866 31365 63278 30457 63780 64187 30779 30572 63787 30585 30351 63071 62632 31464 31440 30531 29808 30938 62745 31248 62520 31137 30025 31250 63293 64473 63184 30260 62925 30001 63685 64102 62607 29742 62831 62991 63295 30900 64361 31004 30946 30044 30875 30389 62561 64153 30569 31528 63590 31035 63107 64048 63348 29947 30508 30330 62965 63272 64076 30307 63665 30703 31454 31703 30146 63167 31032 62964 29749 62876 31220 30302 31393 29946 63565 29713 63763 30255 30863 30235 63226 30752 62793 29855 30009 63263 30197 63105 29873 31384 30157 64125 30449 31273 31185 30645 63541 63796 30364 30588 62994 63247 64227 31518 62911 30131 63889 31205 63295 30052 30775 64445 31170 63486 62557 62503 62966 30988 63077 62486 62955 63004 63411 31348 63384 62978 62590 30039 30442 30195 29848 30415 29982 29994 64123 29909 29725 62761 30047 63950 64490 63619 62650 64494 30251 64127 31351 31178 63410 63196 30865 31166 63000 63278 29728 62863 29806 63295 62747 31110 63129 62902 62631 30968 63597 63518 64118 30873 31298 62596 30070 30558 30082 30154 63105 63883 30600 62921 63527 63451 29967 30698 64275 64177 63422 31401 62650 63951 63599 30755 30690 30595 30986 63868 63019 63804 30212 64110 31541 64111 31410 63248 63394 30342 63193 30325 31118 31367 64487 31677 31127 63370 29969 63699 64483 64361 31354 63159 31232 31013 62785 30240 30768 62915 63952 31595 63258 62507 30909 63322 64449 31476 64033 31008 31035 63126 62648 30900 30967 31270 30783 64249 31214 31338 30032 31286 64290 31011 64051 63237 64414 29727 30218 64030 62913 63634 29821 30924 62689 30820 30584 30160 64257 63179 30315 63795 30603 30738 63224 63270 64286 64412 63120 64441 31076 30096 30495 31274 30340 64134 64224 63252 64237 31294 63806 63347 63751 63554 64281 30343 63187 30590 30128 64500 31464 31614 63942 31100 30874 30767 63910 30341 30394 30043 31246 63186 62930 30944 30070 62633 62836 63246 29935 63452 31424 29995 30727 62587 62779 62693 31700 63367 31267 64370 63982 29717 62883 63445 62515 30047 64345 31442 62623 63210 62790 62878 62670 63420 30276 64314 63630 31410 30888 29701 31251 62525 63407 63665 63017 31582 30944 64085 63208 64426 63838 64501 31288 64209 64443 64415 31474 63424 63716 63138 64493 31242 62907 62909 63445 30437 64249 63003 31522 30790 63936 62609 31616 64344 64443 31486 30921 29841 31111 62840 63115 64217 31168 31301 63925 29949 30469 30462 63856 31596 29972 63119 64171 62488 62495 63498 31568 62786 30630 64119 30212 63333 30732 64500 30106 31241 31470 30015 30903 30375 31324 31615 63163 62977 63592 31472 30991 29778 63629 62613 31270 64505 64009 64415 31340 62553 62465 31222 30808 62816 63190 63921 63065 64177 64505 31039 63469 64441 30570 63882 29945 63497 63125 62651 64189 30028 62826 30818 30678 62817 29819 30320 29740 63493 30367 31191 63542 30880 30956 63541 64214 63343 64008 62562 63269 63582 31473 64108 64233 31498 64182 31448 30402 62604 31687 30306 62533 30858 62759 29736 29972 31209 62646 64035 62902 31449 31713 30030 63417 63380 31701 30256 29857 31657 63893 30023 62553 31161 30313 30493 29918 64238 31688 63031 29772 30185 30116 31164 31273 63589 63623 62883 30928 63621 63893 63010 63575 62501 64228 30788 30177 31201 63588 30005 62791 63453 63844 64408 29962 31204 30453 63266 30329 63277 30478 63802 31215 31047 63746 64216 31367 30413 30153 64478 31103 62653 63131 31392 62879 63763 62490 63095 63522 29744 63939 31301 30378 64042 64480 29944 29764 30758 31742 30437 64363 30804 63935 30478 30150 63500 30505 30908 63727 31102 31659 31584 63741 62621 31223 30312 64483 30302 31325 62808 63048 31469 64482 63289 31386 64101 31440 31066 29962 63040 62887 63250 29736 64474 29793 62960 31243 31144 64297 62578 63056 64396 29725 62832 30300 63911 64368 31018 64477 30375 64177 64142 30216 31101 63686 29893 30842 29812 64077 31099 63609 31147 30660 64334 62666 64063 63669 31286 31297 31080 31031 62497 30644 62819 30219 31308 63716 62660 62590 62537 31579 63188 64070 63372 63973 31327 62557 31573 31052 31605 30892 31386 64409 62604 29998 31683 30025 64095 31453 31140 30656 29697 31553 30499 64115 30180 29757 63292 31517 29796 30466 62768 31067 64365 62881 63707 31583 64480 62793 62935 30671 63182 31120 30388 64064 63130 31526 31271 62930 63048 30941 31264 31653 29924 63861 64058 30868 29718 31127 29894 31321 31530 30814 64090 31271 31300 64210 30508 30181 63964 62489 29998 63311 31630 31024 62547 30426 64247 31666 31094 63532 31049 64044 64064 30856 63911 63400 30704 30677 30303 30852 30716 64161 63709 30412 64288 63297 30530 63336 29920 62533 30477 30649 30651 30363 31579 30916 63488 64154 30108 63864 31503 29930 63480 30351 63924 29711 63277 62559 30533 30135 62497 30024 63290 30075 31144 31689 30006 63276 30973 30351 64253 30170 31740 63025 31155 63781 63383 63103 30560 31576 29911 29708 62715 30626 31273 63736 30932 63092 30629 31641 62986 62528 63902 63398 31011 63589 64376 31205 64504 31399 62864 30511 31619 30699 62522 62678 30074 63591 62582 63878 62507 63841 31230 30390 29741 30964 62808 31123 30935 63343 30388 30669 30880 64415 31734 31397 62515 30747 30054 63276 63196 29948 63987 30989 30130 63837 63559 63977 63859 64097 31064 63564 31383 64359 30625 30766 31624 30616 63494 64435 63055 62656 64047 29747 63874 63476 31346 31531 63169 62986 62983 64425 62592 31222 62809 63287 62826 62758 63882 63191 31603 63068 63639 64353 63184 64027 30191 64135 31266 62816 30349 30619 64162 62914 63256 63435 30043 29909 29999 30935 31268 30306 63546 31708 62615 29910 30185 30295 64342 64375 30651 62797 63606 29945 63594 64147 31688 31251 31148 63407 64350 63554 30349 30992 64085 30792 30059 62904 64337 31063 30536 31086 30116 30149 29827 31464 30981 31129 62562 31085 63319 29953 31159 31627 30198 63940 62894 30894 30328 30160 30681 29755 63396 63822 31577 62764 64145 63011 31608 30446 30573 30081 63187 64277 62836 30737 30651 30756 30064 30994 63875 63764 4286578687 4286578687 +1024 31354 64391 29925 63522 31365 62841 30018 29875 62562 29920 31482 31579 30429 31202 62652 62543 31142 62464 62903 31704 30276 64414 31679 30078 30148 63678 63939 30471 64132 30869 62945 64076 62691 63393 29726 30823 30094 30389 30577 64010 29699 30204 63460 63214 63676 30700 63064 29977 30463 30224 64354 63581 31557 62978 63267 63371 63052 63307 29926 30867 29977 62685 29849 30276 63237 30031 31115 29945 63442 29755 63100 64022 31222 63632 64472 30558 31231 64049 30619 30399 30428 63998 31458 31089 63927 63171 63249 31005 64122 30241 64387 30131 63029 64478 31049 63187 30666 64350 63009 31719 64155 64142 31363 30179 30494 63290 62981 31245 30130 30929 62615 30551 64311 30354 29827 30332 31051 64465 64170 63446 31158 30107 63842 30557 31069 30543 31268 29982 29850 30915 29965 31251 63067 64132 63930 29754 30843 30931 30193 63246 30414 30025 63721 63758 64038 64175 62529 62511 64072 30691 63295 30334 63999 63750 63894 31400 63492 31593 31647 30563 64175 31587 30660 63378 62842 29994 30055 63754 31365 30031 63486 63662 64153 30782 63352 62516 31439 31446 30393 63149 30336 31570 64412 31528 64120 29979 29697 31387 64425 62806 30940 64130 62635 29975 63643 63829 62966 30156 30105 62739 30974 31362 62739 62876 63073 31490 63582 64399 30810 30922 62784 31480 30833 62619 29760 31414 30853 62844 63286 30036 63052 30463 64182 30522 30459 31633 64208 30818 30247 62696 64110 64072 30384 29771 63523 62802 63536 31722 30247 62563 31538 63420 30168 63369 30516 29910 31317 31190 31375 63538 30766 31039 62587 29894 31044 31679 30612 30837 63273 63102 30129 62994 63438 31601 30792 63972 31618 30553 29746 63476 63518 63653 30992 62640 63801 62693 29745 30733 63074 63114 30384 63612 30508 31361 63481 30757 31150 63429 62691 30519 31310 31072 62594 63045 30084 31705 63671 63725 62861 30736 63082 31510 30945 63635 63321 63063 64305 64199 29815 31011 64467 30242 64450 30908 29830 62609 62724 31687 62819 64396 30458 29933 31697 63066 62626 63683 30240 63587 63381 30228 30418 63245 30768 62872 29699 63714 30126 31195 29752 63379 64171 31621 63625 29832 63124 63304 62996 30221 63042 64334 30949 31418 30153 30484 63670 62674 31104 63730 63671 62904 64077 63501 30605 30315 30189 31581 64471 30141 30758 30292 31018 30520 63763 30308 64250 30532 62957 30782 63625 63053 62958 62941 30627 64080 63292 31143 30918 63574 29726 29968 29996 31578 64000 30588 63031 29715 63032 63536 64107 30609 63458 62562 31131 62507 63096 64232 30464 62866 64095 63161 30782 63443 30774 63168 62713 30094 63961 64079 30799 30739 30851 63783 30683 62760 62621 30027 63681 63253 30228 31095 62615 30139 62742 63800 62628 29997 30366 29996 30804 30086 30183 62955 63714 30580 31243 62493 63201 30709 30085 62921 64060 31506 30468 62887 31088 62857 64429 63029 31293 31164 63041 30315 31112 64118 31090 64027 63519 29706 31695 63209 30903 63011 30280 31305 63385 29964 30154 63604 29860 63670 64355 62592 64141 31284 30213 31238 63260 30611 31705 63610 30103 63991 63880 64446 63180 31394 63717 31505 63121 62660 63615 30962 30908 63477 63474 30041 63003 62665 30397 30508 63664 64004 62894 31130 64184 29864 29714 31349 64098 64031 63943 62922 62675 31079 64216 64060 62644 30249 31360 64099 30061 30073 30219 63513 31565 31727 62621 30284 29824 30767 30905 30585 62486 63589 64092 63493 63969 63594 64096 62916 63776 63671 31402 31330 31286 64157 30353 64456 31084 64134 64510 62820 29984 64368 30945 31258 63840 63724 30781 63444 63861 31399 64110 31044 31554 31705 31056 31728 31104 63200 62944 63908 31407 30356 31612 62488 62508 63333 64144 63239 62924 62548 62670 64330 30283 63329 62736 31513 63456 29883 31442 63543 30949 29988 63756 62479 29923 31655 63211 63232 31301 62684 31021 29979 63081 62671 31741 62838 62994 63857 62618 30689 31580 64097 63447 62741 62848 30807 62733 64340 63359 29797 31736 63274 62727 62635 63282 30757 31599 29936 64169 62562 30912 63621 29888 31245 30508 64100 64397 31164 63759 29734 63301 31363 31010 64497 30299 29971 31253 62893 63851 29787 64080 31049 29857 64308 63712 30161 30949 30284 30318 30759 31026 64213 64033 30852 30874 31410 64148 30318 30212 31037 64431 64173 63256 63638 30271 30769 30528 31429 29873 31689 64068 62795 62717 62782 29720 29919 31503 64316 63671 62819 31242 62757 31150 64437 29894 31060 63662 31268 63456 29857 31576 64463 64126 30308 31344 30759 63972 63841 63804 63155 63699 30932 30355 63479 62828 63603 30291 63061 62471 30255 31166 63726 63987 31668 62738 30064 31602 29697 30555 31721 63166 63508 63705 29796 63391 30510 62879 30601 30643 29887 64236 30128 30359 29927 62821 30730 30462 30698 30893 63456 29790 30742 63613 62848 31219 63262 31049 29785 64070 62551 63516 63353 29786 31481 63023 62858 29706 63622 30451 63630 64336 30142 62918 62640 30863 29708 31505 62701 31500 29811 31259 62809 31298 31504 64496 63694 31067 63473 30695 30791 64442 31238 63579 31373 30255 63588 31185 64427 62914 31471 64386 64280 30249 31649 31682 29999 64346 62642 63584 31101 64194 30427 63534 62706 62636 31057 63245 63893 63827 62809 30810 30934 63193 62927 30528 63232 31350 30960 64190 64351 31564 63959 30784 30018 63081 64162 30380 64179 64001 31510 63865 30983 31494 64441 30122 31243 64315 31251 31036 64420 30081 64298 30967 30735 64008 29741 64362 30518 63358 30234 29725 30233 29810 63518 64377 30034 31582 30141 63311 30827 63917 63821 30654 63545 31252 30948 63555 64497 31679 62465 64043 30916 29918 63470 63382 30681 62609 30440 31621 63191 63646 30832 64181 64290 31418 30080 31299 30178 63881 30448 62559 62974 63769 30730 64298 30477 30599 30738 63533 31399 64203 63084 30799 30707 30380 31198 29978 64465 30664 63670 63966 29697 30170 62702 63168 30446 63267 63617 63541 31416 30566 29979 63191 30051 30714 64113 64279 63210 62867 63803 31400 62658 30619 31302 30501 62815 31360 31087 64299 63464 30638 31532 30016 64082 63110 30638 62636 62649 30352 64059 63662 62969 64395 62609 30663 63119 62887 64251 31246 63216 62832 63584 63679 64258 62950 63313 30585 29799 31499 62745 63642 31363 31701 62665 64147 62763 62533 63077 31407 31170 63051 31175 31144 31174 62967 64348 29915 63015 31067 63834 30265 64480 62766 30410 30412 63298 64428 63473 63875 29780 31117 62877 30943 31732 64064 64370 63587 30081 29931 31478 31267 62999 64216 63281 63794 63648 62767 62602 30957 31142 31282 30680 63317 30496 30070 63855 63516 62540 63085 63028 31148 63782 63589 31665 63935 31291 29861 31342 63786 30103 31581 63932 31290 62723 63151 62815 30797 29941 64246 30546 30444 30096 31071 62831 63905 31510 64029 31699 31108 62678 62907 31647 64025 64215 63750 63459 62979 31273 30760 64256 31506 63567 62968 62712 62843 29701 30284 62546 30011 31075 30605 29834 63948 30554 30253 64303 62830 63648 31109 62948 30758 62542 30487 62816 30829 63969 30679 63208 30186 30358 31180 63901 63881 63233 63354 63807 31333 31356 30642 30614 63966 62751 63756 63799 63776 63042 30105 63146 30495 63786 62700 30790 64510 31426 63625 63356 64428 30819 64233 29769 30153 30376 63977 30010 31316 29946 63108 63125 63344 29834 29799 62716 30807 62770 64454 62923 29761 62688 30388 30754 63978 30355 63124 64413 30460 30498 63985 29918 63713 64415 63558 62545 64083 64484 30695 62863 30691 31107 63938 31546 31253 63396 30544 30064 30088 62490 30059 30345 63661 64420 63448 62817 30714 30062 30740 63673 31493 29901 62579 30405 31713 29840 64383 63178 30336 62711 64159 62716 30078 62692 64450 63280 31272 30385 31467 31353 30527 63742 62874 63257 30311 31069 64227 64402 62828 63703 30345 62579 30397 30289 63254 31012 64066 29858 30933 29730 29750 64266 29788 30139 29891 30636 30037 63724 64035 31435 63104 30114 64468 63824 63044 62970 31712 63741 30341 30459 30284 63745 63251 63234 63261 31570 30609 30972 29768 31152 31540 31735 62827 29852 29970 30712 64384 62691 29997 63746 63116 64422 64492 64083 31339 30562 30566 63406 31616 64154 30727 29762 63216 63708 30471 63415 62599 30584 63784 62815 63644 62756 62997 63520 63161 29722 62985 30629 62935 30813 30855 63613 64010 63744 63433 62826 29771 30616 62940 63394 30838 31625 31569 62512 64303 31335 63602 62933 31207 29998 31070 31305 62611 63601 63434 31597 63479 62897 30453 30829 62576 64187 63455 64241 31254 30572 63162 63044 64080 63889 62711 29731 30909 64052 30587 64371 30505 62879 30087 30197 31346 63186 63257 31584 29938 30162 31649 31125 29849 29948 31457 30928 30971 31107 31414 30240 31507 64197 62765 63673 63577 63472 63815 62606 31650 31479 63862 62475 30401 31061 62647 31185 30284 63724 30415 30352 30271 63723 31106 30866 29707 62821 31277 63538 30557 30586 30585 30485 64382 64498 31227 63006 30271 62872 63471 29853 30747 63050 62672 30641 31123 64295 64455 30363 29706 63001 62711 62558 64096 62912 63317 63825 63668 62604 62812 64034 30255 31140 31552 30682 64074 31678 31607 62480 64229 30420 64145 31051 31195 63785 30381 30624 31381 63765 63382 31099 30840 31118 30086 30015 63207 31395 63133 31597 64416 63268 63381 30772 63881 63065 30595 29902 30460 29797 31553 30987 31391 63523 30635 63529 64430 63559 63884 30186 64140 31420 30772 29918 31541 30493 63586 62797 30063 63230 29902 30674 30443 30817 63620 31029 64355 62578 64485 63997 64142 63286 30419 63709 62553 30924 62919 30935 62818 63513 31241 63426 63023 63806 30584 63160 64177 29733 30823 62609 64203 31284 29998 29715 31153 30633 31345 31311 30980 62584 62781 63487 63749 29883 30348 63139 63340 31535 30952 63126 64337 62978 31648 62535 29897 31549 63371 62741 63563 30960 63315 64173 30161 30780 64287 63266 29878 62562 31623 31669 30118 62735 62750 29714 31641 30385 63016 63002 30771 30853 63401 31351 30000 30013 31637 30395 29746 29731 62537 30699 30090 30986 30030 62814 64235 62560 31213 64480 30575 31534 31312 63074 62628 62590 31237 62541 30475 62715 30947 29753 30506 31489 30391 30402 63189 63043 64288 63220 63725 64357 62638 64507 63559 30966 30574 62885 63350 64037 64485 63484 63943 62654 30632 64230 62774 64510 63589 30282 30685 62705 63896 63234 63914 30648 64502 63819 64464 63812 63285 63465 31503 64127 30728 64239 31491 31408 63702 63014 64300 31487 62994 63806 31507 31116 62944 31349 62735 31712 63794 31535 30728 31330 64327 30585 31296 62712 63704 62998 30428 30718 29972 62904 31360 62469 63074 30342 63754 30592 31036 30262 64467 31461 29821 31696 63387 62913 31482 30449 62776 30676 31589 29719 30023 31591 63977 31565 63794 31563 64253 63143 30856 31577 30587 30123 30980 64272 63119 63209 63250 63284 30376 30161 63777 30449 30141 30674 63547 30481 62986 31077 63134 31647 30572 63683 30505 31113 31055 31245 29983 63008 63871 30698 62590 30572 31544 64165 30510 30489 30828 63373 62588 63322 29783 30748 62966 62923 62717 30826 29723 63730 62966 62481 29792 62895 31589 63423 62692 31062 30153 29809 30320 29813 63788 63600 63402 63012 63187 64392 30491 30425 63087 63605 63512 62527 31344 31335 30202 31400 64082 31647 62823 30360 63816 63624 62784 64451 31454 30430 30370 29799 31140 63613 62882 30291 31347 30392 64185 63622 63395 64400 31099 63396 62515 30435 31080 62662 63144 30843 30478 30643 64272 64152 63912 30301 31257 63858 63583 30585 62977 62528 64467 63144 63649 62795 63911 64196 63440 64056 63646 63691 30437 30725 29697 63109 62498 64485 30083 30128 30535 63944 31717 63729 30263 63768 63992 30411 29865 30144 62655 31360 64113 62519 31605 64199 63884 30028 31005 30381 64259 63077 30492 64105 31256 63703 62746 30541 31396 64429 64203 63035 62630 63783 63470 30325 30575 63878 31005 30177 64064 30187 30584 62777 62940 30784 30733 30586 31571 62602 30640 31619 30577 62991 64251 64503 29801 31090 64070 31324 62895 63053 30360 64402 62472 29766 62626 62900 64061 31359 63328 62891 31729 62628 62678 30468 63593 64074 63284 31487 31198 62665 62638 63177 62721 29723 31546 29810 30429 30071 63926 30167 30124 62760 64116 30396 31573 64252 30939 30806 62912 62549 63662 63873 31602 31298 62949 64228 31183 31107 30221 30940 31275 63773 30798 30791 63639 30454 31303 29900 31636 29862 63049 31363 63176 64460 62657 29764 31705 30232 63149 29992 31138 30183 63528 63914 31400 63930 31677 62560 31203 63166 31482 63552 31159 62636 31375 63926 64189 29980 31010 31266 30523 30958 63530 29735 31718 63280 63054 31125 62482 64252 64173 31258 63773 31633 30180 63063 31488 30442 63507 63872 31025 63415 64005 30172 29715 29959 63671 62567 31008 64030 30730 30322 30855 30225 31493 64151 30022 63533 64492 30079 62780 64086 31620 31600 31340 64480 4286578687 4286578687 +1024 64023 30638 63104 30567 63818 63157 63410 30807 64393 63128 31015 30077 62759 64172 30727 62849 63972 62782 63007 31729 30136 29824 63957 30517 30803 30082 63086 63957 63603 29879 31552 29933 30839 31349 63303 63230 30745 30335 31001 63053 63471 31705 30507 30025 31612 31229 62498 62949 63777 64444 63853 31071 64224 62731 31672 29856 62931 29882 31209 63588 30599 62572 63690 31322 30147 63319 30332 64420 63943 63440 30995 64424 64095 31397 64320 62658 31053 64404 31215 62623 30296 63914 63580 31119 31390 30545 62951 63792 63618 30562 63963 30103 30591 30172 62464 64042 31057 30252 63723 31045 30735 63918 64292 30077 63815 63830 29731 63928 63535 30104 64417 64419 30199 64131 63281 63636 30715 63762 30155 30684 30132 64326 64273 29782 62477 29916 29727 62827 29750 64225 30094 63682 64419 30008 63183 62561 30413 30380 63456 29759 30213 30562 30136 29993 63125 63638 63575 63506 31485 62924 30334 30177 62977 63448 30307 62949 31550 29898 63820 63123 64469 30917 64224 63974 63173 30560 64177 62710 29901 63403 29998 63289 29874 30369 64012 63286 31672 31588 29979 30359 30593 62612 63135 31591 30856 31541 62781 63775 31174 64200 62576 64187 31023 31460 63304 30832 64090 31478 63495 62521 63514 63207 63390 63133 30667 29905 29823 62505 63520 63651 62555 63137 63642 31298 62483 31631 31135 30752 31666 30066 63168 31400 62923 31669 30614 63890 62785 62471 64021 31441 64315 29827 63873 62931 62480 64437 30976 62937 63969 64086 64330 31399 64462 64466 64190 64400 30758 30435 64220 63120 30313 31458 31670 31040 31713 63841 63933 63395 62987 31116 29771 31169 62693 31276 63378 29819 30651 64361 62489 64123 62629 30663 30510 30035 63647 64212 64058 63208 62871 31132 62513 64203 30800 30885 30360 62975 29912 31461 62749 63375 29733 30006 64077 31130 62723 63927 63695 63732 31303 29818 31631 30617 30995 64061 64154 31303 62577 62906 62867 63983 30787 63327 63882 31098 62932 31234 30740 30057 64352 62630 30643 62799 64161 62789 31061 62624 63513 30699 64029 31532 63609 31251 63026 30906 63276 62845 30504 31539 62962 64300 63965 62961 30556 63987 63649 30403 31535 63832 31319 64277 29910 62829 31041 63394 63884 31346 63418 31207 62867 62957 63346 63760 31423 31579 30491 30606 62586 64038 62927 64224 31155 30802 64352 64450 64214 64031 63160 62646 62744 63928 30799 30401 63219 63566 31403 30677 63353 64372 31511 64035 31256 62977 63160 30683 64297 63979 30706 31299 31385 63880 30282 30032 30361 31431 63800 62974 63978 64086 63027 63783 62537 31011 30722 30344 63662 63918 64229 64029 63531 30432 63281 31657 63373 30468 30351 31016 63559 63739 64362 62973 62624 63283 31220 64437 30013 63971 64234 63804 29875 30136 31663 62941 30465 30022 62637 29880 63212 31019 31673 29902 62991 63630 62586 63977 31177 30302 31173 62579 30375 63308 63170 31238 31631 29883 31663 31692 30440 30462 31407 63072 63445 31184 63284 63786 63750 29820 31174 31225 63820 31632 30901 64284 62978 30013 63127 31016 30149 31033 30490 63417 30394 63884 63248 63792 62645 30082 30391 63296 63600 63494 30031 30377 62800 62706 62908 31059 63754 64506 30616 63331 30172 31539 64399 62962 63361 31401 62538 30740 31064 30912 30210 64364 63505 31278 30110 64022 30560 63273 31109 64336 31191 64056 31676 64436 30419 30965 29705 62770 64174 30959 30635 64510 30090 30802 30124 29920 63443 31456 30559 30621 30077 30945 63510 30163 62772 29946 29975 30299 31429 31604 31359 62667 62846 62657 30709 63914 31149 30131 63742 30313 62917 30152 30628 31645 30828 63536 31672 64056 31743 29728 31210 30475 31346 64127 30541 30622 31049 31135 29769 63346 30273 31722 63991 30625 62849 64149 62971 63735 64259 31007 64505 63785 62934 30111 29963 63965 30377 29919 30737 62590 30548 64194 30385 30863 30352 64487 63762 31313 62528 63263 29947 64479 30626 30379 31706 30269 30225 31219 30208 63343 31601 64403 31394 30914 29961 63481 30908 31099 31144 63148 64180 62810 31086 64410 63672 63362 63996 63459 30052 63556 63797 31721 63222 31320 29812 31371 29968 30963 62520 62952 31645 29797 31352 30770 63452 31167 63705 29797 31440 31594 63486 63904 30245 31118 30378 30127 31362 30433 31106 30279 30701 62649 64215 31261 63199 62473 62956 64183 30330 30059 62950 63815 63237 31515 29740 31052 63676 63761 29713 31469 63987 31707 63578 62817 31117 62935 31054 63520 30584 63561 62857 62659 31436 29734 63512 62673 30845 30423 62950 63392 62742 31654 30888 63152 64269 30196 30138 31254 30501 30341 62834 30196 63725 30049 63838 64478 30531 30343 63757 64259 30352 62865 31481 64477 31432 30499 62827 29878 31199 63357 31069 30338 30884 30164 30528 63419 63194 64169 63496 62911 63120 30986 63901 29795 62758 31731 63830 63017 63535 64115 62957 64037 64451 30815 63751 63785 62574 64452 31144 63062 31434 29755 62993 31604 63112 63434 62748 63064 63313 64062 62877 63797 30512 63160 64367 30814 31729 29725 63931 62783 30495 29821 63775 29944 31296 29922 63650 30651 31575 31190 63304 62950 63438 30407 63587 62560 63524 63443 63502 62756 63421 64164 63128 64419 63935 62974 63996 63910 31561 63892 30822 30559 62801 31722 31684 63631 62972 30946 31026 62665 31709 62951 63025 30389 30282 64488 31692 30513 63023 30752 63180 30747 30492 64052 30236 30728 30955 31661 30349 30125 62506 31276 62739 30134 64275 63980 64266 64122 63062 31715 30253 63757 64046 30755 63960 31095 64003 31079 64022 63621 63744 62994 63746 30269 31348 63621 64043 30988 63394 64389 63423 63107 63455 29702 30381 63017 63318 31470 63168 63040 63483 31308 31667 29716 64099 63215 31189 29979 64446 31239 63495 63494 30381 31286 63806 30946 64075 64403 62823 31271 62653 31202 31659 31349 29700 64105 31093 64507 30613 30854 30094 64407 31261 63989 63623 63544 31320 30695 63720 63855 62739 31162 64464 30293 64131 63293 62954 31270 63759 63005 31553 31401 30052 30888 63925 30498 64439 29894 31344 31110 63179 30289 31741 63438 64164 63535 63394 31224 62743 31107 62581 30522 62789 30362 64296 30109 30607 30025 62857 63672 63888 30841 64179 63332 29984 62658 30995 30613 30926 63173 31666 30140 63067 62760 62517 30967 64332 64265 63251 30051 31584 62776 30688 29921 29987 63081 31403 63698 64102 64156 62929 63944 30174 63231 31278 63484 63612 30169 30143 62690 63578 62657 64203 30782 64160 30211 31273 64063 63958 63735 63579 30337 62468 64019 30334 30397 64168 62798 31656 30446 31691 62716 30793 31529 63795 62631 62736 64290 31376 63930 31333 62846 31581 31391 30862 62520 63488 62871 30979 30648 30072 63399 62848 30614 31592 63656 63040 31020 30280 63779 64187 62798 30233 31477 31651 63885 31479 62991 62573 62843 29913 62517 63162 62767 62823 29967 63216 30188 29903 30817 30714 29971 63677 31483 30103 31229 30583 62903 63117 30143 64508 62847 30429 31662 62549 62568 31445 63421 31350 31322 30191 63686 30163 30481 31235 31228 31309 31077 31154 30264 63665 31256 30563 30932 31255 62870 30603 63570 30195 63715 30482 64058 62974 29783 63713 30982 30645 29999 63076 63929 31280 31317 30727 63716 31674 30709 63869 62957 30715 29974 63429 64204 30467 62932 63334 63546 30220 29779 30489 31141 64019 30047 30225 31420 64051 31630 31668 31019 63430 63215 31196 63581 64433 31733 63486 63316 30129 29820 30236 64265 30126 30602 62584 64308 64271 29920 63914 30100 30941 31482 64262 31087 29793 30595 62948 31167 30447 31447 30729 31273 63948 30746 30890 31306 30598 30879 63162 30336 63098 63281 29835 31740 31650 63666 64390 63109 30538 62872 63568 63439 63568 62945 64347 62663 64214 64230 30587 31484 63776 30607 30025 63440 30247 31364 30736 30389 63100 31071 64466 63018 30260 30219 64195 31070 31564 63918 63379 30520 62898 64355 62865 62973 29952 30471 31012 64072 63949 30848 30232 63050 63242 62940 29874 29879 63212 62972 30538 31059 30432 31070 29733 62772 63162 63917 62526 30057 64477 31584 31473 63268 63130 63145 30424 30976 62926 29953 31435 31465 30521 30210 63604 30751 30194 31437 29971 63230 29716 63667 30732 64249 63233 30913 64293 63175 63773 30979 30948 64473 29844 62645 63816 63706 30868 63588 63414 64185 31664 30657 63541 64315 31159 31134 63413 31424 30832 64333 64071 64050 63859 31306 29815 29892 29748 30076 62488 30194 29913 31526 63699 63371 64410 64320 30739 30596 64187 63815 31709 64363 62546 31727 64009 30564 30691 29979 30524 30213 30332 62552 64464 63085 30860 30179 63775 30042 31102 63532 62848 63392 64092 30067 31427 29858 64270 31736 63496 64491 29868 64178 29946 31183 64155 62696 62826 63677 63039 31068 63131 31333 63702 31239 63429 64423 29771 63505 31065 62591 64323 30605 30012 64259 62819 63219 29746 63901 31040 30531 31506 30925 62999 31185 63719 30796 63793 31133 31691 64456 62857 30433 64039 31629 31581 30057 63385 63090 29920 30746 64493 30480 31584 62667 62970 31621 30423 62988 62579 30958 31607 31186 30153 64100 29725 63483 30151 64316 63703 64270 63281 63875 64340 63874 29724 30689 30079 29934 30925 63579 29934 64367 29697 62633 63492 30494 30454 30196 64337 62872 64211 63966 31457 30799 30314 63746 63524 64080 30158 62750 31416 29895 63183 63300 63339 30312 31689 30501 63826 64486 30948 31086 31231 30154 31461 64292 30948 63336 30812 63985 31442 30349 64090 62701 63196 64094 63446 31311 30904 63238 31087 30510 30922 63428 64388 63843 62908 64041 30096 63288 30144 63967 64508 63206 63294 30375 63435 63072 62488 29951 30233 63824 63846 31736 62529 31031 29878 63374 31543 31072 62573 31108 64096 30473 64342 63216 30887 29853 30070 62978 64108 30583 63144 30160 31741 63103 63609 62734 30756 63480 63753 63794 30163 63906 63276 29713 31393 64052 30873 63594 29821 64188 63031 64411 30869 64380 64472 63950 31078 29773 64504 64199 63645 62758 30801 62808 31554 30013 30952 30495 64457 64354 63802 63159 64025 64309 30472 63040 30805 64281 63109 31572 63024 31405 62750 31210 63773 30795 30267 29849 62475 31405 63962 62550 31552 64220 63774 63071 63681 63320 63683 30532 29868 62835 31395 31200 63221 63197 62631 29949 30331 63419 63152 62623 63662 31629 63553 30574 30099 30546 64208 62920 62919 63999 31355 64092 63087 63101 63569 30196 31661 64286 30534 31096 30430 63436 29797 31679 31695 31152 63805 31206 30356 30132 30427 63605 63266 62747 29727 30367 31702 30102 31692 62890 62608 64386 64317 30535 29790 30550 63137 62552 64417 29980 64005 29748 63845 62963 63047 30093 63075 30576 63604 63726 30283 64167 30999 64146 64210 30917 30564 29927 63970 63314 29909 64392 29938 63037 63808 30326 30686 63507 30019 29752 62888 64408 31573 30907 63680 63393 30044 30068 63098 63537 30484 31503 31385 30679 62597 63775 30417 31184 63462 63407 30477 31351 63089 31306 29719 62596 62614 31432 30651 63642 30148 31599 31601 31695 63857 63096 62794 62964 31351 64058 63127 63247 64087 31135 30237 63086 63977 31121 64057 30600 64428 31473 30053 31726 31087 62754 29996 64173 31704 30063 63805 64463 62929 30497 62769 62934 30234 30206 64077 30347 30092 31001 31236 31140 63374 62672 31350 30170 30367 62591 31593 62755 63329 63973 63410 30548 64114 64451 62528 64276 30345 63782 31568 62722 31129 63642 31461 30146 30998 63670 31085 62941 30824 64477 63180 30789 63793 63649 29861 30503 31110 30809 31243 31605 64445 63302 62568 30462 63388 63800 30681 29942 30372 29820 63293 63569 29831 63294 62952 64305 30577 62738 63298 63310 62476 64176 63109 63935 64103 30594 63525 29942 30374 63137 31629 30285 63750 30774 30448 30745 30783 30496 30794 30740 29876 62681 63755 63053 31666 31285 31206 30390 63463 64478 30562 64047 62521 63826 63010 63962 29765 30262 62922 62968 62650 30446 64300 31418 64073 31395 63488 63277 62974 62785 30345 30575 63861 63385 64107 62558 30394 30871 62643 30429 31247 31436 64383 29762 64423 64485 29993 63708 63053 64212 62993 30424 29847 31431 63443 64206 63167 64172 64036 30138 63941 63185 64146 31425 64028 29887 30491 63113 30133 29701 63088 64162 29759 62618 63452 64001 30127 63909 63273 30612 30000 64298 30396 31730 30879 62634 64471 31091 63039 63361 30443 31304 64027 64194 30717 29983 63121 64142 62608 64304 30967 63500 62555 64137 30553 63954 63166 63684 30192 30314 63591 62845 63259 62484 64103 63183 63038 31322 63468 31071 62660 29907 63057 63298 30917 63155 63159 64227 62665 63266 31551 62538 30202 64359 63811 30492 29882 30275 30438 63810 29773 30180 30301 62769 30324 30342 63885 62883 64012 29895 30589 63419 31646 64127 29928 63008 62593 63470 63220 64058 62871 62598 63703 62815 31429 29696 31484 62657 63188 30403 63452 64444 30189 30166 30711 63341 30251 31244 63747 63914 29780 30887 63692 30423 2139095039 2139095039 diff --git a/zk-pow/src/api/fp16/verify.rs b/zk-pow/src/api/fp16/verify.rs new file mode 100644 index 000000000..d2f127b2e --- /dev/null +++ b/zk-pow/src/api/fp16/verify.rs @@ -0,0 +1,713 @@ +//! Plaintext tile verification for the FP16 (A100) scheme. +//! +//! Mirrors the FP8 plaintext verifier ([`crate::api::verify::verify_plain_proof`]) +//! but over the FP16 datapath: given the opened FP16 operand strips and the +//! deterministic noise, it rebuilds the noised operands, replays the A100 tile +//! bit-for-bit, runs the unpredictable-accumulation-steps policy, folds the tile +//! into the jackpot ticket, and checks the difficulty target. +//! +//! The lottery extractor ([`xor_fold_extract`]), lane assignment, ticket hash, +//! and difficulty check are scheme-independent and reused from the FP8 modules; +//! only the operand open + noise + quantization + matmul + policy are FP16. +//! +//! Commitment wiring (Merkle openings, seed derivation, wire codec) is a +//! separate layer: this function takes the opened operands and noise factors +//! directly, which is exactly the boundary the FP8 `open_and_noisy_quantize` +//! sits above. + +use anyhow::{bail, Result}; + +use super::params::Fp16Params; +use super::plain_proof::Fp16PlainProof; +use super::policy::{check_shared_gates, replay_and_evaluate, PolicyReport}; +use super::quantization::{noisy_quantize, row_norms}; +use crate::api::fp8::transcript::{compute_jackpot_ticket, Ticket}; +use crate::api::fp8::utils::xor_fold_extract; +use crate::api::layout::{lane_assignment, AxisPattern}; +use crate::api::primitives::{Hash256, IncompleteBlockHeader}; +use crate::api::proof_utils::check_jackpot_difficulty; + +/// The rank-`r` noise for one operand side (the low-rank factors `E` and `F`, +/// FP16 bit patterns; `N = E @ F^T`). +pub struct OperandNoise16<'a> { + /// `num_rows x r`. + pub e: &'a [u16], + /// `k x r`. + pub f: &'a [u16], +} + +/// The result of a successful tile replay: the recomputed tile, the policy +/// report, and the jackpot ticket. +pub struct TileVerify { + pub tile: Vec, + pub report: PolicyReport, + pub ticket: Ticket, +} + +/// Rebuilds, replays, and scores an FP16 tile. Errors if the jackpot policy +/// rejects the tile; otherwise returns the ticket for the difficulty check. +/// +/// `a_rows` is `h x k` and `b_rows` is `w x k` FP16 bit patterns (the operands +/// as committed). `rows_pattern`/`cols_pattern` are the periodic partitions that +/// define the 16-lane extractor layout. `seed_a` keys the jackpot hash. +pub fn verify_tile( + params: &Fp16Params, + a_rows: &[u16], + b_rows: &[u16], + noise_a: &OperandNoise16, + noise_b: &OperandNoise16, + rows_pattern: &AxisPattern, + cols_pattern: &AxisPattern, + seed_a: &Hash256, +) -> Result { + params.validate()?; + let (h, w, k, r) = (params.h, params.w, params.k, params.r); + anyhow::ensure!(a_rows.len() == h * k && b_rows.len() == w * k, "operand shape mismatch"); + + // Rebuild the noised FP16 operands: A' = Q(alpha_a*A + beta_a*E_a@F_a), likewise B'. + let norms_a: Vec<_> = (0..h).map(|i| row_norms(&a_rows[i * k..i * k + k])).collect::>()?; + let norms_b: Vec<_> = (0..w).map(|j| row_norms(&b_rows[j * k..j * k + k])).collect::>()?; + let built_a = noisy_quantize(a_rows, noise_a.e, noise_a.f, &norms_a, r)?; + let built_b = noisy_quantize(b_rows, noise_b.e, noise_b.f, &norms_b, r)?; + + // Shared entry-liveness + noise-floor gates (bound degenerate operands) + // before the unpredictable-accumulation-steps density gate below. + check_shared_gates(a_rows, &built_a, b_rows, &built_b, k) + .map_err(|e| anyhow::anyhow!("the jackpot is not admissible: {e}"))?; + + // Replay the A100 tile and score it. + let (tile, report) = replay_and_evaluate(&built_a.noised_part, &built_b.noised_part, h, w, k); + if !report.accept { + bail!("the jackpot is not admissible (f_bp={:.4}, rho={:.4})", report.f_bp, report.rho); + } + + // Fold the tile into the ticket over the committed 16-subtile lane layout. + let lanes = lane_assignment(rows_pattern, cols_pattern); + let message = xor_fold_extract(&tile, &lanes); + let ticket = compute_jackpot_ticket(seed_a, &message); + Ok(TileVerify { tile, report, ticket }) +} + +/// Full plaintext acceptance: [`verify_tile`] plus the difficulty target check. +pub fn verify_tile_proof( + params: &Fp16Params, + a_rows: &[u16], + b_rows: &[u16], + noise_a: &OperandNoise16, + noise_b: &OperandNoise16, + rows_pattern: &AxisPattern, + cols_pattern: &AxisPattern, + seed_a: &Hash256, + nbits: u32, +) -> Result { + let v = verify_tile(params, a_rows, b_rows, noise_a, noise_b, rows_pattern, cols_pattern, seed_a)?; + check_jackpot_difficulty(&v.ticket.jackpot, nbits, params.h as u32, params.w as u32, params.k as u32)?; + Ok(v) +} + +/// Full certificate acceptance: the FP16 analogue of +/// [`crate::api::verify::verify_plain_proof`]. Parses and authenticates the wire +/// certificate ([`Fp16PlainProof::parse_proof`]: Merkle open+rebuild of both +/// operand trees + the B-then-A noise-seed chain + deterministic FP16 noise), +/// replays and scores the tile, folds the jackpot ticket, and checks difficulty. +/// +/// `nbits_override` replaces the proposed header's difficulty (e.g. a pool share). +/// `Ok(())` accepts; any failure (bad opening, inadmissible tile, or unmet +/// difficulty) is an `Err`. +pub fn verify_fp16_plain_proof( + proposed_header: &IncompleteBlockHeader, + proof: &Fp16PlainProof, + nbits_override: Option, +) -> Result<()> { + let opened = proof.parse_proof(proposed_header)?; + let noise_a = OperandNoise16 { e: &opened.noise.a.e, f: &opened.noise.a.f }; + let noise_b = OperandNoise16 { e: &opened.noise.b.e, f: &opened.noise.b.f }; + let nbits = nbits_override.unwrap_or(proposed_header.nbits); + verify_tile_proof( + &opened.params, + &opened.a_rows, + &opened.b_rows, + &noise_a, + &noise_b, + &opened.rows_pattern, + &opened.cols_pattern, + &opened.seed_a, + nbits, + )?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::layout::DimType::{Blake, Fold}; + + const H: usize = 4; + const W: usize = 64; + const K: usize = 256; + const R: usize = 32; + + fn params() -> Fp16Params { + Fp16Params { device: super::super::params::Fp16Device::A100, h: H, w: W, k: K, r: R } + } + + fn patterns() -> (AxisPattern, AxisPattern) { + // 4 row subtiles x 4 col subtiles = 16 lanes; cols fold 16 each. + (AxisPattern::new(&[(4, Blake)]).unwrap(), AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap()) + } + + /// Deterministic xorshift stream of FP16 values with spread magnitudes, + /// so the tile has dense breakpoints (the honest/realistic regime). + struct Gen(u64); + impl Gen { + fn next_u64(&mut self) -> u64 { + self.0 ^= self.0 << 13; + self.0 ^= self.0 >> 7; + self.0 ^= self.0 << 17; + self.0 + } + fn operand(&mut self, n: usize) -> Vec { + (0..n) + .map(|_| { + let r = self.next_u64(); + let sign = if r & 1 == 0 { 1.0 } else { -1.0 }; + let exp = ((r >> 1) % 9) as i32 - 3; // 2^-3 .. 2^5 + let mant = 1.0 + ((r >> 8) % 1024) as f32 / 1024.0; + f32_to_fp16(sign * mant * 2f32.powi(exp)).unwrap() + }) + .collect() + } + fn noise(&mut self, n: usize) -> Vec { + let scale = 256.0 / (R as f32).sqrt(); + (0..n).map(|_| f32_to_fp16(if self.next_u64() & 1 == 0 { scale } else { -scale }).unwrap()).collect() + } + } + + #[test] + fn accepts_honest_tile_and_ticket_is_deterministic() { + let mut g = Gen(0x1234_5678_9abc_def1); + let a = g.operand(H * K); + let b = g.operand(W * K); + let (ea, fa) = (g.noise(H * R), g.noise(K * R)); + let (eb, fb) = (g.noise(W * R), g.noise(K * R)); + let (rp, cp) = patterns(); + let seed = [7u8; 32]; + let na = OperandNoise16 { e: &ea, f: &fa }; + let nb = OperandNoise16 { e: &eb, f: &fb }; + + let v = verify_tile(¶ms(), &a, &b, &na, &nb, &rp, &cp, &seed).expect("honest tile accepts"); + assert!(v.report.accept && v.report.f_bp >= 0.30 && v.report.rho >= 1.2); + // Deterministic: re-running yields the identical ticket. + let v2 = verify_tile(¶ms(), &a, &b, &na, &nb, &rp, &cp, &seed).unwrap(); + assert_eq!(v.ticket.jackpot, v2.ticket.jackpot); + // Easy target accepts; an impossible (all-zero) target rejects. + check_jackpot_difficulty(&v.ticket.jackpot, 0x207fffff, H as u32, W as u32, K as u32).unwrap(); + assert!(check_jackpot_difficulty(&v.ticket.jackpot, 0, H as u32, W as u32, K as u32).is_err()); + } + + #[test] + fn rejects_flat_tile() { + // Flat +-1 operands with no noise: products barely truncate, so the + // policy's breakpoint density falls below the gate. + let one = f32_to_fp16(1.0).unwrap(); + let a = vec![one; H * K]; + let b = vec![one; W * K]; + let (ea, fa) = (vec![0u16; H * R], vec![0u16; K * R]); + let (eb, fb) = (vec![0u16; W * R], vec![0u16; K * R]); + let (rp, cp) = patterns(); + let na = OperandNoise16 { e: &ea, f: &fa }; + let nb = OperandNoise16 { e: &eb, f: &fb }; + let err = match verify_tile(¶ms(), &a, &b, &na, &nb, &rp, &cp, &[0u8; 32]) { + Ok(_) => panic!("flat tile must be rejected"), + Err(e) => e, + }; + assert!(format!("{err:#}").contains("not admissible"), "got: {err:#}"); + } + + /// Dumps the full `verify_tile` chain (per-stage + final) for several + /// params/shapes/seeds, as the bit-exactness oracle for the sm_80 + /// `pearl_gemm.fp16_pipeline` driver. Additive and `#[ignore]`d; run with: + /// ```text + /// PEARL_FP16_ORACLE_OUT=/path/oracle.json cargo test -p zk-pow --lib -- \ + /// api::fp16::verify::tests::dump_pipeline_oracle --ignored --exact --nocapture + /// ``` + #[test] + #[ignore = "dumps the FP16 verify_tile oracle vectors for the sm_80 pipeline; run explicitly"] + fn dump_pipeline_oracle() { + use crate::api::layout::AxisPattern; + use serde_json::{json, Value}; + + fn axis_json(p: &AxisPattern) -> Value { + Value::Array(p.dims().iter().map(|&(l, t)| json!([l, t as u8])).collect()) + } + + // Fully dumps one case: always computes the whole chain (even when the + // policy rejects), so every stage boundary can be checked downstream. + #[allow(clippy::too_many_arguments)] + fn case( + name: &str, + h: usize, + w: usize, + k: usize, + r: usize, + a: &[u16], + b: &[u16], + ea: &[u16], + fa: &[u16], + eb: &[u16], + fb: &[u16], + rp: &AxisPattern, + cp: &AxisPattern, + seed: &[u8; 32], + nbits: u32, + ) -> Value { + let norms_a: Vec<(u16, u16)> = + (0..h).map(|i| row_norms(&a[i * k..i * k + k]).unwrap()).collect(); + let norms_b: Vec<(u16, u16)> = + (0..w).map(|j| row_norms(&b[j * k..j * k + k]).unwrap()).collect(); + let built_a = noisy_quantize(a, ea, fa, &norms_a, r).unwrap(); + let built_b = noisy_quantize(b, eb, fb, &norms_b, r).unwrap(); + let (tile, report) = + replay_and_evaluate(&built_a.noised_part, &built_b.noised_part, h, w, k); + let lanes = lane_assignment(rp, cp); + let message = xor_fold_extract(&tile, &lanes); + let ticket = compute_jackpot_ticket(seed, &message); + let diff_ok = + check_jackpot_difficulty(&ticket.jackpot, nbits, h as u32, w as u32, k as u32).is_ok(); + json!({ + "name": name, "h": h, "w": w, "k": k, "r": r, + "a_rows": a, "b_rows": b, "ea": ea, "fa": fa, "eb": eb, "fb": fb, + "rows_pattern": axis_json(rp), "cols_pattern": axis_json(cp), + "seed_a": seed.to_vec(), "nbits": nbits, + "norms_a": norms_a.iter().map(|&(l, i)| json!([l, i])).collect::>(), + "norms_b": norms_b.iter().map(|&(l, i)| json!([l, i])).collect::>(), + "built_a": built_a.noised_part, "built_b": built_b.noised_part, + "alpha_a": built_a.alpha, "beta_a": built_a.beta, "l2_a": built_a.l2, + "tile_bits": tile.iter().map(|x| x.to_bits()).collect::>(), + "f_bp_bits": report.f_bp.to_bits(), "rho_bits": report.rho.to_bits(), + "f_bp": report.f_bp, "rho": report.rho, "accept": report.accept, + "message": message.to_vec(), "ticket": ticket.jackpot.to_vec(), + "difficulty_ok": diff_ok, + }) + } + + let mut cases: Vec = Vec::new(); + + // Honest spread-magnitude operands (accept), two seeds, h=4/w=64. + for (name, gseed, hseed) in [ + ("honest_a", 0x1234_5678_9abc_def1u64, [7u8; 32]), + ("honest_b", 0xfeed_face_cafe_b0bau64, [0x5au8; 32]), + ] { + let mut g = Gen(gseed); + let a = g.operand(H * K); + let b = g.operand(W * K); + let (ea, fa) = (g.noise(H * R), g.noise(K * R)); + let (eb, fb) = (g.noise(W * R), g.noise(K * R)); + let (rp, cp) = patterns(); + cases.push(case(name, H, W, K, R, &a, &b, &ea, &fa, &eb, &fb, &rp, &cp, &hseed, EASY)); + } + + // Flat operands, zero noise (reject); still dumps the full chain. + { + let one = f32_to_fp16(1.0).unwrap(); + let a = vec![one; H * K]; + let b = vec![one; W * K]; + let (ea, fa) = (vec![0u16; H * R], vec![0u16; K * R]); + let (eb, fb) = (vec![0u16; W * R], vec![0u16; K * R]); + let (rp, cp) = patterns(); + cases.push(case( + "flat_reject", H, W, K, R, &a, &b, &ea, &fa, &eb, &fb, &rp, &cp, &[0u8; 32], EASY, + )); + } + + // h = 16 (no A-side pad), 4x16 col subtiles: a different fold geometry. + { + let (h4, w4) = (16usize, 64usize); + let rp = AxisPattern::new(&[(4, Blake), (4, Fold)]).unwrap(); + let cp = AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap(); + assert_eq!(rp.tile_size() as usize, h4); + assert_eq!(cp.tile_size() as usize, w4); + let mut g = Gen(0x0bad_f00d_1337_d00d); + let a = g.operand(h4 * K); + let b = g.operand(w4 * K); + let (ea, fa) = (g.noise(h4 * R), g.noise(K * R)); + let (eb, fb) = (g.noise(w4 * R), g.noise(K * R)); + cases.push(case( + "h16", h4, w4, K, R, &a, &b, &ea, &fa, &eb, &fb, &rp, &cp, &[0x11u8; 32], EASY, + )); + } + + let out = std::env::var("PEARL_FP16_ORACLE_OUT") + .unwrap_or_else(|_| "/tmp/fp16_pipeline_oracle.json".to_string()); + std::fs::write(&out, serde_json::to_vec_pretty(&cases).unwrap()).unwrap(); + println!("wrote {} FP16 pipeline oracle cases to {}", cases.len(), out); + } + + const EASY: u32 = 0x207f_ffff; + + // ---- End-to-end certificate path (commit -> open -> wire -> verify) ---- + + mod cert { + use super::{Blake, Fold, Gen}; + use crate::api::fp16::commitment::{commit_operand, open_rows}; + use crate::api::fp16::noise::{key_a, key_b}; + use crate::api::fp16::params::Fp16Device; + use crate::api::fp16::plain_proof::{Fp16JobParams, Fp16MatrixProof, Fp16OperandParams, Fp16PlainProof}; + use crate::api::fp16::verify::verify_fp16_plain_proof; + use crate::api::fp8::public_params::HashId; + use crate::api::layout::AxisPattern; + use crate::api::primitives::{IncompleteBlockHeader, Sides}; + + // Total committed rows (> tile sizes, so some rows stay unopened and the + // openings carry real siblings). + const M: usize = 8; + const N: usize = 128; + const K: usize = 256; + const R: usize = 32; + const EASY_NBITS: u32 = 0x207f_ffff; + const HASH: HashId = HashId::Blake3Chunk1024; + + fn patterns() -> (AxisPattern, AxisPattern) { + ( + AxisPattern::new(&[(4, Blake)]).unwrap(), // h = 4 + AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap(), // w = 64 + ) + } + + /// Builds a wire certificate from full operands: commits the A tree under + /// keyA (proposed header) and the B tree under keyB (the ancestor header), + /// then opens the pattern tile rows. `ancestor` is the proof-carried `σ_Δ`. + fn build_proof_with_ancestor( + header: &IncompleteBlockHeader, + ancestor: &IncompleteBlockHeader, + a_full: &[u16], + b_full: &[u16], + ) -> Fp16PlainProof { + let (rp, cp) = patterns(); + let tree_a = commit_operand(a_full, M, K, HASH, key_a(header)).unwrap(); + let tree_b = commit_operand(b_full, N, K, HASH, key_b(ancestor)).unwrap(); + let a_idx: Vec = rp.tile_offsets().iter().map(|&o| o as usize).collect(); + let b_idx: Vec = cp.tile_offsets().iter().map(|&o| o as usize).collect(); + let pa = open_rows(&tree_a, &a_idx, M, K, HASH).unwrap(); + let pb = open_rows(&tree_b, &b_idx, N, K, HASH).unwrap(); + Fp16PlainProof { + job: Fp16JobParams { + ancestor_header: *ancestor, + device: Fp16Device::A100, + k: K as u32, + r: R as u32, + operands: Sides { + a: Fp16OperandParams { num_rows: M as u32, hash_id: HASH, pattern: rp }, + b: Fp16OperandParams { num_rows: N as u32, hash_id: HASH, pattern: cp }, + }, + }, + values: Sides { + a: Fp16MatrixProof { proof: pa, row_indices: a_idx }, + b: Fp16MatrixProof { proof: pb, row_indices: b_idx }, + }, + } + } + + /// Dense-fixture helper: the proposed header is also the ancestor (`σ_Δ = + /// σ̂`), the honest single-block case. Keeps the existing call sites intact. + fn build_proof(header: &IncompleteBlockHeader, a_full: &[u16], b_full: &[u16]) -> Fp16PlainProof { + build_proof_with_ancestor(header, header, a_full, b_full) + } + + /// An honest, policy-accepting fixture: spread-magnitude operands whose + /// noised tile clears the gate (same regime as `accepts_honest_tile`). + fn honest_fixture() -> (IncompleteBlockHeader, Fp16PlainProof) { + // Asymmetric prev_block/merkle_root (NOT palindromic under byte + // reversal) so the committed Go fixture actually exercises header + // byte-orientation across the FFI seam -- a reversal-invariant header + // would let a wrong-orientation conversion pass undetected. + let header = IncompleteBlockHeader { + prev_block: std::array::from_fn(|i| i as u8), + merkle_root: std::array::from_fn(|i| 0x40u8 + i as u8), + ..IncompleteBlockHeader::new_for_test(EASY_NBITS) + }; + let mut g = Gen(0xdead_beef_0bad_f00d); + let a_full = g.operand(M * K); + let b_full = g.operand(N * K); + (header, build_proof(&header, &a_full, &b_full)) + } + + #[test] + fn verifier_accepts_the_honest_fixture() { + let (header, proof) = honest_fixture(); + verify_fp16_plain_proof(&header, &proof, None) + .unwrap_or_else(|e| panic!("the honest FP16 certificate must verify: {e:#}")); + } + + /// Writes the committed Go/FFI test vector for the honest A100 certificate. + /// Format: `header(76) | u32le proof_len | proof_bytes` — the proposed header + /// (which keys the commitment + seed chain), then the serialized + /// [`Fp16PlainProof`]. The header's own `nbits` is the difficulty target, so + /// the verifier is called with `nbits_override = None` (FFI `0`). + /// + /// Run explicitly to regenerate: + /// ```text + /// cargo test -p zk-pow --lib -- \ + /// api::fp16::verify::tests::cert::regenerate_go_fixture --ignored --exact + /// ``` + #[test] + #[ignore = "regenerates the committed Go/FFI fixture; run explicitly"] + fn regenerate_go_fixture() { + let (header, proof) = honest_fixture(); + // Self-check: the vector we are about to commit must verify. + verify_fp16_plain_proof(&header, &proof, None).expect("fixture must verify before writing"); + + let proof_bytes = proof.to_bytes().expect("serialize Fp16PlainProof"); + let proof_len = u32::try_from(proof_bytes.len()).expect("proof length fits u32"); + let mut fixture = Vec::with_capacity(76 + 4 + proof_bytes.len()); + fixture.extend_from_slice(&header.to_bytes()); + fixture.extend_from_slice(&proof_len.to_le_bytes()); + fixture.extend_from_slice(&proof_bytes); + + let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../node/zkpow/testdata/fp16_plain_proof_a100.bin"); + std::fs::write(&path, &fixture).expect("write FP16 Go fixture"); + println!("FP16 A100 Go fixture ({} bytes) written to {}", fixture.len(), path.display()); + } + + /// Additive dump for the Python FP16 opener/assembler round-trip + /// (`miner_base.fp16_commitment` / `fp16_block_submission`). Writes the + /// exact operands + keys + roots behind the committed + /// `fp16_plain_proof_a100.bin` fixture, so the Python side can rebuild the + /// trees and assert its assembled `Fp16PlainProof.to_bytes()` equals the + /// fixture bytes (and that its tree roots equal `commit_operand`'s). + /// Binary layout: `header(76) | m,n,k (u32 le) | a_full (m*k u16 le) | + /// b_full (n*k u16 le) | keyA(32) | keyB(32) | root_A(32) | root_B(32)`. + /// ```text + /// PEARL_FP16_CERT_OPERANDS_OUT=/path/operands.bin cargo test -p zk-pow --lib -- \ + /// api::fp16::verify::tests::cert::dump_cert_operands --ignored --exact --nocapture + /// ``` + #[test] + #[ignore = "dumps the FP16 cert operands for the Python opener/assembler round-trip; run explicitly"] + fn dump_cert_operands() { + let header = IncompleteBlockHeader::new_for_test(EASY_NBITS); + let mut g = Gen(0xdead_beef_0bad_f00d); + let a_full = g.operand(M * K); + let b_full = g.operand(N * K); + let ka = key_a(&header); + let kb = key_b(&header); + let root_a = commit_operand(&a_full, M, K, HASH, ka).unwrap().root(); + let root_b = commit_operand(&b_full, N, K, HASH, kb).unwrap().root(); + + let mut out = Vec::new(); + out.extend_from_slice(&header.to_bytes()); + for v in [M as u32, N as u32, K as u32] { + out.extend_from_slice(&v.to_le_bytes()); + } + for &x in &a_full { + out.extend_from_slice(&x.to_le_bytes()); + } + for &x in &b_full { + out.extend_from_slice(&x.to_le_bytes()); + } + out.extend_from_slice(&ka); + out.extend_from_slice(&kb); + out.extend_from_slice(&root_a); + out.extend_from_slice(&root_b); + + let path = std::env::var("PEARL_FP16_CERT_OPERANDS_OUT") + .unwrap_or_else(|_| "/tmp/fp16_cert_operands.bin".to_string()); + std::fs::write(&path, &out).unwrap(); + println!("wrote {} bytes ({} + {} operand u16s) to {}", out.len(), M * K, N * K, path); + } + + #[test] + fn parses_a_non_origin_tile_with_global_indices() { + // A winner off the origin: row tile t_r=1 (global rows [4,8)) and col + // tile t_c=1 (global cols [64,128)). The opener discloses the GLOBAL + // rows (`base + tile_offsets()`); `parse_proof` must accept them and + // open exactly those rows (the E noise then keys on the right global + // indices -- the reconciliation that makes the full-matrix search and + // the cert agree for a non-origin winner). + let header = IncompleteBlockHeader::new_for_test(EASY_NBITS); + let mut g = Gen(0x0bad_c0de_0bad_cafe); + let a_full = g.operand(M * K); + let b_full = g.operand(N * K); + let (rp, cp) = patterns(); + let (h, w) = (rp.tile_size() as usize, cp.tile_size() as usize); + let (tr, tc) = (1usize, 1usize); + + let tree_a = commit_operand(&a_full, M, K, HASH, key_a(&header)).unwrap(); + let tree_b = commit_operand(&b_full, N, K, HASH, key_b(&header)).unwrap(); + let a_idx: Vec = rp.tile_offsets().iter().map(|&o| tr * h + o as usize).collect(); + let b_idx: Vec = cp.tile_offsets().iter().map(|&o| tc * w + o as usize).collect(); + let pa = open_rows(&tree_a, &a_idx, M, K, HASH).unwrap(); + let pb = open_rows(&tree_b, &b_idx, N, K, HASH).unwrap(); + + let proof = Fp16PlainProof { + job: Fp16JobParams { + ancestor_header: header, + device: Fp16Device::A100, + k: K as u32, + r: R as u32, + operands: Sides { + a: Fp16OperandParams { num_rows: M as u32, hash_id: HASH, pattern: rp.clone() }, + b: Fp16OperandParams { num_rows: N as u32, hash_id: HASH, pattern: cp.clone() }, + }, + }, + values: Sides { + a: Fp16MatrixProof { proof: pa, row_indices: a_idx.clone() }, + b: Fp16MatrixProof { proof: pb, row_indices: b_idx.clone() }, + }, + }; + + let opened = proof.parse_proof(&header).expect("a non-origin tile must parse"); + assert_eq!(opened.a_rows, a_full[tr * h * K..(tr * h + h) * K].to_vec()); + assert_eq!(opened.b_rows, b_full[tc * w * K..(tc * w + w) * K].to_vec()); + + // A base that is not a valid periodic tile offset (row base must be a + // multiple of h) is rejected, even though the indices are still a + // contiguous run of valid rows. + let bad_a: Vec = rp.tile_offsets().iter().map(|&o| 1 + o as usize).collect(); + let bad_pa = open_rows(&tree_a, &bad_a, M, K, HASH).unwrap(); + let mut bad = proof.clone(); + bad.values.a = Fp16MatrixProof { proof: bad_pa, row_indices: bad_a }; + assert!(bad.parse_proof(&header).is_err(), "a non-periodic tile base must be rejected"); + } + + #[test] + fn wire_roundtrips_and_rejects_trailing_bytes() { + let (header, proof) = honest_fixture(); + let bytes = proof.to_bytes().expect("serialize"); + let back = Fp16PlainProof::from_bytes(&bytes).expect("deserialize"); + assert_eq!(back.job, proof.job); + assert_eq!(back.values.a.row_indices, proof.values.a.row_indices); + assert_eq!(back.values.a.proof.root, proof.values.a.proof.root); + assert_eq!(back.values.b.proof.root, proof.values.b.proof.root); + // The round-tripped certificate still verifies (against the fixture's + // own header -- honest_fixture uses asymmetric prev_block/merkle_root). + verify_fp16_plain_proof(&header, &back, None).expect("round-tripped cert must verify"); + // No compat ladder: a trailing byte is rejected. + let mut trailing = bytes.clone(); + trailing.push(0); + assert!(Fp16PlainProof::from_bytes(&trailing).is_err()); + } + + #[test] + fn rejects_a_flipped_opened_row() { + let (header, mut proof) = honest_fixture(); + proof.values.a.proof.leaf_data[0][0] ^= 0xFF; + let err = verify_fp16_plain_proof(&header, &proof, None).expect_err("flipped leaf must be rejected"); + assert!(format!("{err:#}").contains("root"), "got: {err:#}"); + } + + #[test] + fn rejects_a_wrong_root() { + let (header, mut proof) = honest_fixture(); + proof.values.b.proof.root = [0u8; 32]; + assert!(verify_fp16_plain_proof(&header, &proof, None).is_err(), "wrong root must be rejected"); + } + + #[test] + fn rejects_a_wrong_header() { + // A different proposed header derives a different opening key, so the + // committed trees no longer reconstruct their roots. + let (_, proof) = honest_fixture(); + let wrong = IncompleteBlockHeader { timestamp: 0x1234_5678, ..IncompleteBlockHeader::new_for_test(EASY_NBITS) }; + let err = verify_fp16_plain_proof(&wrong, &proof, None).expect_err("wrong header must be rejected"); + assert!(format!("{err:#}").contains("root"), "got: {err:#}"); + } + + #[test] + fn rejects_a_tampered_ancestor_header_via_the_b_side_key() { + // The B-side tree is keyed by keyB = H_"key-B"(ancestor_header). The B + // operand was committed under the honest ancestor's keyB, so swapping + // the proof-carried ancestor (as an out-of-window / unauthenticated + // ancestor would) re-derives keyB and the committed B root no longer + // rebuilds: parse_proof REJECTS before any tile replay. + let (header, proof) = honest_fixture(); + proof.parse_proof(&header).expect("the honest ancestor must open the B tree"); + let mut tampered = proof.clone(); + tampered.job.ancestor_header.prev_block[0] ^= 1; + let err = match tampered.parse_proof(&header) { + Ok(_) => panic!("a B-key from an unauthenticated ancestor must be rejected"), + Err(e) => e, + }; + assert!(format!("{err:#}").contains("root"), "expected a B-side Merkle rebuild failure, got: {err:#}"); + } + + #[test] + fn rejects_an_out_of_window_ancestor_key() { + // A certificate whose B tree is committed under one ancestor's keyB but + // whose job advertises a different ancestor (e.g. one outside the state + // window) must fail the B-side Merkle rebuild. We build the B tree under + // `committed_ancestor` yet carry `claimed_ancestor` in the job. + let header = IncompleteBlockHeader::new_for_test(EASY_NBITS); + let committed_ancestor = IncompleteBlockHeader { prev_block: [0x33; 32], ..header }; + let claimed_ancestor = IncompleteBlockHeader { prev_block: [0x44; 32], ..header }; + let mut g = Gen(0x0bad_f00d_dead_beef); + let a_full = g.operand(M * K); + let b_full = g.operand(N * K); + let mut proof = build_proof_with_ancestor(&header, &committed_ancestor, &a_full, &b_full); + // Baseline: the matching ancestor verifies end-to-end. + { + let mut honest = proof.clone(); + honest.job.ancestor_header = committed_ancestor; + verify_fp16_plain_proof(&header, &honest, None).expect("matching ancestor must verify"); + } + // Swap in the mismatched (out-of-window) ancestor: keyB changes and the + // committed B root no longer rebuilds. + proof.job.ancestor_header = claimed_ancestor; + let err = verify_fp16_plain_proof(&header, &proof, None) + .expect_err("an out-of-window ancestor key must be rejected"); + assert!(format!("{err:#}").contains("root"), "expected a B-side Merkle rebuild failure, got: {err:#}"); + } + + #[test] + fn policy_gate_rejects_a_flat_opened_tile() { + // The policy gate that `verify_fp16_plain_proof` funnels into rejects + // a degenerate tile. We exercise it honestly over the commitment + // layer: commit + open flat +-1 operands, then replay with zero noise + // (the full cert path cannot present a flat tile to the policy, since + // the deterministic rank-r noise always injects admissible breakpoint + // structure; the flat regime only arises absent that noise). + use super::super::super::params::Fp16Params; + use super::super::{verify_tile, OperandNoise16}; + use crate::api::fp16::commitment::verify_and_open_rows; + use crate::api::fp16::dtype::f32_to_fp16; + + let header = IncompleteBlockHeader::new_for_test(EASY_NBITS); + let one = f32_to_fp16(1.0).unwrap(); + let proof = build_proof(&header, &vec![one; M * K], &vec![one; N * K]); + let (rp, cp) = patterns(); + let (h, w) = (rp.tile_size() as usize, cp.tile_size() as usize); + // A keys on the proposed header, B on the ancestor (= header here). + let a_rows = verify_and_open_rows( + &proof.values.a.proof, + &proof.values.a.row_indices, + M, + K, + HASH, + key_a(&header), + &proof.values.a.proof.root, + ) + .unwrap(); + let b_rows = verify_and_open_rows( + &proof.values.b.proof, + &proof.values.b.row_indices, + N, + K, + HASH, + key_b(&header), + &proof.values.b.proof.root, + ) + .unwrap(); + let (ea, fa) = (vec![0u16; h * R], vec![0u16; K * R]); + let (eb, fb) = (vec![0u16; w * R], vec![0u16; K * R]); + let na = OperandNoise16 { e: &ea, f: &fa }; + let nb = OperandNoise16 { e: &eb, f: &fb }; + let params = Fp16Params { device: Fp16Device::A100, h, w, k: K, r: R }; + let err = match verify_tile(¶ms, &a_rows, &b_rows, &na, &nb, &rp, &cp, &[0u8; 32]) { + Ok(_) => panic!("a flat opened tile must be rejected by the policy"), + Err(e) => e, + }; + assert!(format!("{err:#}").contains("not admissible"), "got: {err:#}"); + } + } +} diff --git a/zk-pow/src/api/fp16/zk.rs b/zk-pow/src/api/fp16/zk.rs new file mode 100644 index 000000000..9ca4c8859 --- /dev/null +++ b/zk-pow/src/api/fp16/zk.rs @@ -0,0 +1,329 @@ +//! FP16 (A100) ZK prover: turns a winning tile into the header-bound recursive +//! certificate the consensus path now carries. +//! +//! This is the prover-side analogue of [`crate::api::fp8::zk::Fp8Prover`], and the +//! exact inverse of the consensus verifier +//! ([`crate::circuit::fp16::wrapper::verify_wrapped_proof_with_headers`], wired at +//! the FFI by `verify_fp16_zk_cert_ffi`). Where the retired plaintext path opened +//! the operand strips and let the verifier replay the tile, the prover now: +//! +//! 1. derives the per-side opening keys from the headers exactly as the verifier +//! does — `keyA = key_a(proposed)`, `keyB = key_b(ancestor)` — and the noise +//! seeds from the committed operand roots + keys + the job's `p` encoding +//! ([`Fp16System::root_derived_seeds`]), so the lottery-compression jackpot key +//! is the header/root-derived `jackpot_key(seed_a)` the verifier pins; +//! 2. proves the FP16 batch ([`Fp16System::prove`]) under those header-derived +//! keys, deriving the Fiat-Shamir statement digest from the proven +//! `HASH_JACKPOT`; +//! 3. wraps it to the constant-size stage-2 recursive proof +//! ([`Fp16WrapperCircuits::prove`]) and packages it with the public job +//! statement into an [`Fp16ZkCertificate`]. +//! +//! An honestly-produced certificate therefore passes +//! `verify_wrapped_proof_with_headers` under the same headers, because every key / +//! seed / digest it commits is the header-derived value the verifier recomputes. +//! +//! # Setup cost / caching +//! +//! The FP16 wrapper is compiled **per tile shape** (the universal wrapper is the +//! documented residual, `docs/fp16_scheme/stark_feasibility.md §8`): compiling the +//! two wrapper stages for one `(h, w, k, hash_id)` geometry costs minutes. +//! [`set_noise_seed_params`] only affects the witness (the seed/public-input +//! values), never the circuit shape, so [`Fp16Prover`] caches one setup per +//! geometry and reuses it across blocks — each block then pays only the (still +//! minutes-long) proving, not recompilation. This mirrors [`Fp8Prover`] caching +//! per device; FP16 caches per geometry because its wrapper is not yet universal. +//! +//! [`Fp8Prover`]: crate::api::fp8::zk::Fp8Prover +//! [`set_noise_seed_params`]: crate::circuit::fp16::driver::Fp16System::set_noise_seed_params + +use std::collections::HashMap; + +use anyhow::{ensure, Result}; +use plonky2::util::timing::TimingTree; +use starky::batch_prover::BatchStarkPreprocessedData; + +use super::noise::commitment_keys; +use super::plain_proof::{Fp16JobParams, Fp16PlainProof}; +use super::zk_cert::Fp16ZkCertificate; +use crate::api::fp8::public_params::HashId; +use crate::api::fp8::transcript::jackpot_key; +use crate::api::primitives::{IncompleteBlockHeader, Sides}; +use crate::circuit::fp16::ctl::BLAKE3_A100_TABLE; +use crate::circuit::fp16::driver::Fp16System; +use crate::circuit::fp16::wrapper::{Fp16WrapperCircuits, D, F, InnerC}; + +/// One tile shape's compiled prover setup: the LUT precommitment and the +/// two-stage wrapper circuits. Shape-only — reused across blocks/jobs. The +/// `Fp16System` itself is NOT retained (it holds non-`Send` STARK trait objects, +/// and reconstructing it from the geometry is cheap — construction only, no +/// circuit work), so this setup stays `Send` and the prover is a plain pyclass. +struct Fp16ProverSetup { + preprocessed: BatchStarkPreprocessedData, + circuits: Fp16WrapperCircuits, +} + +/// A reusable FP16 prover. Retains one compiled setup per tile geometry +/// `(h, w, k, hash_id_A, hash_id_B)` and reuses it across proofs. +#[derive(Default)] +pub struct Fp16Prover { + setups: HashMap<(usize, usize, usize, u8, u8), Fp16ProverSetup>, +} + +impl Fp16Prover { + /// An empty prover; geometries are compiled lazily on first [`Self::prove`] + /// (or eagerly via [`Self::setup_geometry`]). + pub fn new() -> Self { + Self::default() + } + + /// Compiles and retains the wrapper circuits for one tile geometry now, so a + /// later [`Self::prove`] of that shape does not pay the compilation cost. + /// A no-op if the geometry is already cached. + pub fn setup_geometry(&mut self, h: usize, w: usize, k: usize, a_hash: HashId, b_hash: HashId) -> Result<()> { + let mut timing = TimingTree::default(); + self.ensure_setup(h, w, k, a_hash, b_hash, &mut timing) + } + + fn ensure_setup( + &mut self, + h: usize, + w: usize, + k: usize, + a_hash: HashId, + b_hash: HashId, + timing: &mut TimingTree, + ) -> Result<()> { + let key = (h, w, k, a_hash as u8, b_hash as u8); + if !self.setups.contains_key(&key) { + let system = Fp16System::::new(h, w, k, a_hash, b_hash); + let preprocessed = system.preprocessed_data::(timing); + let circuits = Fp16WrapperCircuits::build(&system, &preprocessed.cap(), timing)?; + self.setups.insert(key, Fp16ProverSetup { preprocessed, circuits }); + } + Ok(()) + } + + /// Proves one winning tile and returns the header-bound [`Fp16ZkCertificate`] + /// (the bytes the node's `CertificateV5.ProofData` carries). + /// + /// `a_codes` is the opened `h x k` A tile and `b_codes` the `w x k` B tile + /// (row-major FP16 bit patterns, the same codes the miner's search ran over); + /// `job` is the public statement (ancestor header, `k`/`r`, per-side + /// `num_rows`/`hash_id`/pattern) whose patterns fix `(h, w)`. `proposed_header` + /// keys the A side and the A branch of the seed chain. + pub fn prove( + &mut self, + proposed_header: &IncompleteBlockHeader, + job: &Fp16JobParams, + a_codes: &[u16], + b_codes: &[u16], + ) -> Result { + let mut timing = TimingTree::default(); + self.prove_with_timing(proposed_header, job, a_codes, b_codes, &mut timing) + } + + /// Proves directly from an [`Fp16PlainProof`] — the opener bundle the miner + /// already assembles for a winning tile. This authenticates and re-opens the + /// tile codes from the committed Merkle openings under `proposed_header` + /// (so a malformed opening is caught before the minutes-long prove), then + /// proves them under the bundle's job. The retired plaintext certificate is + /// thus repurposed as the prover's input, not a submitted artifact. + pub fn prove_from_plain_proof( + &mut self, + proposed_header: &IncompleteBlockHeader, + plain_proof: &Fp16PlainProof, + ) -> Result { + let opened = plain_proof.parse_proof(proposed_header)?; + self.prove(proposed_header, &plain_proof.job, &opened.a_rows, &opened.b_rows) + } + + fn prove_with_timing( + &mut self, + proposed_header: &IncompleteBlockHeader, + job: &Fp16JobParams, + a_codes: &[u16], + b_codes: &[u16], + timing: &mut TimingTree, + ) -> Result { + let h = job.operands.a.pattern.tile_size() as usize; + let w = job.operands.b.pattern.tile_size() as usize; + let k = job.k as usize; + let (a_hash, b_hash) = (job.operands.a.hash_id, job.operands.b.hash_id); + ensure!(a_codes.len() == h * k, "A operand must be h*k = {h}*{k} FP16 codes, got {}", a_codes.len()); + ensure!(b_codes.len() == w * k, "B operand must be w*k = {w}*{k} FP16 codes, got {}", b_codes.len()); + + // Header-derived per-side opening keys (bit-exact with the verifier). + let keys = commitment_keys(proposed_header, &job.ancestor_header); + + // Compile (or reuse) the geometry's wrapper circuits + LUT precommitment. + self.ensure_setup(h, w, k, a_hash, b_hash, timing)?; + let setup = self.setups.get(&(h, w, k, a_hash as u8, b_hash as u8)).expect("setup ensured above"); + + // Reconstruct the (cheap, non-`Send`) system for this geometry and fold + // THIS job's `p` into its witness seed chain. `p` affects only the + // seed/public-input witness, never the circuit shape, so the cached + // `preprocessed`/`circuits` (built from an identical system) stay valid. + let mut system = Fp16System::::new(h, w, k, a_hash, b_hash); + system.set_noise_seed_params(Sides { a: job.encode_p_a(), b: job.encode_p_b() }); + + // The lottery-compression key the verifier pins: jackpot_key(seed_a) over + // the header/root-derived seed_a. `root_derived_seeds` commits the operands + // under the header keys and runs the B-then-A chain, bit-exact with + // `api::fp16::noise::noise_seeds`. + let seeds = system.root_derived_seeds(a_codes, b_codes, keys.a, keys.b)?; + let jk = jackpot_key(&seeds.a); + + // Prove the batch under the header-derived keys, then wrap to stage 2. The + // statement digest is DERIVED from the proven HASH_JACKPOT (not caller + // salt), exactly what the verifier recomputes and pins. + let batch = system.prove::(a_codes, b_codes, keys.a, keys.b, jk, &setup.preprocessed, timing)?; + let digest = Fp16System::::statement_digest(&batch.public_inputs[BLAKE3_A100_TABLE]); + let wrapped = setup.circuits.prove(&system, &batch, digest, timing)?; + + Ok(Fp16ZkCertificate { job: job.clone(), proof_bytes: wrapped.to_bytes() }) + } +} + +#[cfg(test)] +mod fixture { + //! Generates + self-verifies the committed Go/Rust FP16 **ZK-cert** fixture + //! (`node/zkpow/testdata/fp16_zk_cert_a100.bin`): `header(76) | u32le cert_len | + //! Fp16ZkCertificate::to_bytes()`. The self-check is a full header-bound + //! prove -> verify-through-the-production-cache cycle (mirroring the FFI), plus a + //! tamper-rejects assertion. Heavy (recursive wrap ~min); run explicitly: + //! ```text + //! cargo test -p zk-pow --lib --no-default-features -- \ + //! api::fp16::zk::fixture::regenerate_zk_cert_fixture --ignored --exact --nocapture + //! ``` + use super::*; + use crate::api::fp16::commitment::{commit_operand, open_rows}; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::fp16::noise::{key_a, key_b}; + use crate::api::fp16::params::Fp16Device; + use crate::api::fp16::plain_proof::{Fp16MatrixProof, Fp16OperandParams, Fp16PlainProof}; + use crate::api::layout::AxisPattern; + use crate::api::layout::DimType::{Blake, Fold}; + use crate::api::primitives::Sides; + use crate::circuit::fp16::verifier_cache::Fp16VerifierCache; + use crate::circuit::fp16::wrapper::verify_wrapped_proof_with_headers; + use plonky2::plonk::proof::ProofWithPublicInputs; + + const M: usize = 8; + const N: usize = 128; + const K: usize = 256; + const R: u32 = 32; + const EASY: u32 = 0x207f_ffff; + const HASH: HashId = HashId::Blake3Chunk1024; + + /// The asymmetric `honest_fixture` header (matches `api::fp16::verify` tests): + /// version 0, prev_block [0..31], merkle_root [0x40..0x5f], ts 0x66666666. + fn asymmetric_test_header(nbits: u32) -> IncompleteBlockHeader { + IncompleteBlockHeader { + version: 0, + prev_block: std::array::from_fn(|i| i as u8), + merkle_root: std::array::from_fn(|i| 0x40u8 + i as u8), + timestamp: 0x6666_6666, + nbits, + } + } + + /// Spread-magnitude FP16 operands (the honest/admissible regime), byte-identical + /// to `api::fp16::verify`'s `Gen`. + fn spread_operands(na: usize, nb: usize, seed: u64) -> (Vec, Vec) { + let mut s = seed; + let mut next = || { + s ^= s << 13; + s ^= s >> 7; + s ^= s << 17; + s + }; + let mut op = |n: usize| -> Vec { + (0..n) + .map(|_| { + let r = next(); + let sign = if r & 1 == 0 { 1.0 } else { -1.0 }; + let exp = ((r >> 1) % 9) as i32 - 3; + let mant = 1.0 + ((r >> 8) % 1024) as f32 / 1024.0; + f32_to_fp16(sign * mant * 2f32.powi(exp)).unwrap() + }) + .collect() + }; + (op(na), op(nb)) + } + + fn build_plain_proof(header: &IncompleteBlockHeader, a_full: &[u16], b_full: &[u16]) -> Fp16PlainProof { + let rp = AxisPattern::new(&[(4, Blake)]).unwrap(); // h = 4 + let cp = AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap(); // w = 64 + let tree_a = commit_operand(a_full, M, K, HASH, key_a(header)).unwrap(); + let tree_b = commit_operand(b_full, N, K, HASH, key_b(header)).unwrap(); + let a_idx: Vec = rp.tile_offsets().iter().map(|&o| o as usize).collect(); + let b_idx: Vec = cp.tile_offsets().iter().map(|&o| o as usize).collect(); + let pa = open_rows(&tree_a, &a_idx, M, K, HASH).unwrap(); + let pb = open_rows(&tree_b, &b_idx, N, K, HASH).unwrap(); + Fp16PlainProof { + job: Fp16JobParams { + ancestor_header: *header, + device: Fp16Device::A100, + k: K as u32, + r: R, + operands: Sides { + a: Fp16OperandParams { num_rows: M as u32, hash_id: HASH, pattern: rp }, + b: Fp16OperandParams { num_rows: N as u32, hash_id: HASH, pattern: cp }, + }, + }, + values: Sides { + a: Fp16MatrixProof { proof: pa, row_indices: a_idx }, + b: Fp16MatrixProof { proof: pb, row_indices: b_idx }, + }, + } + } + + #[test] + #[ignore = "recursive FP16 wrap (~min) + writes the committed ZK-cert fixture; run explicitly"] + fn regenerate_zk_cert_fixture() { + let header = asymmetric_test_header(EASY); + let (a_full, b_full) = spread_operands(M * K, N * K, 0xdead_beef_0bad_f00d); + let plain = build_plain_proof(&header, &a_full, &b_full); + + // PROVE (header-bound ZK cert from the opener bundle). + let mut prover = Fp16Prover::new(); + let cert = prover.prove_from_plain_proof(&header, &plain).expect("prove the winning tile"); + + // VERIFY through the PRODUCTION cache, exactly as the FFI does. + let (h, w, k) = cert.tile_geometry(); + let (a_hash, b_hash) = (cert.job.operands.a.hash_id, cert.job.operands.b.hash_id); + let cache_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/api/fp16/fp16_cache.bin"); + let cache = Fp16VerifierCache::from_bytes(&std::fs::read(&cache_path).expect("read fp16_cache.bin")) + .expect("parse production cache"); + let mut system = Fp16System::::new(h, w, k, a_hash, b_hash); + let verifier = cache.get(system.degree_bits()).expect("production cache covers the fixture profile"); + let vd = verifier.circuit(); + let proof = ProofWithPublicInputs::from_bytes(cert.proof_bytes.clone(), &vd.common).expect("deserialize"); + // The verifier folds THIS job's `p` into the system internally. + verify_wrapped_proof_with_headers(&mut system, vd, &proof, &header, &cert.job, EASY) + .expect("header-bound prove -> verify-through-cache must accept the honest cert"); + + // TAMPER: a flipped proof byte must be rejected. + let mut bad = cert.proof_bytes.clone(); + *bad.last_mut().unwrap() ^= 1; + assert!( + ProofWithPublicInputs::from_bytes(bad, &vd.common) + .map_err(|e| e.to_string()) + .and_then(|p| verify_wrapped_proof_with_headers(&mut system, vd, &p, &header, &cert.job, EASY).map_err(|e| e.to_string())) + .is_err(), + "a tampered wrapped proof must be rejected" + ); + + // WRITE the fixture: header(76) | u32le cert_len | cert bytes. + let cert_bytes = cert.to_bytes().expect("serialize Fp16ZkCertificate"); + let mut out = Vec::with_capacity(76 + 4 + cert_bytes.len()); + out.extend_from_slice(&header.to_bytes()); + out.extend_from_slice(&(cert_bytes.len() as u32).to_le_bytes()); + out.extend_from_slice(&cert_bytes); + let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../node/zkpow/testdata/fp16_zk_cert_a100.bin"); + std::fs::write(&path, &out).expect("write ZK-cert fixture"); + println!("wrote FP16 ZK-cert fixture ({} bytes) to {}", out.len(), path.display()); + } +} diff --git a/zk-pow/src/api/fp16/zk_cert.rs b/zk-pow/src/api/fp16/zk_cert.rs new file mode 100644 index 000000000..9ad958ae1 --- /dev/null +++ b/zk-pow/src/api/fp16/zk_cert.rs @@ -0,0 +1,163 @@ +//! FP16 (A100) ZK consensus certificate: the wire container the node's +//! `CertificateV5` carries once the scheme's consensus path is the recursive ZK +//! proof rather than the plaintext replay. +//! +//! This is the ZK analogue of [`crate::api::fp16::plain_proof::Fp16PlainProof`]. +//! Where the plaintext certificate carried the opened operand strips (so cert +//! size scaled with the tile, up to several MiB), the ZK certificate carries a +//! **constant-size** recursive proof plus the public job statement: +//! +//! ```text +//! Fp16ZkCertificate = { job: Fp16JobParams, proof_bytes: Vec } +//! ``` +//! +//! * `job` — the public statement ([`Fp16JobParams`]: the proof-carried ancestor +//! header `σ_Δ`, device, `k`, `r`, and per-side `num_rows`/`hash_id`/pattern). +//! It fixes the tile geometry `(h, w, k)` (`h = P_A.tile_size()`, +//! `w = P_B.tile_size()`) and feeds the noise-seed public-parameter encodings +//! `p_A`/`p_B` ([`Fp16JobParams::encode_p_a`]/`encode_p_b`), so the verifier +//! can header-bind the proof exactly as the plaintext path did. +//! * `proof_bytes` — the serialized stage-2 wrapped plonky2 proof +//! (`ProofWithPublicInputs::to_bytes()`). It is opaque here: the +//! committed operand roots `HASH_A`/`HASH_B`, the jackpot hash `HASH_JACKPOT`, +//! and the statement digest all live inside the proof's public inputs, and are +//! recovered + header-bound by the verifier +//! ([`crate::circuit::fp16::wrapper::verify_wrapped_proof_with_headers`]). +//! Deserialization needs the wrapper's `CommonCircuitData`, which the verifier +//! reconstructs from `job`'s geometry, so this container keeps the proof as +//! bytes (the FP8 `proof_blob` discipline). +//! +//! The codec is canonical fixint bincode and rejects trailing bytes, matching +//! [`Fp16PlainProof`]. + +use anyhow::Result; +use serde::{Deserialize, Serialize}; + +use super::plain_proof::Fp16JobParams; + +/// The FP16 (A100) ZK consensus certificate (see module docs). +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(name = "Fp16ZkCertificate"))] +pub struct Fp16ZkCertificate { + /// The public job statement (fixes geometry + the noise-seed `p` encodings). + pub job: Fp16JobParams, + /// The serialized stage-2 wrapped recursive proof + /// (`ProofWithPublicInputs::to_bytes()`); opaque to this container. + pub proof_bytes: Vec, +} + +impl Fp16ZkCertificate { + /// Strict fixint bincode (matches [`Fp16PlainProof::to_bytes`]). + /// + /// [`Fp16PlainProof::to_bytes`]: super::plain_proof::Fp16PlainProof::to_bytes + pub fn to_bytes(&self) -> Result> { + use bincode::Options; + bincode::options() + .with_fixint_encoding() + .serialize(self) + .map_err(|e| anyhow::anyhow!("serialize Fp16ZkCertificate: {e}")) + } + + /// Inverse of [`Self::to_bytes`]. No compat ladder; rejects trailing bytes. + pub fn from_bytes(bytes: &[u8]) -> Result { + use bincode::Options; + bincode::options() + .with_fixint_encoding() + .reject_trailing_bytes() + .deserialize(bytes) + .map_err(|e| anyhow::anyhow!("deserialize Fp16ZkCertificate: {e}")) + } + + /// The tile geometry `(h, w, k)` the statement fixes — what the consensus + /// verifier rebuilds the `Fp16System`/wrapper circuit for. + pub fn tile_geometry(&self) -> (usize, usize, usize) { + ( + self.job.operands.a.pattern.tile_size() as usize, + self.job.operands.b.pattern.tile_size() as usize, + self.job.k as usize, + ) + } +} + +#[cfg(feature = "pyo3")] +#[pyo3::pymethods] +impl Fp16ZkCertificate { + #[new] + fn py_new(job: Fp16JobParams, proof_bytes: Vec) -> Self { + Self { job, proof_bytes } + } + + #[getter] + fn job(&self) -> Fp16JobParams { + self.job.clone() + } + + #[getter] + fn proof_bytes<'py>(&self, py: pyo3::Python<'py>) -> pyo3::Bound<'py, pyo3::types::PyBytes> { + pyo3::types::PyBytes::new(py, &self.proof_bytes) + } + + #[getter] + fn min_cert_version(&self) -> u32 { + crate::ffi::plain_proof::CertificateVersion::PlainFp16 as u32 + } + + #[pyo3(name = "to_bytes")] + fn py_to_bytes(&self) -> pyo3::PyResult> { + Self::to_bytes(self).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) + } + + #[staticmethod] + #[pyo3(name = "from_bytes")] + fn py_from_bytes(data: Vec) -> pyo3::PyResult { + Self::from_bytes(&data).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::fp16::params::Fp16Device; + use crate::api::fp16::plain_proof::{Fp16JobParams, Fp16OperandParams}; + use crate::api::fp8::public_params::HashId; + use crate::api::layout::AxisPattern; + use crate::api::layout::DimType::{Blake, Fold}; + use crate::api::primitives::{IncompleteBlockHeader, Sides}; + + fn sample() -> Fp16ZkCertificate { + let rp = AxisPattern::new(&[(4, Blake)]).unwrap(); // h = 4 + let cp = AxisPattern::new(&[(4, Blake), (16, Fold)]).unwrap(); // w = 64 + Fp16ZkCertificate { + job: Fp16JobParams { + ancestor_header: IncompleteBlockHeader::new_for_test(0x207f_ffff), + device: Fp16Device::A100, + k: 256, + r: 32, + operands: Sides { + a: Fp16OperandParams { num_rows: 8, hash_id: HashId::Blake3Chunk1024, pattern: rp }, + b: Fp16OperandParams { num_rows: 128, hash_id: HashId::Blake3Chunk1024, pattern: cp }, + }, + }, + proof_bytes: (0u16..5000).flat_map(|x| x.to_le_bytes()).collect(), + } + } + + #[test] + fn roundtrips_and_rejects_trailing_bytes() { + let cert = sample(); + let bytes = cert.to_bytes().expect("serialize"); + let back = Fp16ZkCertificate::from_bytes(&bytes).expect("deserialize"); + assert_eq!(back.job, cert.job); + assert_eq!(back.proof_bytes, cert.proof_bytes); + assert_eq!(back.tile_geometry(), (4, 64, 256)); + + let mut trailing = bytes.clone(); + trailing.push(0); + assert!(Fp16ZkCertificate::from_bytes(&trailing).is_err(), "a trailing byte must be rejected"); + } + + #[test] + fn tile_geometry_matches_patterns() { + assert_eq!(sample().tile_geometry(), (4, 64, 256)); + } +} diff --git a/zk-pow/src/api/mod.rs b/zk-pow/src/api/mod.rs index 2a302b1a4..a7b871502 100644 --- a/zk-pow/src/api/mod.rs +++ b/zk-pow/src/api/mod.rs @@ -1,4 +1,5 @@ pub mod fp8; +pub mod fp16; pub mod layout; pub mod primitives; pub mod proof_utils; diff --git a/zk-pow/src/bin/build_cache.rs b/zk-pow/src/bin/build_cache.rs index fbf16253a..929db2215 100644 --- a/zk-pow/src/bin/build_cache.rs +++ b/zk-pow/src/bin/build_cache.rs @@ -26,9 +26,12 @@ fn main() -> Result<()> { let mut args: Vec = std::env::args().skip(1).collect(); ensure!( - args.len() <= 3, - "usage: build_cache [ [ []]] \ - (`-` skips a cache; no arguments rebuilds all three at their canonical paths)" + args.len() <= 4, + "usage: build_cache [ [ [ []]]] \ + (`-` skips a cache; no arguments rebuilds the fp8/v2/v1 caches at their canonical paths. \ + The FP16 cache is NOT part of the no-argument default — it compiles one wrapper per \ + reachable degree profile and is heavy — so pass its path explicitly to build it, e.g. \ + `build_cache - - - src/api/fp16/fp16_cache.bin`)" ); if args.is_empty() { args = vec![ @@ -42,6 +45,7 @@ fn main() -> Result<()> { let fp8_path = skippable(args.next()); let v2_path = skippable(args.next()); let v1_path = skippable(args.next()); + let fp16_path = skippable(args.next()); if let Some(fp8_path) = fp8_path { let cache_bytes = build_fp8_cache()?; @@ -78,9 +82,128 @@ fn main() -> Result<()> { println!("wrote {v1_path} ({} bytes)", bytes.len()); } + if let Some(fp16_path) = fp16_path { + let bytes = build_fp16_cache()?; + std::fs::write(&fp16_path, &bytes).with_context(|| format!("writing {fp16_path}"))?; + println!("wrote {fp16_path} ({} bytes)", bytes.len()); + } + Ok(()) } +/// Builds the FP16 wrapper verifier cache: one compiled stage-2 verifier circuit per +/// *reachable degree profile*. The FP16 wrapper is per-degree-profile (the universal +/// variant is deferred), but every table height snaps to +/// [`zk_pow::circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS`], so the profile space +/// is small and fully enumerable — all consensus-legal geometries sharing a profile +/// share the one circuit, and the node verifier LOADS the setup for a proof's geometry +/// instead of rebuilding it (closing the verify-time rebuild / DoS). +/// +/// We sweep a representative grid of consensus-legal geometries (the +/// [`Fp16Params`](zk_pow::api::fp16::params::Fp16Params) envelope: `h >= 4`, `w >= 16`, +/// `h*w in [256, 2048]`, `k % 8 == 0`, `k*(h+w) <= 2^22`) across both operand hash ids, +/// dedup by the `Fp16System::degree_bits` profile, and compile one wrapper per distinct +/// profile. Each compile is expensive (minutes; the largest profiles are multi-GB), so +/// this is an offline one-time build. +fn build_fp16_cache() -> Result> { + use std::collections::BTreeSet; + use zk_pow::api::fp16::params::Fp16Params; + use zk_pow::api::fp8::public_params::HashId; + use zk_pow::circuit::fp16::driver::Fp16System; + use zk_pow::circuit::fp16::verifier_cache::{Fp16Verifier, Fp16VerifierCache, Fp16VerifierKey}; + use zk_pow::circuit::fp16::wrapper::{Fp16WrapperCircuits, InnerC, D, F}; + + // Representative geometry grid. The reachable degree profiles are a small set + // (every table snaps to the reachable ladder), so sweeping the envelope's corners + // and a few interior points over both hash ids finds them all; dedup collapses + // the rest. `k` spans small .. the per-shape maximum `k*(h+w) <= 2^22`. + // `FP16_CACHE_SAMPLE=1` restricts the sweep to the single smallest legal tile + + // one hash id (one profile) — a cheap way to generate a bootstrap blob so the + // `embedded_cache` crate compiles and the load path can be exercised, WITHOUT the + // full (heavy, multi-GB) envelope compile. Production omits it. + let sample = std::env::var("FP16_CACHE_SAMPLE").is_ok(); + let hs: &[usize] = &[4, 8, 16, 32, 45, 64]; + let ws: &[usize] = &[16, 32, 45, 64, 128, 256, 512]; + let k_samples: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 4096, 16384, 65536]; + let hash_ids: &[HashId] = &HashId::ALL; + + // A profile is wrapper-legal only if every table height lies on the consensus + // ladder; off-ladder geometries cannot be wrapped (so the prover can't produce a + // proof for them either), and are skipped. `FP16_CACHE_DRYRUN` prints the + // reachable on-ladder profiles without compiling (cheap space-mapping). + let on_ladder = + |profile: &[usize]| profile.iter().all(|b| zk_pow::circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS.contains(b)); + let dry_run = std::env::var("FP16_CACHE_DRYRUN").is_ok(); + + let mut cache = Fp16VerifierCache::default(); + let mut seen: BTreeSet> = BTreeSet::new(); + let mut considered = 0usize; + + for &h in hs { + for &w in ws { + for &k in k_samples { + // Consensus-legality gate (mirror Fp16Params::validate). + let params = Fp16Params { + device: zk_pow::api::fp16::params::Fp16Device::A100, + h, + w, + k, + r: zk_pow::circuit::fp16::driver::FP16_QUANT_R, + }; + if params.validate().is_err() { + continue; + } + for &a_hash in hash_ids { + for &b_hash in hash_ids { + considered += 1; + // Fp16System::new is cheap (AIR defs + closed-form snapped heights). + // validate() above gates the known realizability constraints; still + // skip (not abort) any residual geometry whose construction panics. + let built = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let system = Fp16System::::new(h, w, k, a_hash, b_hash); + let profile: Vec = system.degree_bits().to_vec(); + (system, profile) + })); + let (system, profile) = match built { + Ok(v) => v, + Err(_) => continue, + }; + // Skip off-ladder (non-wrapper-legal) geometries; dedup profiles. + if !on_ladder(&profile) || !seen.insert(profile.clone()) { + continue; + } + if dry_run { + println!("profile {profile:?} (h={h} w={w} k={k} a_hash={a_hash:?} b_hash={b_hash:?})"); + continue; + } + let mut timing = plonky2::util::timing::TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let circuits = + Fp16WrapperCircuits::build(&system, &preprocessed.cap(), &mut timing)?; + let key: Fp16VerifierKey = *system.degree_bits(); + cache.insert(key, Fp16Verifier::new(circuits.verifier_data())); + println!( + "compiled fp16 wrapper for profile {profile:?} (h={h} w={w} k={k} \ + a_hash={a_hash:?} b_hash={b_hash:?}); {} profiles so far", + cache.len() + ); + if sample { + // Bootstrap mode: one on-ladder profile is enough to prove the + // generator + load path; the full envelope is the offline run. + println!("fp16 cache: sample mode — built 1 profile, stopping"); + return cache.to_bytes(); + } + } + } + } + } + } + + ensure!(!cache.is_empty(), "FP16 verifier cache came out empty"); + println!("fp16 cache: {} distinct profiles from {considered} legal geometries", cache.len()); + cache.to_bytes() +} + /// Builds the sole FP8 setup artifact: one *universal* verifier per device. Each /// setup derives its cap fresh from the LUT tables before baking it into the wrapper /// circuit; the degree profile and geometry remain public inputs. diff --git a/zk-pow/src/circuit/fp16/blake3_commit.rs b/zk-pow/src/circuit/fp16/blake3_commit.rs new file mode 100644 index 000000000..ba6ef521e --- /dev/null +++ b/zk-pow/src/circuit/fp16/blake3_commit.rs @@ -0,0 +1,562 @@ +//! FP16 driver for the shared, scheme-neutral BLAKE3 STARK engine +//! ([`crate::circuit::fp8::blake3_stark`]). +//! +//! The FP8 bridge [`Blake3Program::from_blake_program`] hard-asserts the FP8 prequant four-plane +//! shape (A values / A scales / B values / B scales, each root produced exactly once) and panics +//! on anything else. The FP16 scheme instead commits **one keyed-BLAKE3 Merkle tree per operand +//! directly over the operand's `u16` LE row bytes** (no scales, no prequant fold — see +//! [`crate::api::fp16::commitment::commit_operand`]), and folds the 16 lottery words into +//! `HASH_JACKPOT` under `JACKPOT_KEY`. So `from_blake_program` cannot be used. +//! +//! This module assembles the [`Blake3Instruction`] schedule **directly** for the FP16 shape, +//! reusing the shared [`Blake3Stark`] AIR, [`Blake3Program::generate_trace`], and public-input +//! layout unchanged. Two things are proven, bit-exact against the plaintext: +//! +//! * **jackpot hash** ([`jackpot_program`]): one keyed compression of the 16 lottery words under +//! `JACKPOT_KEY`, output bound to `HASH_JACKPOT` — bit-exact with +//! [`crate::api::fp8::transcript::compute_jackpot_ticket`] (the FP16 scheme reuses the +//! scheme-neutral jackpot transcript). This is [`Blake3Instruction::lottery`], already supported +//! by the engine. +//! * **operand Merkle roots** ([`operand_tree_program`] / [`fp16_blake3_program`]): one keyed tree +//! per operand over the chunk-padded `u16` row bytes, root bound to `HASH_A` / `HASH_B` — +//! bit-exact with `commit_operand(..).root()` (which is `pearl_blake3::MerkleTree::with_chunk_len` +//! under the side key). The per-leaf chunk, chunk-chaining, odd-tail promotion and ROOT +//! finalization mirror [`pearl_blake3::MerkleTree`] for any `HashId` leaf size (128/256/512/1024). +//! +//! Scope: this delivers the Blake3 *constructor + generate_trace + public-binding* step (design +//! doc `docs/fp16_scheme/zk_binding_design.md` §5a item 2). It does **not** wire the batch driver +//! or the noisy_quant / XorFold counterparties; the CTL looking-sides are exposed here as +//! parameterized hooks ([`ctl_lottery_words_looking_blake3`], [`ctl_operand_bytes_looking_blake3`]) +//! for the batch-integration step, exactly as the sibling FP16 sub-STARKs expose theirs. + +use pearl_blake3::{B3F_CHUNK_END, B3F_CHUNK_START, B3F_KEYED_HASH, B3F_PARENT, B3F_ROOT, BLAKE3_MSG_LEN}; + +use crate::api::fp8::public_params::HashId; +use crate::circuit::fp8::blake3_stark::{ + Blake3Instruction, Blake3Program, CvRef, CvSource, MessageSource, PlaneId, PublicBinding, +}; + +/// 64-byte blocks per `chunk_len`-byte Merkle leaf (BLAKE3 blocks are 64 bytes). +fn blocks_per_leaf(chunk_len: usize) -> usize { + chunk_len / BLAKE3_MSG_LEN +} + +/// Appends one operand's keyed Merkle tree over `raw_len` chunk-padded `u16` row bytes, returning +/// the index of the root instruction (whose `bind` is `bind`). Mirrors +/// [`pearl_blake3::MerkleTree::with_chunk_len`] bit-for-bit: +/// +/// * each leaf is a BLAKE3 chunk of `chunk_len` bytes (`chunk_len / 64` blocks), chunk counter = +/// leaf index, `CHUNK_START` on block 0 and `CHUNK_END` on the last block, chained in-table +/// ([`CvSource::Chain`]) across the leaf's blocks; +/// * leaf CVs are paired bottom-up with keyed `PARENT` compressions, odd tails promoted unchanged; +/// * the single top merge carries `ROOT`; a one-leaf tree instead ROOT-finalizes that leaf's last +/// block (matching `MerkleTree`'s `data.len() <= chunk_len` branch, `hasher.hash(data)`). +/// +/// `plane` selects the committed byte stream and `key` its opening key (`KeyA`/`KeyB`); the trace +/// inputs must supply that plane's bytes padded under the same `HashId`. `ctl_base` is the byte +/// offset of the plane's first element in the operand stream (0 for a single-operand program). +fn append_operand_tree( + instrs: &mut Vec, + plane: PlaneId, + key: CvSource, + raw_len: usize, + chunk_len: usize, + ctl_base: u64, + bind: Option, +) -> usize { + assert!( + HashId::from_chunk_len(chunk_len).is_some(), + "chunk_len {chunk_len} is not an allowed BLAKE3 Merkle leaf size" + ); + assert!( + matches!(key, CvSource::KeyA | CvSource::KeyB), + "operand tree key must be KeyA/KeyB" + ); + let bpl = blocks_per_leaf(chunk_len); + // Chunk-padded leaf count (matches HashId::padded_len / MerkleTree leaf count). + let padded = raw_len.div_ceil(chunk_len).max(1) * chunk_len; + let leaves = padded / chunk_len; + + // ---- Leaf chunks. ---- + let mut cvs: Vec = Vec::with_capacity(leaves); + for leaf in 0..leaves { + for b in 0..bpl { + let mut flags = B3F_KEYED_HASH as u32; + if b == 0 { + flags |= B3F_CHUNK_START as u32; + } + let last_block = b + 1 == bpl; + // A single-leaf tree ROOT-finalizes the leaf itself (MerkleTree's `hash(data)` branch). + let is_tree_root = leaves == 1 && last_block; + if last_block { + flags |= B3F_CHUNK_END as u32; + if is_tree_root { + flags |= B3F_ROOT as u32; + } + } + let offset = leaf * chunk_len + b * BLAKE3_MSG_LEN; + instrs.push(Blake3Instruction { + cv: if b == 0 { + key + } else { + CvSource::Chain(instrs.len() - 1) + }, + msg: MessageSource::PlaneBytes { + plane, + offset, + ctl_base: ctl_base + offset as u64, + }, + counter: leaf as u64, + block_len: BLAKE3_MSG_LEN as u32, + flags, + bind: if is_tree_root { bind } else { None }, + }); + } + cvs.push(instrs.len() - 1); + } + + // ---- Parent layers (keyed), bottom-up, odd tail promoted; top merge is ROOT. ---- + while cvs.len() > 1 { + let is_root_layer = cvs.len() == 2; + let mut next = Vec::with_capacity(cvs.len().div_ceil(2)); + for pair in cvs.chunks(2) { + if let [left, right] = *pair { + let mut flags = (B3F_KEYED_HASH | B3F_PARENT) as u32; + if is_root_layer { + flags |= B3F_ROOT as u32; + } + instrs.push(Blake3Instruction { + cv: key, + msg: MessageSource::Parent { + left: CvRef::Instruction(left), + right: CvRef::Instruction(right), + }, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags, + bind: if is_root_layer { bind } else { None }, + }); + next.push(instrs.len() - 1); + } else { + next.push(pair[0]); // Odd tail: promoted unchanged. + } + } + cvs = next; + } + cvs[0] +} + +/// The jackpot-only program: one keyed compression of the 16 lottery words under `JACKPOT_KEY`, +/// output bound to `HASH_JACKPOT`. This is the smallest FP16 Blake3 statement and its XorFold +/// lottery-words counterparty ([`crate::circuit::fp16::xor_fold_stark`]) already exists. +pub fn jackpot_program() -> Blake3Program { + Blake3Program { + instructions: vec![Blake3Instruction::lottery()], + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: Vec::new(), + moe: None, + } +} + +/// A single operand's tree (root bound to `bind`), plus the mandatory lottery compression (the +/// engine's [`Blake3Program::validate`] requires exactly one). `side` picks the opening key and +/// committed plane. +pub fn operand_tree_program(raw_len: usize, chunk_len: usize, bind: PublicBinding) -> Blake3Program { + let (plane, key) = match bind { + PublicBinding::HashA => (PlaneId::AValues, CvSource::KeyA), + PublicBinding::HashB => (PlaneId::BValues, CvSource::KeyB), + other => panic!("operand_tree_program binds HashA/HashB, not {other:?}"), + }; + let mut instructions = Vec::new(); + append_operand_tree(&mut instructions, plane, key, raw_len, chunk_len, 0, Some(bind)); + instructions.push(Blake3Instruction::lottery()); + Blake3Program { + instructions, + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: Vec::new(), + moe: None, + } +} + +/// The full FP16 Blake3 program: operand-A tree (→ `HASH_A`, keyed `KEY_A`), operand-B tree +/// (→ `HASH_B`, keyed `KEY_B`), and the lottery compression (→ `HASH_JACKPOT`). `a_len`/`b_len` +/// are the raw (pre-chunk-padding) `u16` row-byte lengths (`num_rows * k * 2`); `a_chunk`/`b_chunk` +/// are the per-side [`HashId::chunk_len`]. The B plane's CTL keys are offset past A's byte range so +/// a future operand-bytes channel keeps the two sides disjoint. +pub fn fp16_blake3_program(a_len: usize, a_chunk: usize, b_len: usize, b_chunk: usize) -> Blake3Program { + let mut instructions = Vec::new(); + append_operand_tree( + &mut instructions, + PlaneId::AValues, + CvSource::KeyA, + a_len, + a_chunk, + 0, + Some(PublicBinding::HashA), + ); + append_operand_tree( + &mut instructions, + PlaneId::BValues, + CvSource::KeyB, + b_len, + b_chunk, + a_len as u64, + Some(PublicBinding::HashB), + ); + instructions.push(Blake3Instruction::lottery()); + Blake3Program { + instructions, + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: Vec::new(), + moe: None, + } +} + +/// 8 LE `u32` limbs of a 32-byte key / hash (the [`crate::circuit::fp8::blake3_stark::Blake3TraceInputs`] +/// key-word form, and the public-input word form). +pub fn bytes32_to_words(b: &[u8; 32]) -> [u32; 8] { + core::array::from_fn(|i| u32::from_le_bytes(b[4 * i..4 * i + 4].try_into().unwrap())) +} + +/// The inverse of [`bytes32_to_words`]: the 32 LE bytes of 8 `u32` public-input / key words. +pub fn words_to_bytes32(w: &[u32; 8]) -> [u8; 32] { + core::array::from_fn(|i| w[i / 4].to_le_bytes()[i % 4]) +} + +// ================================================================================================== +// Parameterized CTL looking-side hooks (for the batch-integration step; not wired here). +// ================================================================================================== + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use crate::circuit::fp8::blake3_stark::columns::BLAKE3_COL_MAP; + +/// Blake3's looking side of the **lottery words** channel: 16 `(word_pos, BLAKE3_MSG[pos])` tuples +/// on the lottery message-load row (row 0 holds the message), filter +/// `IS_BIND_JACKPOT_HASH * IS_NEW_BLAKE` (fires exactly once). The counterparty is +/// [`crate::circuit::fp16::xor_fold_stark::ctl::ctl_lottery_words_looked_xor_fold`] (filter +/// `IS_LANE_FINAL`): pairing both sides proves the 16 jackpot message words are exactly XorFold's +/// 16 lane outputs, and `HASH_JACKPOT` then binds their keyed BLAKE3 digest. Mirrors the FP8 +/// `ctl_lottery_words_looking_blake3`, but takes the Blake3 table's batch index explicitly (the +/// FP16 batch does not yet register the table — the index is supplied at integration time). +pub fn ctl_lottery_words_looking_blake3(blake3_table: usize) -> Vec> { + let m = &BLAKE3_COL_MAP; + (0..16) + .map(|j| { + TableWithColumns::new( + TableIdx::from(blake3_table), + vec![Column::constant(F::from_canonical_usize(j)), Column::single(m.blake3_msg[j])], + Filter::new( + vec![(Column::single(m.is_bind_jackpot_hash), Column::single(m.is_new_blake))], + vec![], + ), + ) + }) + .collect() +} + +/// Blake3's looking side of the **operand bytes** channel: 4 `(CTL_KEY_BASE + 2j, UINT8_DATA[2j] + +/// 2^8*UINT8_DATA[2j+1])` tuples per committed operand-values row — one `u16` operand element per +/// tuple (LE), keyed by its low byte's offset in the operand stream. Filter `IS_INT8_MESSAGE`, +/// which [`Blake3Program::generate_trace`] sets on exactly the live (non-chunk-padding) rows of an +/// `AValues`/`BValues` plane, so every committed `u16` crosses exactly once and padding/parent rows +/// do not. The B plane's `CTL_KEY_BASE` carries the `a_len` byte offset +/// ([`fp16_blake3_program`]), keeping the two operands' key spaces disjoint on one shared channel. +/// +/// The pair packing is sound because every message byte is BYTES2-checked by the engine's +/// `blake3_lut_lookups`. This is the Blake3↔noisy_quant counterparty of the design doc §4; the +/// `noisy_quant` looked side (keyed by the same byte offset, value = the raw `u16`) is the +/// integration-step follow-on. Takes the Blake3 table's batch index explicitly. +pub fn ctl_operand_bytes_looking_blake3(blake3_table: usize) -> Vec> { + let m = &BLAKE3_COL_MAP; + let byte_shift = F::from_canonical_u64(1 << 8); + (0..4) + .map(|j| { + TableWithColumns::new( + TableIdx::from(blake3_table), + vec![ + Column::linear_combination_with_constant([(m.ctl_key_base, F::ONE)], F::from_canonical_usize(2 * j)), + Column::linear_combination([(m.uint8_data[2 * j], F::ONE), (m.uint8_data[2 * j + 1], byte_shift)]), + ], + Filter::from_column(Column::single(m.is_int8_message)), + ) + }) + .collect() +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::PrimeField64; + use starky::constraint_consumer::ConstraintConsumer; + use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; + use starky::stark::Stark; + + use super::*; + use crate::api::fp16::commitment::commit_operand; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::fp8::transcript::compute_jackpot_ticket; + use crate::circuit::fp8::blake3_stark::columns::{ + NUM_BLAKE3_COLUMNS, NUM_BLAKE3_PUBLIC_INPUTS, PI_HASH_A, PI_HASH_B, PI_HASH_JACKPOT, + }; + use crate::circuit::fp8::blake3_stark::{Blake3Stark, Blake3TraceInputs}; + use pearl_blake3::blake3_digest; + + const D: usize = 2; + type F = GoldilocksField; + type S = Blake3Stark; + + /// Read an 8-word public-input hash as 32 LE bytes. + fn pi_bytes(pis: &[F; NUM_BLAKE3_PUBLIC_INPUTS], base: usize) -> [u8; 32] { + let w: [u32; 8] = core::array::from_fn(|i| pis[base + i].to_canonical_u64() as u32); + words_to_bytes32(&w) + } + + /// Full AIR check over every row pair, including the last→first wrap (the real vanishing + /// polynomial). Returns true if any constraint is violated. Mirrors the fp8 blake3 test harness. + fn constraints_violated(stark: &S, rows: &[[F; NUM_BLAKE3_COLUMNS]], pis: &[F; NUM_BLAKE3_PUBLIC_INPUTS]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], pis); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().into_iter().any(|acc| acc != F::ZERO) + }) + } + + /// Minimal Blake3TraceInputs for a program that uses only the AValues/BValues planes + lottery + /// (no scales, routing, offsets, aux). + fn inputs<'a>( + a_values: &'a [u8], + b_values: &'a [u8], + lottery_words: [u32; 16], + key_a: [u32; 8], + key_b: [u32; 8], + jackpot_key: [u32; 8], + a_hash_id: HashId, + b_hash_id: HashId, + ) -> Blake3TraceInputs<'a> { + Blake3TraceInputs { + a_values, + a_scales: &[], + b_values, + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: &[], + aux_cvs: &[], + lottery_words, + key_a, + key_b, + jackpot_key, + a_hash_id, + b_hash_id, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + } + } + + /// A finite FP16 row-major operand of spread magnitudes. + fn operand(num_rows: usize, k: usize, salt: u32) -> Vec { + (0..num_rows * k) + .map(|i| f32_to_fp16(((i as u32).wrapping_mul(salt) % 193) as f32 * 0.25 - 24.0).unwrap()) + .collect() + } + + // ---------------------------------------------------------------- jackpot + + #[test] + fn jackpot_hash_is_bit_exact_vs_plaintext() { + let seed_a = [0x5au8; 32]; + let jk = crate::api::fp8::transcript::jackpot_key(&seed_a); + let msg: [u8; 64] = core::array::from_fn(|i| (i as u8).wrapping_mul(37).wrapping_add(11)); + let lottery_words: [u32; 16] = core::array::from_fn(|i| u32::from_le_bytes(msg[4 * i..4 * i + 4].try_into().unwrap())); + + let program = jackpot_program(); + let data = inputs( + &[], + &[], + lottery_words, + [0; 8], + [0; 8], + bytes32_to_words(&jk), + HashId::Blake3Chunk1024, + HashId::Blake3Chunk1024, + ); + let (rows, pis) = program.generate_trace::(&data); + + // Bit-exact against the scheme-neutral jackpot transcript the plaintext verifier uses. + let expected = compute_jackpot_ticket(&seed_a, &msg).jackpot; + assert_eq!(pi_bytes(&pis, PI_HASH_JACKPOT), expected, "HASH_JACKPOT != compute_jackpot_ticket"); + // And against the raw keyed-BLAKE3 primitive, to catch a transcript-helper regression. + assert_eq!(pi_bytes(&pis, PI_HASH_JACKPOT), blake3_digest(&msg, Some(jk))); + + // The honest trace satisfies the full reused AIR. + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + #[test] + fn jackpot_hash_rejects_tampered_lottery_word() { + let seed_a = [0x11u8; 32]; + let jk = crate::api::fp8::transcript::jackpot_key(&seed_a); + let msg: [u8; 64] = core::array::from_fn(|i| i as u8); + let mut lottery_words: [u32; 16] = + core::array::from_fn(|i| u32::from_le_bytes(msg[4 * i..4 * i + 4].try_into().unwrap())); + // Flip one lottery word: the proven HASH_JACKPOT must diverge from the honest digest. + lottery_words[7] ^= 0xDEAD_BEEF; + + let program = jackpot_program(); + let data = inputs( + &[], + &[], + lottery_words, + [0; 8], + [0; 8], + bytes32_to_words(&jk), + HashId::Blake3Chunk1024, + HashId::Blake3Chunk1024, + ); + let (_, pis) = program.generate_trace::(&data); + assert_ne!( + pi_bytes(&pis, PI_HASH_JACKPOT), + compute_jackpot_ticket(&seed_a, &msg).jackpot, + "a tampered lottery word must change HASH_JACKPOT" + ); + } + + // ------------------------------------------------------------ operand trees + + /// For every allowed leaf size and a spread of operand shapes (single leaf, odd-promote, + /// multi-leaf cascade), HASH_A / HASH_B equal `commit_operand(..).root()` bit-for-bit. + #[test] + fn operand_roots_are_bit_exact_vs_commit_operand() { + let key_a_bytes = [3u8; 32]; + let key_b_bytes = [200u8; 32]; + // (num_rows, k): row bytes = 2*k; shapes chosen to exercise 1 leaf, odd promote, >2 leaves + // across the different chunk sizes. + let shapes = [(1usize, 16usize), (2, 64), (3, 96), (8, 256), (5, 300)]; + for hash_id in HashId::ALL { + let chunk = hash_id.chunk_len(); + for &(nr, k) in &shapes { + let a = operand(nr, k, 0x9E37); + let b = operand(nr, k, 0x85EB); + let a_bytes = crate::api::fp16::commitment::rows_to_bytes(&a); + let b_bytes = crate::api::fp16::commitment::rows_to_bytes(&b); + + let program = fp16_blake3_program(a_bytes.len(), chunk, b_bytes.len(), chunk); + let data = inputs( + &a_bytes, + &b_bytes, + [0; 16], + bytes32_to_words(&key_a_bytes), + bytes32_to_words(&key_b_bytes), + [0; 8], + hash_id, + hash_id, + ); + let (rows, pis) = program.generate_trace::(&data); + + let root_a = commit_operand(&a, nr, k, hash_id, key_a_bytes).unwrap().root(); + let root_b = commit_operand(&b, nr, k, hash_id, key_b_bytes).unwrap().root(); + assert_eq!( + pi_bytes(&pis, PI_HASH_A), + root_a, + "HASH_A mismatch: chunk={chunk} shape={nr}x{k}" + ); + assert_eq!( + pi_bytes(&pis, PI_HASH_B), + root_b, + "HASH_B mismatch: chunk={chunk} shape={nr}x{k}" + ); + + // The honest trace satisfies the full reused AIR (soundness of the schedule). + assert!( + !constraints_violated(&S::new(program), &rows, &pis), + "AIR violated: chunk={chunk} shape={nr}x{k}" + ); + } + } + } + + #[test] + fn operand_root_rejects_tampered_byte() { + let key_a_bytes = [7u8; 32]; + let (nr, k) = (4usize, 128usize); + let hash_id = HashId::Blake3Chunk256; + let chunk = hash_id.chunk_len(); + let a = operand(nr, k, 0x1234); + let mut a_bytes = crate::api::fp16::commitment::rows_to_bytes(&a); + + let honest_root = commit_operand(&a, nr, k, hash_id, key_a_bytes).unwrap().root(); + let program = operand_tree_program(a_bytes.len(), chunk, PublicBinding::HashA); + + // Flip one committed byte: the proven HASH_A must diverge from the honest root. + a_bytes[13] ^= 0xFF; + let data = inputs( + &a_bytes, + &[], + [0; 16], + bytes32_to_words(&key_a_bytes), + [0; 8], + [0; 8], + hash_id, + HashId::Blake3Chunk1024, + ); + let (_, pis) = program.generate_trace::(&data); + assert_ne!(pi_bytes(&pis, PI_HASH_A), honest_root, "a tampered operand byte must change HASH_A"); + } + + #[test] + fn full_program_binds_all_three_hashes() { + let key_a_bytes = [9u8; 32]; + let key_b_bytes = [19u8; 32]; + let seed_a = [0x77u8; 32]; + let jk = crate::api::fp8::transcript::jackpot_key(&seed_a); + let (nr, k) = (3usize, 80usize); + let hash_id = HashId::Blake3Chunk512; + let chunk = hash_id.chunk_len(); + let a = operand(nr, k, 0xABCD); + let b = operand(nr + 1, k, 0xBEEF); + let a_bytes = crate::api::fp16::commitment::rows_to_bytes(&a); + let b_bytes = crate::api::fp16::commitment::rows_to_bytes(&b); + let msg: [u8; 64] = core::array::from_fn(|i| (i as u8) ^ 0x3C); + let lottery_words: [u32; 16] = core::array::from_fn(|i| u32::from_le_bytes(msg[4 * i..4 * i + 4].try_into().unwrap())); + + let program = fp16_blake3_program(a_bytes.len(), chunk, b_bytes.len(), chunk); + let data = inputs( + &a_bytes, + &b_bytes, + lottery_words, + bytes32_to_words(&key_a_bytes), + bytes32_to_words(&key_b_bytes), + bytes32_to_words(&jk), + hash_id, + hash_id, + ); + let (rows, pis) = program.generate_trace::(&data); + + assert_eq!(pi_bytes(&pis, PI_HASH_A), commit_operand(&a, nr, k, hash_id, key_a_bytes).unwrap().root()); + assert_eq!(pi_bytes(&pis, PI_HASH_B), commit_operand(&b, nr + 1, k, hash_id, key_b_bytes).unwrap().root()); + assert_eq!(pi_bytes(&pis, PI_HASH_JACKPOT), compute_jackpot_ticket(&seed_a, &msg).jackpot); + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + // ------------------------------------------------------------ CTL hooks + + #[test] + fn ctl_hooks_are_well_formed() { + // Any placeholder table index is fine; the real index is supplied at batch integration. + assert_eq!(ctl_lottery_words_looking_blake3::(3).len(), 16); + assert_eq!(ctl_operand_bytes_looking_blake3::(3).len(), 4); + } +} diff --git a/zk-pow/src/circuit/fp16/blake3_fp16_stark/columns.rs b/zk-pow/src/circuit/fp16/blake3_fp16_stark/columns.rs new file mode 100644 index 000000000..97446a12e --- /dev/null +++ b/zk-pow/src/circuit/fp16/blake3_fp16_stark/columns.rs @@ -0,0 +1,389 @@ +//! Trace columns for eight-row BLAKE3 compressions. +//! +//! Each compression streams its 64-byte message at eight bytes per row, applies one of BLAKE3's +//! seven rounds on each of the first seven rows, and finalizes the eight-word chaining value +//! `cv_out` on the eighth. `blake3_msg_buffer` binds that byte stream to the sixteen-word +//! `blake3_msg`; `cv_in`, a source-row pointer, `trace_row_index`, and `cv_out_freq` route +//! chaining values between compressions. +//! +//! The first six columns are verifier-recomputed schedule values: packed row flags, the +//! cross-table key base, int8/scale message selectors, the CV-source pointer or initialization +//! tweak, and packed mixture-of-experts routing indices. Remaining columns unpack those flags, +//! hold message/state data, route CVs, and bind the public hashes. [`FP16_RAW_BLAKE3_COL_MAP`] exposes +//! the same `#[repr(C)]` order as flat column indices. + +use crate::circuit::fp8::columns_view::columns_view; + +/// One tracked BLAKE3 state (16 words `v[0..16]`), in the deployed chip's representation +/// (`chip/blake3/blake3_air.rs`): words 0..4 and 8..12 packed as u32 field elements, words 4..8 +/// and 12..16 as 32 little-endian bits each — the bit halves are exactly the words the +/// G-function XOR/rotate steps consume, so no extra decompositions are needed. +/// +/// 4 + 128 + 4 + 128 = 264 columns per state. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct Fp16RawBlake3StateCols { + /// State words `v[0..4]`, packed u32. + pub row1: [T; 4], + /// State words `v[4..8]`, 32 LE bits each. + pub row2: [[T; 32]; 4], + /// State words `v[8..12]`, packed u32. + pub row3: [T; 4], + /// State words `v[12..16]`, 32 LE bits each. + pub row4: [[T; 32]; 4], +} + +/// Columns per tracked state. +pub const BLAKE3_STATE_WIDTH: usize = size_of::>(); + +/// Number of tracked states per row (input + 3 intermediates; the 4th intermediate is the next +/// row's input state). +pub const NUM_TRACKED_STATES: usize = 4; + +/// Number of message bytes ingested per row. +pub const NUM_UINT8: usize = 8; + +/// Bit position of each committed unpack flag inside `ROW_FLAGS_PACKED` (constraint 2's weights): +/// flag `j` carries weight `2^j`. The order is the field order below: `IS_USE_KEY_A(0), +/// IS_USE_KEY_B(1), IS_USE_JACKPOT_KEY(2), IS_USE_IV(3), IS_BIND_HASH_A(4), +/// IS_BIND_HASH_B(5), IS_BIND_ROUTING_HASH(6), IS_BIND_JACKPOT_HASH(7), IS_CV_IN(8), +/// IS_NEW_BLAKE(9), IS_LAST_ROUND(10), the three IS_MSG_BITS at bits 11, 12, and 13, +/// IS_FIRST_OUTER(14), IS_SECOND_OUTER(15), IS_BIND_OFFSETS_HASH(16), IS_WORD_PIN_FIRST(17), +/// IS_WORD_PIN_SECOND(18), IS_CHAIN_INTRA(19), IS_CHAIN_INTER(20), IS_CHAIN_STRICT(21), +/// IS_BOUND_FIRST(22), IS_BOUND_SECOND(23), IS_CHAIN_DATA(24), and the FP16 fork's +/// IS_EGRESS_CV(25)`. +pub const NUM_UNPACK_FLAGS: usize = 26; + +/// View of one Fp16RawBlake3Stark trace row: control unpacking, routing-index limbs, row counter, +/// streamed bytes, message buffer/schedule, CV selection/routing, four 264-column tracked +/// states, verifier-known schedule columns, and public-root selectors. Constraint numbers +/// 1..7 refer to `super::stark`'s constraint groups. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct Fp16RawBlake3ColumnsView { + // ------------------------------------------------------------------------------------------ + // Class (a): verifier-recomputable from the compiled `Fp16RawBlake3Program` (schedule, geometry). + // Committed *with the trace* like every main column, but the verifier recomputes them + // (`Fp16RawBlake3Program::known_values`) and checks the trace openings against its own values — + // the batch system's "known columns" (`starky::batch_verifier::BatchKnownColumns`, + // assembled by `super::super::driver::Fp8System::derive_known_columns`). The leading + // `NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS` indices are exactly this block. + // ------------------------------------------------------------------------------------------ + /// Packed per-row program word: the 26 unpack flags below at weights `2^0..2^25` + /// (constraint 2 re-packs them to this). + pub row_flags_packed: T, + /// Flat element index (int8-plane rows) or block index (scales-plane rows) of the first item + /// ingested on this row; base of the element/scale CTL keys (B-plane bases carry the + /// `h*k` / `h*k/8` key offsets). 0 off message rows. + pub ctl_key_base: T, + /// 1 on live int8-values message rows of either side; filter of the int8-bytes CTL channel. + /// (One flag serves both sides: the channel's looked side holds the A and B column groups + /// of InputQuant as two slots of one [`starky::cross_table_lookup::CrossTableLookup`], and + /// the `CTL_KEY_BASE` keys carry the `h*k` B-plane offset, so the key spaces are disjoint.) + pub is_int8_message: T, + /// 1 on live bf16-scales message rows of either side; filter of the block-scales CTL + /// channel (B keys carry the `h*k/8` offset). + pub is_scale_message: T, + /// CV-routing source pointer / packed tweak, by row position within the compression: + /// on CV-fetch rows (`IS_CV_IN`) the `TRACE_ROW_INDEX` of the earlier row whose `CV_OUT` feeds + /// this row's `CV_IN`; on row 1 of each compression the packed tweak + /// `counter(48 bits) + 2^48*flags + 2^56*block_len` consumed by the row-0 init-state check; + /// 0 elsewhere. + pub cv_route_key_or_tweak: T, + /// Packed MoE outer indices, `OUTER_INDEX_FIRST + 2^26 * OUTER_INDEX_SECOND` with each + /// index < 2^26. Selective pinning (the deployed chip's semantics): the word carries a + /// nonzero index only in the *sampled* slots of routing rows + /// ([`Fp16RawBlake3Program::routing_pins`](super::stark::Fp16RawBlake3Program)); unsampled neighbor + /// slots and non-routing rows contribute zero, which the unconditional decomposition + /// (constraint 6) plus the unfiltered limb bounds force onto the limbs. + pub moe_outer_indices_packed: T, + /// MoE pinned value for the row's first ingested word (constraint 7). On offsets rows + /// it holds one of the public offsets or a padding zero, and `IS_WORD_PIN_FIRST` checks + /// equality; on the routing bound row it holds `m - 1`, and `IS_BOUND_FIRST` checks an + /// upper bound. 0 when neither flag is set. + pub word_pin_first: T, + /// As `word_pin_first` for the row's second ingested word. + pub word_pin_second: T, + + // ------------------------------------------------------------------------------------------ + // Main: committed unpack of ROW_FLAGS_PACKED (constraint 2). Individually usable in constraints + // and lookup/CTL filters. Bit order = field order (see `NUM_UNPACK_FLAGS`). + // ------------------------------------------------------------------------------------------ + /// CV-source selector: keyed compression under `KEY_A` (the A-side/routing plane and its + /// parents). Bit 0. + pub is_use_key_a: T, + /// CV-source selector: keyed compression under `KEY_B` (the B-side plane and its parents). + /// Bit 1. + pub is_use_key_b: T, + /// CV-source selector: `JACKPOT_KEY` (the lottery compression). Bit 2. + pub is_use_jackpot_key: T, + /// CV-source selector: the BLAKE3 IV constants — the *unkeyed* compressions (the + /// commit-fold wrappers folding the plane roots into `HASH_A`/`HASH_B`). Bit 3. + pub is_use_iv: T, + /// 1 on the A-side commit-fold wrapper's finalization row: binds `CV_OUT` to the `HASH_A` + /// public limbs. Bit 4. + pub is_bind_hash_a: T, + /// As `is_bind_hash_a` for the B side / `HASH_B`. Bit 5. + pub is_bind_hash_b: T, + /// 1 on the routing tree root's finalization row: binds `CV_OUT` to `HASH_ROUTING`. Bit 6. + pub is_bind_routing_hash: T, + /// 1 on **all 8 rows** of the lottery compression (not just the finalization row): the + /// lottery-words CTL filter is `IS_BIND_JACKPOT_HASH * IS_NEW_BLAKE` on the message-load row + /// (`super::ctl`), so the flag must span the compression; the `HASH_JACKPOT` binding is + /// gated by `IS_BIND_JACKPOT_HASH * IS_LAST_ROUND`. Bit 7. + pub is_bind_jackpot_hash: T, + /// 1 on CV-fetch rows: filter of the CV-routing lookup (this row's `CV_IN` is fetched at key + /// `CV_ROUTE_KEY_OR_TWEAK`), and the `CV_IN` selector of the row-0 CV mux (block 2+ of a + /// multi-block chunk fetches on its row 0). Bit 8. + pub is_cv_in: T, + /// 1 on row 0 of every compression (and on padding rows): anchors the init state and gates + /// the round/finalization handoff. Bit 9. + pub is_new_blake: T, + /// 1 on row 7 of every live compression: pins `BLAKE3_MSG_BUFFER = permute(BLAKE3_MSG)` + /// (the message the compression actually consumed). Bit 10. + pub is_last_round: T, + /// Message-source bits (bits 11..14), the **deployed chip's combinational encoding** + /// (`chip/blake3/logic.rs`): plane bytes = `100`, auxiliary/routing/lottery bytes = `011`, + /// CV window (`BLAKE3_MSG_BUFFER[8..16] = CV_IN`, parent child fetches) = `001`, + /// no load = `000`. The deployed jackpot mode `010` is outlawed by a constraint (the + /// lottery message arrives as auxiliary bytes + the XorFold CTL instead). + pub is_msg_bits: [T; 3], + /// 1 on rows whose first ingested u32 word is pinned to `OUTER_INDEX_FIRST`: routing rows + /// where that slot holds a *sampled* entry (selective pinning, exactly the deployed + /// chip). Unsampled neighbor slots keep the selector down and their words free. Bit 14. + pub is_first_outer: T, + /// As `is_first_outer` for the second ingested u32 word / `OUTER_INDEX_SECOND`. Bit 15. + pub is_second_outer: T, + /// 1 on the offsets tree root's finalization row: binds `CV_OUT` to `HASH_OFFSETS`. + /// Bit 16. + pub is_bind_offsets_hash: T, + /// 1 when the row's first ingested word is pinned to `WORD_PIN_FIRST` (offsets rows: + /// the public offsets and the zero padding after `O_{e-1}`). Bit 17. + pub is_word_pin_first: T, + /// As `is_word_pin_first` for the second ingested word / `WORD_PIN_SECOND`. Bit 18. + pub is_word_pin_second: T, + /// 1 when the row's two ingested words are consecutive entries of a checked range (the + /// offsets list `O`, or the winner slice `R[w]`): checks `word0 <= word1` (strict when + /// `IS_CHAIN_STRICT` is set) through `CHAIN_INTRA_LIMBS`. Bit 19. + pub is_chain_intra: T, + /// 1 when the row's first word continues the chain from the previous stream word, held + /// by `CHAIN_CARRY`: checks `CHAIN_CARRY <= word0` (strict when `IS_CHAIN_STRICT` is + /// set) through `CHAIN_INTER_LIMBS`. Bit 20. + pub is_chain_inter: T, + /// 1 on routing rows: the chain gates subtract it from their differences, making the + /// routing order strict (`<`) where the offsets order is non-strict (`<=`). Bit 21. + pub is_chain_strict: T, + /// 1 on the routing row whose first word is the slice's last entry: checks + /// `word0 <= WORD_PIN_FIRST = m - 1` through this row's `CHAIN_INTRA_LIMBS`, which are + /// idle here (the intra gate needs a second in-slice word). With the strict chain this + /// bounds the whole slice into `[0, m)`. Bit 22. + pub is_bound_first: T, + /// As `IS_BOUND_FIRST` when the slice's last entry is the row's second word: checks + /// `word1 <= WORD_PIN_SECOND = m - 1` through the next row's `CHAIN_INTER_LIMBS`, which + /// are idle there (the next pair starts past the slice). Bit 23. + pub is_bound_second: T, + /// 1 on every routing/offsets block row. `CHAIN_CARRY` updates to the row's second word + /// on these rows and copies from the previous row everywhere else, so the chain + /// survives the Merkle-parent compressions interleaved between blocks. Bit 24. + pub is_chain_data: T, + /// **FP16 fork addition.** 1 on a compression's finalization row when the program requested + /// output egress (`Fp16RawBlake3Instruction::egress`): pins `CV_EGRESS_LIMBS` to this row's + /// `CV_OUT` (the forked AIR's egress constraint, degree 2) and filters the egress CTL channel + /// ([`super::ctl::ctl_cv_egress_looking_blake3`]). 0 everywhere the program leaves egress off, + /// so all shared-engine behavior is byte-identical when this flag is 0. Bit 25. + pub is_egress_cv: T, + + // ------------------------------------------------------------------------------------------ + // Main: witness data. + // ------------------------------------------------------------------------------------------ + /// First/second MoE outer index as 13-bit limb pairs (`value = limb0 + 2^13*limb1`), + /// constrained against `MOE_OUTER_INDICES_PACKED` (constraint 6); each limb bounded + /// < 2^13 by the **unfiltered** pair `RC16(limb)` + `RC16(8*limb)` (`super::ctl` — the + /// first pins `limb < 2^16` so the second's `8*limb` cannot alias mod p) — the bounds + /// must hold on every row so the packed decomposition is unique and dark slots are + /// pinned to zero. + pub outer_index_first: [T; 2], + /// See `outer_index_first`. + pub outer_index_second: [T; 2], + /// 16-bit limb pair of a gated order-chain difference: `diff = limbs[0] + 2^16 * + /// limbs[1]`, both limbs RC16-bounded on every row (`super::ctl`), so the difference + /// lies in `[0, 2^32)` and a wrapped negative can never satisfy the gate. Holds + /// `word1 - word0 - IS_CHAIN_STRICT` under `IS_CHAIN_INTRA`, and `WORD_PIN_FIRST - + /// word0` under `IS_BOUND_FIRST` (that row's intra gate is idle). Free witness when + /// both gates are off. + pub chain_intra_limbs: [T; 2], + /// As `chain_intra_limbs` for the across-row chain: holds `word0 - CHAIN_CARRY - + /// IS_CHAIN_STRICT` under `IS_CHAIN_INTER`, and the previous row's `WORD_PIN_SECOND - + /// word1` on the row after `IS_BOUND_SECOND` (whose inter gate is idle). + pub chain_inter_limbs: [T; 2], + /// The last routing/offsets word seen before this row: updated to the row's second word + /// on `IS_CHAIN_DATA` rows, copied from the previous row elsewhere. The inter chain + /// compares a data row's first word against this carry, so the comparison reaches the + /// stream-previous word even when Merkle parents sit between two blocks. + pub chain_carry: T, + /// Row counter (constraint 8); key of the CV-routing lookup (`CV_OUT` published here). + pub trace_row_index: T, + /// The 8 message bytes ingested this row (int8 elements, bf16 scale halves, routing-word + /// bytes, or auxiliary Merkle/lottery bytes); each byte in [0, 255] via BYTES2 + /// (`super::ctl`); source of the InputQuant CTL channels and of the message-buffer tail + /// load. + pub uint8_data: [T; NUM_UINT8], + /// 16-word sliding buffer accumulating the message (shift-by-2 per row): at each + /// compression's row 7 it equals the 16 u32 message words. + pub blake3_msg_buffer: [T; 16], + /// The 16 u32 message words of the running compression, in this round's schedule order + /// (row 0 holds the message itself; each next row is the BLAKE3 permutation of the previous; + /// `permute^8 = id` closes the loop against the buffer at row 7). + pub blake3_msg: [T; 16], + /// The 8 chaining-value words routed from an earlier row's `CV_OUT` (fetched by the + /// CV-routing lookup at key `CV_ROUTE_KEY_OR_TWEAK`); 0 off fetch rows. + pub cv_in: [T; 8], + /// The CV entering the compression: one-hot mux of `KEY_A` / `KEY_B` / `JACKPOT_KEY` + /// / `CV_IN` (constraint 3, the deployed mux plus the per-side key sources). + pub blake3_cv: [T; 8], + /// The deployed round block: 4 tracked states of the G-function cascade (constraint 1); + /// `round[0]` is the row's input state (= the init state on `IS_NEW_BLAKE` rows). + pub round: [Fp16RawBlake3StateCols; NUM_TRACKED_STATES], + /// The 8 output CV words: on finalization rows the compression output + /// (`v[i] ^ v[8+i]`), on other rows the same XOR expression over that row's tracked states + /// (published into the routing lookup with multiplicity 0). + pub cv_out: [T; 8], + /// Witness multiplicity of this row's `CV_OUT` in the CV-routing lookup (how many later + /// rows fetch it); nonzero only on finalization rows of consumed compressions. + pub cv_out_freq: T, + /// **FP16 fork addition.** The 16 little-endian 16-bit limbs of `CV_OUT` exported on the + /// output-egress channel: `cv_egress_limbs[2w] + 2^16 * cv_egress_limbs[2w+1] = cv_out[w]` + /// (`w in 0..8`). Pinned to `CV_OUT` only under `IS_EGRESS_CV` (degree 2); each limb is + /// RC16-bounded `< 2^16` on **every** row ([`super::ctl::blake3_lut_lookups`]), so the + /// recomposition is unique on egress rows and the limbs are forced to the zero (in-domain) + /// witness everywhere else. Source of [`super::ctl::ctl_cv_egress_looking_blake3`]. + pub cv_egress_limbs: [T; 16], +} + +/// Total number of committed Fp16RawBlake3Stark columns. +pub const NUM_FP16_RAW_BLAKE3_COLUMNS: usize = size_of::>(); + +// Committed-column count: 1181 (the shared engine's 1164 + the FP16 fork's IS_EGRESS_CV flag + +// 16 CV_EGRESS_LIMBS witness columns). +const _: () = assert!(NUM_FP16_RAW_BLAKE3_COLUMNS == 1181); +const _: () = assert!(BLAKE3_STATE_WIDTH == 264); + +/// Public inputs of Fp16RawBlake3Stark, 8 u32 limbs each, in LE word order of the native 32-byte +/// digests. `HASH_A`/`HASH_B` are the per-side aggregate commitment digests: an in-AIR +/// wrapper per side folds the two plane tree roots (`api/proof_utils.rs:: +/// operand_digest_fp10`), so the roots themselves stay internal. +pub const PI_KEY_A: usize = 0; +/// KEY_B limbs (the B-side plane's tree key). +pub const PI_KEY_B: usize = 8; +/// JACKPOT_KEY limbs (the lottery compression's key). +pub const PI_JACKPOT_KEY: usize = 16; +/// HASH_A limbs (the A-side commitment digest, bound at the A combine wrapper). +pub const PI_HASH_A: usize = 24; +/// HASH_B limbs (the B-side commitment digest). +pub const PI_HASH_B: usize = 32; +/// HASH_ROUTING limbs (the routing tree root; all-zero when the job has no routing plane). +pub const PI_HASH_ROUTING: usize = 40; +/// HASH_JACKPOT limbs (the lottery compression output). +pub const PI_HASH_JACKPOT: usize = 48; +/// HASH_OFFSETS limbs (the MoE offsets tree root `HO`; all-zero for dense jobs). +pub const PI_HASH_OFFSETS: usize = 56; +/// Number of Fp16RawBlake3Stark public inputs. +pub const NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS: usize = 64; + +columns_view!(Fp16RawBlake3ColumnsView, NUM_FP16_RAW_BLAKE3_COLUMNS, FP16_RAW_BLAKE3_COL_MAP); + +/// Number of leading class (a) ("known") columns: `ROW_FLAGS_PACKED..=WORD_PIN_SECOND`, +/// recomputable from the program + public geometry alone (`Fp16RawBlake3Program::known_values`) and +/// re-checked by the batch verifier against the trace openings. +pub const NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS: usize = FP16_RAW_BLAKE3_COL_MAP.word_pin_second + 1; + +/// The 25 unpack-flag column indices in `ROW_FLAGS_PACKED` bit order (constraint 2's weights are +/// `2^position` in this array). +pub const fn unpack_flag_cols() -> [usize; NUM_UNPACK_FLAGS] { + let m = &FP16_RAW_BLAKE3_COL_MAP; + [ + m.is_use_key_a, + m.is_use_key_b, + m.is_use_jackpot_key, + m.is_use_iv, + m.is_bind_hash_a, + m.is_bind_hash_b, + m.is_bind_routing_hash, + m.is_bind_jackpot_hash, + m.is_cv_in, + m.is_new_blake, + m.is_last_round, + m.is_msg_bits[0], + m.is_msg_bits[1], + m.is_msg_bits[2], + m.is_first_outer, + m.is_second_outer, + m.is_bind_offsets_hash, + m.is_word_pin_first, + m.is_word_pin_second, + m.is_chain_intra, + m.is_chain_inter, + m.is_chain_strict, + m.is_bound_first, + m.is_bound_second, + m.is_chain_data, + m.is_egress_cv, + ] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_FP16_RAW_BLAKE3_COLUMNS] = FP16_RAW_BLAKE3_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + // Class (a) columns come first (their indices will feed `preprocessed_indices`). + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.row_flags_packed, 0); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.ctl_key_base, 1); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.is_int8_message, 2); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.is_scale_message, 3); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.cv_route_key_or_tweak, 4); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.moe_outer_indices_packed, 5); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.word_pin_first, 6); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.word_pin_second, 7); + // The unpack flags are consecutive after the class (a) block. + let flags = unpack_flag_cols(); + for (j, &c) in flags.iter().enumerate() { + assert_eq!(c, NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS + j, "unpack flag {j} not at its packing position"); + } + // The FP16 fork's egress limbs are the trailing 16 columns, so cv_out_freq sits just + // before them and cv_egress_limbs[15] is the last column. + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.cv_egress_limbs[15], NUM_FP16_RAW_BLAKE3_COLUMNS - 1); + assert_eq!(FP16_RAW_BLAKE3_COL_MAP.cv_out_freq, NUM_FP16_RAW_BLAKE3_COLUMNS - 17); + // The round block is 4 * 264 = 1056 contiguous columns. + assert_eq!( + FP16_RAW_BLAKE3_COL_MAP.round[0].row1[0] + 4 * BLAKE3_STATE_WIDTH, + FP16_RAW_BLAKE3_COL_MAP.cv_out[0] + ); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_FP16_RAW_BLAKE3_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: Fp16RawBlake3ColumnsView = arr.into(); + assert_eq!(view.row_flags_packed, 1); + assert_eq!(view.uint8_data[0], FP16_RAW_BLAKE3_COL_MAP.uint8_data[0] as u64 * 3 + 1); + assert_eq!(view.round[2].row2[1][7], FP16_RAW_BLAKE3_COL_MAP.round[2].row2[1][7] as u64 * 3 + 1); + assert_eq!(view.cv_out_freq, FP16_RAW_BLAKE3_COL_MAP.cv_out_freq as u64 * 3 + 1); + // FP16 fork addition: the trailing egress limbs round-trip too. + assert_eq!(view.cv_egress_limbs[15], (NUM_FP16_RAW_BLAKE3_COLUMNS as u64 - 1) * 3 + 1); + let back: [u64; NUM_FP16_RAW_BLAKE3_COLUMNS] = view.into(); + assert_eq!(back, arr); + + use core::borrow::Borrow; + let borrowed: &Fp16RawBlake3ColumnsView = arr.borrow(); + assert_eq!(borrowed.trace_row_index, arr[FP16_RAW_BLAKE3_COL_MAP.trace_row_index]); + } +} diff --git a/zk-pow/src/circuit/fp16/blake3_fp16_stark/ctl.rs b/zk-pow/src/circuit/fp16/blake3_fp16_stark/ctl.rs new file mode 100644 index 000000000..56bccbf6c --- /dev/null +++ b/zk-pow/src/circuit/fp16/blake3_fp16_stark/ctl.rs @@ -0,0 +1,218 @@ +//! CTL and LUT wiring for Fp16RawBlake3Stark. +//! +//! Int8 and scale message rows emit four keyed byte pairs from `ctl_key_base` and +//! `uint8_data`. The jackpot load row emits 16 `blake3_msg` words. Every row checks four byte +//! pairs, and the MoE index limbs receive unfiltered RC16 bounds. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +use super::columns::FP16_RAW_BLAKE3_COL_MAP; + +/// The shared shape of both message channels: 4 byte-pair instances per message row, +/// `(CTL_KEY_BASE + key_stride*j, UINT8_DATA[2j] + 2^8*UINT8_DATA[2j+1])` for `j in 0..4`, under a +/// message-kind filter column. `blake3_table` is this forked AIR's batch table index (the fork is +/// batch-unwired this increment, so the index is supplied by the caller rather than a `Table` +/// enum — the FP16 batch uses `usize` table indices, see [`crate::circuit::fp16::ctl`]). +fn msg_pair_tables(blake3_table: usize, filter_col: usize, key_stride: usize) -> Vec> { + let m = &FP16_RAW_BLAKE3_COL_MAP; + let byte_shift = F::from_canonical_u64(1 << 8); + (0..4) + .map(|j| { + TableWithColumns::new( + TableIdx::from(blake3_table), + vec![ + Column::linear_combination_with_constant([(m.ctl_key_base, F::ONE)], F::from_canonical_usize(key_stride * j)), + Column::linear_combination([(m.uint8_data[2 * j], F::ONE), (m.uint8_data[2 * j + 1], byte_shift)]), + ], + Filter::from_column(Column::single(filter_col)), + ) + }) + .collect() +} + +/// Blake3's looking side of the **strip int8 bytes** channel: 4 byte-pair +/// instances per values-message row, `(CTL_KEY_BASE + 2j, UINT8_DATA[2j] + 2^8*UINT8_DATA[2j+1])` +/// for `j in 0..4` — two consecutive int8 elements per tuple (raw bytes; InputQuant's INT8DEC +/// does the two's-complement decode). Filtered by `IS_INT8_MESSAGE`, set only on opened-strip +/// values rows of either side — auxiliary blocks and parents don't cross; every strip element +/// crosses exactly once. One channel serves both sides: the looked side holds InputQuant's A +/// and B column groups as two slots, and `CTL_KEY_BASE` carries the `h*k` B-plane key offset, so +/// the two sides' key spaces are disjoint. +/// +/// The pair packing is sound because each byte is individually BYTES2-checked +/// ([`blake3_lut_lookups`]). +/// +/// Looked side: `input_quant_stark::ctl::ctl_int8_bytes_looked_input_quant` (slots A, B). +pub fn ctl_int8_bytes_looking_blake3(blake3_table: usize) -> Vec> { + msg_pair_tables(blake3_table, FP16_RAW_BLAKE3_COL_MAP.is_int8_message, 2) +} + +/// Blake3's looking side of the **block scales** channel: 4 instances per +/// scales-message row, `(CTL_KEY_BASE + j, UINT8_DATA[2j] + 2^8*UINT8_DATA[2j+1])` for `j in 0..4` +/// — one LE bf16 block-scale code per tuple, keyed by block index. Filtered by +/// `IS_SCALE_MESSAGE` (opened-strip scales rows of either side; B keys carry the `h*k/8` offset +/// in `CTL_KEY_BASE`); every block scale crosses exactly once. +/// +/// Looked side: `input_quant_stark::ctl::ctl_block_scales_looked_input_quant` (slots A, B). +pub fn ctl_block_scales_looking_blake3(blake3_table: usize) -> Vec> { + msg_pair_tables(blake3_table, FP16_RAW_BLAKE3_COL_MAP.is_scale_message, 1) +} + +/// Blake3's looking side of the **lottery words** channel: 16 +/// instances `(word_pos, FOLD_OUT)` on the lottery message-load row — the 16 LE u32 words of +/// the 64-byte lottery block, read from `BLAKE3_MSG` (row 0 of a compression holds the message +/// itself). Filter `IS_BIND_JACKPOT_HASH * IS_NEW_BLAKE`, a degree-2 product of committed flags +/// (`IS_BIND_JACKPOT_HASH` spans all 8 lottery rows precisely so this product fires exactly once). +/// +/// Looked side: `xor_fold_stark::ctl::ctl_lottery_words_looked_xor_fold` (filter +/// `IS_LANE_FINAL`). The FP8 V2 batch assembler pairs both sides, proving that the 16 jackpot +/// message words are exactly XorFold's 16 lane outputs; the public `HASH_JACKPOT` then binds +/// their keyed BLAKE3 digest. +pub fn ctl_lottery_words_looking_blake3(blake3_table: usize) -> Vec> { + let m = &FP16_RAW_BLAKE3_COL_MAP; + (0..16) + .map(|j| { + TableWithColumns::new( + TableIdx::from(blake3_table), + vec![Column::constant(F::from_canonical_usize(j)), Column::single(m.blake3_msg[j])], + Filter::new( + vec![(Column::single(m.is_bind_jackpot_hash), Column::single(m.is_new_blake))], + vec![], + ), + ) + }) + .collect() +} + +/// **FP16 fork addition** — the output-egress channel's looking side: on a compression's +/// finalization row where the program set `IS_EGRESS_CV`, this exports the 8-word output CV as 16 +/// little-endian 16-bit limbs, each on key `CTL_KEY_BASE + j` (`j in 0..16`). `CV_EGRESS_LIMBS[j]` +/// is `cv_out[j/2]`'s low (even `j`) or high (odd `j`) halfword, pinned to `cv_out` by the fork's +/// egress constraint (degree 2) and bounded `< 2^16` by the **unfiltered** RC16 instances in +/// [`blake3_lut_lookups`], so the two limbs recompose `cv_out[w]` uniquely (`< 2^32`, no wrap). +/// +/// Keyed by the program-chosen `CTL_KEY_BASE` (reused onto the finalization row by +/// [`super::stark::Fp16RawBlake3Program::known_values`] when the instruction carries an egress +/// base), so several egressing compressions occupy disjoint key ranges. The looked side is the +/// FP16 noise table (next increment); this increment delivers the engine + channel + unit tests. +/// +/// `blake3_table` is the forked AIR's batch table index (batch-unwired this increment). +pub fn ctl_cv_egress_looking_blake3(blake3_table: usize) -> Vec> { + let m = &FP16_RAW_BLAKE3_COL_MAP; + (0..16) + .map(|j| { + TableWithColumns::new( + TableIdx::from(blake3_table), + vec![ + Column::linear_combination_with_constant([(m.ctl_key_base, F::ONE)], F::from_canonical_usize(j)), + Column::single(m.cv_egress_limbs[j]), + ], + Filter::from_column(Column::single(m.is_egress_cv)), + ) + }) + .collect() +} + +/// Fp16RawBlake3Stark's per-row LUT instance inventory: BYTES2 x4 (every message +/// byte pair), RC16 x8 (the four 13-bit outer-index limb bounds, each as an unshifted + +/// shifted pair, **unfiltered** — every row), RC16 x4 (the MoE order-chain limbs, unfiltered). +/// The CV-routing lookup is *not* a LUT instance — it is in-trace with both sides in this +/// table and lives in `Fp16RawBlake3Stark::lookups` (already wired and proven). +/// +/// The limb bounds must be unfiltered, exactly the deployed chip's unfiltered `URANGE13` +/// lookups: constraint 6 decodes the known packed word through the limbs *unconditionally*, +/// and an unpinned slot (selector down — an unsampled neighbor, or any non-routing row) is +/// sound only because its limbs are still range-checked and therefore forced to zero by the +/// unique decomposition. Filtering by the selectors would let a malicious prover put +/// arbitrary field elements in the dark slots' limbs and satisfy the packed equality with a +/// wrap, breaking the pinned slot's binding. Off-routing rows all four limbs are zero, which +/// is in-domain, so the unfiltered instances cost nothing. +/// +/// Each 13-bit bound needs **both** RC16s. `RC16(8 * LIMB)` alone does not bound `LIMB` in +/// Goldilocks: `p = 1 (mod 8)`, so every `v < 2^16` has aliases `LIMB = (v + k*p) / 8` +/// (`k in 1..8`, huge canonical values) whose scaled key still lands in `[0, 2^16)` — with +/// only the scaled check, `2^16 * LIMB_1` can contribute e.g. `2^23 * t (mod p)` to the +/// packed word and shift a *pinned* slot's decoded index by `-2^23 * t` while an unpinned +/// neighbor slot absorbs the difference. `RC16(LIMB)` first pins `LIMB < 2^16` (so `8 * LIMB` +/// cannot wrap), and `RC16(8 * LIMB)` then gives the true 13-bit bound. +pub fn blake3_lut_lookups() -> Vec> { + let m = &FP16_RAW_BLAKE3_COL_MAP; + let eight = F::from_canonical_u64(8); + + let mut lookups = Vec::new(); + // ---- BYTES2(UINT8_DATA[2j], UINT8_DATA[2j+1]) x4, every row (padding rows carry + // ---- zero bytes, which are in-domain). These byte ranges are also what make the byte-pair + // ---- CTL packings and the buffer-word packings (constraint 5) sound. + for j in 0..4 { + lookups.push(LutLookup { + table: LutTable::Bytes2, + keys: vec![Column::single(m.uint8_data[2 * j]), Column::single(m.uint8_data[2 * j + 1])], + values: vec![], + filter: Filter::default(), + }); + } + // ---- RC16(limb) + RC16(8 * limb) x4, unfiltered — the alias-free 13-bit bounds that make + // ---- the packed outer-index decomposition (constraint 6) unique on every row (module + // ---- docs above: neither check bounds the limb alone). + for limb in [ + m.outer_index_first[0], + m.outer_index_first[1], + m.outer_index_second[0], + m.outer_index_second[1], + ] { + lookups.push(LutLookup::rc16(Column::single(limb))); + lookups.push(LutLookup::rc16(Column::linear_combination([(limb, eight)]))); + } + // ---- RC16 x4, unfiltered — the MoE order-chain limbs (constraint 7). The bounds force + // ---- each gated difference into [0, 2^32), so a wrapped negative (~2^64) can never + // ---- satisfy the chain equality. Rows with every gate off hold zeros, which are + // ---- in-domain. + for limbs in [m.chain_intra_limbs, m.chain_inter_limbs] { + lookups.push(LutLookup::rc16(Column::single(limbs[0]))); + lookups.push(LutLookup::rc16(Column::single(limbs[1]))); + } + // ---- FP16 fork addition: RC16 x16, unfiltered — the output-egress CV limbs. Each is a 16-bit + // ---- halfword of `cv_out`, so a single RC16 is the exact bound (no 13-bit aliasing concern). + // ---- Unfiltered: off-egress rows the limbs are zero (in-domain), so this costs nothing there + // ---- while making the limbs' recomposition of `cv_out[w]` (< 2^32) unique on egress rows. + for limb in m.cv_egress_limbs { + lookups.push(LutLookup::rc16(Column::single(limb))); + } + lookups +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + + type F = GoldilocksField; + + #[test] + fn blake3_ctl_halves_are_well_formed() { + // Any placeholder table index is fine; the real index is supplied at batch integration. + assert_eq!(ctl_int8_bytes_looking_blake3::(3).len(), 4); + assert_eq!(ctl_block_scales_looking_blake3::(3).len(), 4); + assert_eq!(ctl_lottery_words_looking_blake3::(3).len(), 16); + // FP16 fork addition: 16 egress limb instances. + assert_eq!(ctl_cv_egress_looking_blake3::(3).len(), 16); + } + + #[test] + fn blake3_lut_inventory_matches_documented_counts() { + let lookups = blake3_lut_lookups::(); + let count = |t: LutTable| lookups.iter().filter(|l| l.table == t).count(); + // Documented inventory: BYTES2 x4 (byte pairs), RC16 x8 (outer-index limb bounds, + // an unshifted + scaled pair per limb — see `blake3_lut_lookups` on aliasing), + // RC16 x4 (order-chain limbs), plus the FP16 fork's RC16 x16 (egress CV limbs). + assert_eq!(count(LutTable::Bytes2), 4); + assert_eq!(count(LutTable::Range16), 12 + 16); + assert_eq!(lookups.len(), 32); + } +} diff --git a/zk-pow/src/circuit/fp16/blake3_fp16_stark/mod.rs b/zk-pow/src/circuit/fp16/blake3_fp16_stark/mod.rs new file mode 100644 index 000000000..f72def627 --- /dev/null +++ b/zk-pow/src/circuit/fp16/blake3_fp16_stark/mod.rs @@ -0,0 +1,26 @@ +//! FP16-owned fork of the eight-row BLAKE3 compression AIR. +//! +//! This is a verbatim fork of [`crate::circuit::fp8::blake3_stark`] (the shared, scheme-neutral +//! BLAKE3 engine) with the public types renamed (`Fp16Raw*`) so the FP16 scheme can extend the +//! AIR without touching the live FP8 consensus engine. The only functional addition over the +//! shared engine is an **output-egress** CTL channel (`IS_EGRESS_CV` + `cv_egress_limbs`, see +//! [`ctl::ctl_cv_egress_looking_blake3`]) that exports a compression's `cv_out` as 16-bit limbs +//! on a program-chosen key, which the FP16 noise binding consumes. All existing engine behavior +//! is byte-identical when the egress flag is 0. +//! +//! It still reuses the shared infrastructure it depends on: the `columns_view!` macro +//! ([`crate::circuit::fp8::columns_view`]), the generic constraint evaluators +//! ([`crate::circuit::utils`]), and the committed-LUT machinery ([`crate::circuit::fp8::luts`]). +//! Only the AIR itself is forked. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{ + FP16_RAW_BLAKE3_COL_MAP, Fp16RawBlake3ColumnsView, NUM_FP16_RAW_BLAKE3_COLUMNS, NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS, +}; +pub use stark::{ + Fp16RawBlake3Instruction, Fp16RawBlake3Program, Fp16RawBlake3Stark, Fp16RawBlake3TraceInputs, Fp16RawCvRef, + Fp16RawCvSource, Fp16RawMessageSource, Fp16RawPlaneId, Fp16RawPublicBinding, +}; diff --git a/zk-pow/src/circuit/fp16/blake3_fp16_stark/stark.rs b/zk-pow/src/circuit/fp16/blake3_fp16_stark/stark.rs new file mode 100644 index 000000000..f72233602 --- /dev/null +++ b/zk-pow/src/circuit/fp16/blake3_fp16_stark/stark.rs @@ -0,0 +1,3894 @@ +//! Proves every BLAKE3 compression used by FP8 V2 and binds the resulting public hashes. +//! +//! # Compression rows +//! +//! One BLAKE3 compression consumes a 64-byte message (sixteen little-endian `u32` words), an +//! eight-word chaining value (CV), a counter, block length, and flags. It occupies eight trace +//! rows: seven rows apply BLAKE3's seven permutation rounds, and the eighth applies the +//! feed-forward finalization and exposes the eight-word output CV. [`Fp16RawBlake3Program`] is the +//! public instruction schedule selecting each compression's CV source, message source, +//! counter/flag tweak, and optional public-output slot. +//! +//! # Protocol hash graph +//! +//! Leaf and parent compressions build four keyed Merkle roots: int8 values and bf16 block-scale +//! codes for each of matrices A and B. A separate keyed tree binds mixture-of-experts (MoE) +//! routing data when present. Eight parallel lookups route an internal CV by packing each +//! `(source trace row, CV word value)` pair injectively; `cv_route_key_or_tweak` carries the +//! source-row pointer on fetch rows or the instruction's public tweak on initialization rows. +//! +//! Two keyed wrapper compressions ([`append_commit_fold`]) fold the four roots into the +//! per-side commitment digests `blake3(values_root || scales_root, key=keyA/keyB)`, bound to the +//! `HASH_A`/`HASH_B` public inputs — the roots themselves stay internal CVs. +//! +//! After Matmul and XorFold, one final keyed compression hashes the folded lottery words under +//! `POW_KEY`; its output is the public jackpot hash. `HASH_A`, `HASH_B`, the optional +//! routing/offsets hashes, and the jackpot hash are public inputs. +//! +//! The verifier recomputes the schedule columns and checks their openings. Cross-table lookups +//! bind live int8/scale message blocks to InputQuantStark and lottery words to XorFoldStark; +//! byte and MoE-limb lookups range-check packed message data. Thus neither padding +//! compressions nor an alternative private instruction schedule can contribute to a public +//! binding. + +// TODO: this file contains many asserts, that should be prevented in advance + +use core::borrow::{Borrow, BorrowMut}; +use std::marker::PhantomData; + +use anyhow::{Result, ensure}; + +use pearl_blake3::{B3F_CHUNK_END, B3F_CHUNK_START, B3F_KEYED_HASH, B3F_ROOT, BLAKE3_MSG_LEN}; +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::lookup::{Column, Filter, Lookup}; +use starky::stark::Stark; + +use super::columns::{ + FP16_RAW_BLAKE3_COL_MAP, Fp16RawBlake3ColumnsView, Fp16RawBlake3StateCols, NUM_FP16_RAW_BLAKE3_COLUMNS, NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS, NUM_UINT8, + NUM_UNPACK_FLAGS, PI_HASH_A, PI_HASH_B, PI_HASH_JACKPOT, PI_HASH_OFFSETS, PI_HASH_ROUTING, PI_JACKPOT_KEY, PI_KEY_A, + PI_KEY_B, +}; +use crate::api::fp8::prequant::BLOCK_SIZE; +use crate::api::fp8::public_params::{HashId, MoEStatement}; +use crate::circuit::chip::blake3::logic::decode_is_msg_bits; +use crate::circuit::chip::blake3::program as chip_program; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// The BLAKE3 IV constants; the compression's fixed state words 8..12 (constraint 1). +pub const BLAKE3_IV: [u32; 8] = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +]; + +/// The BLAKE3 message word permutation (applied between rounds). +const BLAKE3_MSG_PERMUTATION: [usize; 16] = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; + +/// Rows per compression: 7 round rows + 1 finalization row. +pub const ROWS_PER_COMPRESSION: usize = 8; + +/// Key factor of the CV-routing lookup: `key = word + 2^34 * trace_row_index`. The factor is +/// 2^34, not 2^32, because the round block's unchecked-add slack admits words up to about 2^34; +/// this keeps the packing injective for every value accepted by the constraints. +const CV_ROUTING_KEY_FACTOR: u64 = 1 << 34; + +/// `apply BLAKE3_MSG_PERMUTATION`: `new[i] = old[BLAKE3_MSG_PERMUTATION[i]]` (the deployed +/// chip's `blake3_permute_msg`, generic so the constraint side can permute column handles). +fn blake3_permute(msg: &mut [T; 16]) { + let old = *msg; + for i in 0..16 { + msg[i] = old[BLAKE3_MSG_PERMUTATION[i]]; + } +} + +// ================================================================================================== +// Program: the compiled instruction schedule (deployed `BlakeInstruction` model) +// ================================================================================================== + +/// The six committed byte planes a compression's message bytes can come from. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Fp16RawPlaneId { + /// A-side int8 values plane (the sampled strip rows, `h * k` bytes row-major). + AValues, + /// A-side bf16 scales plane, `h * k / 4` bytes (one LE bf16 code per 8-element block). + AScales, + /// B-side int8 values plane, `w * k` bytes (B transposed row-major, matmul's layout). + BValues, + /// B-side bf16 scales plane, `w * k / 4` bytes. + BScales, + /// MoE routing plane: 16 u32 outer-index words per 64-byte block, each < 2^26. + Routing, + /// MoE offsets plane: the full zero-padded cumulative-count list `O`, 16 u32 words per + /// 64-byte block, every block opened. + Offsets, +} + +const NUM_PLANES: usize = 6; + +impl Fp16RawPlaneId { + fn index(self) -> usize { + match self { + Fp16RawPlaneId::AValues => 0, + Fp16RawPlaneId::AScales => 1, + Fp16RawPlaneId::BValues => 2, + Fp16RawPlaneId::BScales => 3, + Fp16RawPlaneId::Routing => 4, + Fp16RawPlaneId::Offsets => 5, + } + } +} + +/// A chaining value referenced by a parent compression: an earlier instruction's output, or a +/// witness **auxiliary CV** — the root of an unopened subtree, the deployed sparse-opening +/// mechanism (`CvType::Instruction` / `CvType::Auxiliary`). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Fp16RawCvRef { + /// `CV_OUT` of instruction `i` (must precede the referencing instruction). + Instruction(usize), + /// `aux_cvs[idx]` of the trace witness (32 bytes, prover-supplied). + Auxiliary(usize), +} + +/// The CV entering the compression (the constraint-3 mux source / the row-0 fetch). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Fp16RawCvSource { + /// Keyed compression under `KEY_A` (A-plane/routing chunk starts and parents). + KeyA, + /// Keyed compression under `KEY_B` (B-plane chunk starts and parents). + KeyB, + /// `JACKPOT_KEY` (the lottery compression). + JackpotKey, + /// The BLAKE3 IV constants — unkeyed compression. + Iv, + /// `CV_OUT` of instruction `src`, fetched through the CV-routing lookup on row 0 (block 2+ + /// of a multi-block chunk). + Chain(usize), +} + +/// Where one compression's 64 message bytes come from (deployed `MessageType`). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Fp16RawMessageSource { + /// 64 committed plane bytes at `offset` in the **chunk-padded** plane (deployed + /// `MatrixLeaf`), ingested 8 bytes per row through `UINT8_DATA`. `ctl_base` is the + /// element / scale-block CTL key of the block's first byte (ignored on the routing plane); + /// rows whose bytes lie past the raw plane length are chunk padding — CTL filters off. + /// The 64 bytes may span two adjacent opened strips: adjacent committed rows sit + /// back-to-back in the plane stream, so the offsets (and CTL keys) stay contiguous. + PlaneBytes { plane: Fp16RawPlaneId, offset: usize, ctl_base: u64 }, + /// 64 witness bytes, `aux_msgs[idx]` (deployed `AuxiliaryLeaf`): an unopened block that is + /// hashed but exports nothing. + AuxBytes { idx: usize }, + /// A block straddling an opening boundary (deployed `SplitLeaf`): only dwords + /// `skip..skip + take` carry opened plane bytes — `offset` / `ctl_base` are the stream + /// byte offset and CTL key of dword `skip` — while the remaining dwords carry the + /// unopened-neighbor bytes from `aux_msgs[aux_idx]` (the full 64-byte block), hashed but + /// exporting nothing. Arises when a committed row is not a multiple of 64 bytes (int8 + /// rows at `k % 64 != 0`, scales rows at `k % 256 != 0`); never on the routing plane. + PlaneBytesSplit { + plane: Fp16RawPlaneId, + offset: usize, + ctl_base: u64, + skip: usize, + take: usize, + aux_idx: usize, + }, + /// A Merkle parent: message = left child CV (words 0..8) | right child CV (words 8..16). + /// In-table children arrive through the CV-routing lookup (window fetches on rows 3 / 7); + /// auxiliary children are witness bytes ingested as 4 dword rows each. + Parent { left: Fp16RawCvRef, right: Fp16RawCvRef }, + /// The 16 folded lottery words (witness bytes; pinned by the XorFold CTL against + /// `BLAKE3_MSG` on the load row — see `super::ctl`). + Lottery, +} + +/// Which public input this compression's output binds to (constraint 4). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Fp16RawPublicBinding { + HashA, + HashB, + HashRouting, + HashOffsets, + HashJackpot, +} + +/// One compiled compression = 8 trace rows (the deployed `BlakeInstruction` shape: CV source, +/// message source, tweak, binding). +#[derive(Clone, Copy, Debug)] +pub struct Fp16RawBlake3Instruction { + pub cv: Fp16RawCvSource, + pub msg: Fp16RawMessageSource, + /// BLAKE3 block counter (the chunk index for chunk blocks, 0 for parents), < 2^48. + pub counter: u64, + /// BLAKE3 block length (64 for full blocks), < 2^7. + pub block_len: u32, + /// BLAKE3 domain flags (`B3F_*`), < 2^8. + pub flags: u32, + pub bind: Option, + /// **FP16 fork addition.** When `Some(base)`, this compression's finalization row sets + /// `IS_EGRESS_CV` and exports `CV_OUT` as 16 little-endian 16-bit limbs on the output-egress + /// CTL channel ([`super::ctl::ctl_cv_egress_looking_blake3`]) under keys `base..base + 16`. + /// `None` leaves the egress flag and limbs at zero, so the engine behaves identically to the + /// shared FP8 AIR. Independent of `bind` (a compression may both bind a public hash and + /// egress its CV). + pub egress: Option, +} + +impl Fp16RawBlake3Instruction { + /// The lottery compression: one keyed block under `JACKPOT_KEY` (chunk start + end + root), + /// message = XorFold's 16 folded words, output bound to `HASH_JACKPOT`. Scheduled here — + /// the deployed pipeline runs the jackpot outside `BlakeProgram`. + pub fn lottery() -> Self { + Self { + cv: Fp16RawCvSource::JackpotKey, + msg: Fp16RawMessageSource::Lottery, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags: (B3F_CHUNK_START | B3F_CHUNK_END | B3F_ROOT | B3F_KEYED_HASH) as u32, + bind: Some(Fp16RawPublicBinding::HashJackpot), + egress: None, + } + } + + /// The packed tweak riding `CV_ROUTE_KEY_OR_TWEAK` on row 1, in the deployed init-state bit + /// window layout: `counter(48 bits) | flags(8) | block_len(7)`. + fn tweak_packed(&self) -> u64 { + assert!(self.counter < 1 << 48 && self.flags < 1 << 8 && self.block_len < 1 << 7); + self.counter + ((self.flags as u64) << 48) + ((self.block_len as u64) << 56) + } + + /// CV-routing fetches of this compression: `(row within the compression, source + /// instruction)`. Row 0 is the chunk-chaining fetch; rows 3 / 7 are the parent window + /// fetches — the positions that land each fetched CV at message words 0..8 / 8..16 through + /// the shift-by-2 buffer. + fn fetches(&self) -> Vec<(usize, usize)> { + let mut fetches = Vec::new(); + if let Fp16RawCvSource::Chain(src) = self.cv { + fetches.push((0, src)); + } + if let Fp16RawMessageSource::Parent { left, right } = self.msg { + if let Fp16RawCvRef::Instruction(src) = left { + fetches.push((3, src)); + } + if let Fp16RawCvRef::Instruction(src) = right { + fetches.push((7, src)); + } + } + fetches + } +} + +/// Appends one side's commitment-fold wrapper — a single keyed compression mirroring +/// `proof_utils.rs::operand_digest_fp10`: `blake3(values_root || scales_root, key=key)`, +/// whose output binds to the side's public hash. `values_root`/`scales_root` are the +/// instruction indices of the side's tree-root compressions (both roots arrive through the +/// CV window fetches); `key` is the side's opening-key CV source (`KeyA`/`KeyB`). +pub fn append_commit_fold( + instrs: &mut Vec, + values_root: usize, + scales_root: usize, + bind: Fp16RawPublicBinding, + key: Fp16RawCvSource, +) { + debug_assert!( + matches!(key, Fp16RawCvSource::KeyA | Fp16RawCvSource::KeyB), + "commit-fold key must be KeyA/KeyB" + ); + instrs.push(Fp16RawBlake3Instruction { + cv: key, + msg: Fp16RawMessageSource::Parent { + left: Fp16RawCvRef::Instruction(values_root), + right: Fp16RawCvRef::Instruction(scales_root), + }, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags: (B3F_CHUNK_START | B3F_CHUNK_END | B3F_ROOT | B3F_KEYED_HASH) as u32, + bind: Some(bind), + egress: None, + }); +} + +/// The compiled schedule of one job's hash forest: the full per-plane commitment trees (with +/// auxiliary material at the opening boundary), the routing tree, and the lottery — one +/// instruction per compression, children before parents. Produced by the fp8 program +/// compiler; everything here is class (a) (verifier-recomputable from public job geometry). +#[derive(Clone, Debug, Default)] +pub struct Fp16RawBlake3Program { + pub instructions: Vec, + /// Number of auxiliary 64-byte messages the schedule references (witness bound). + pub num_aux_msgs: usize, + /// Number of auxiliary sibling CVs the schedule references (witness bound). + pub num_aux_cvs: usize, + /// The MoE sampled-entry pins, `(stream word index, public outer index)` with the stream + /// word index counting u32 words of the concatenated opened hotspot blocks + /// (`16 * strip + word_in_block`), strictly ascending, each value < 2^26. Exactly the + /// deployed chip's selective outer-index schedule (`pearl_preprocess.rs:: + /// compute_outer_index_packed`): `IS_FIRST_OUTER`/`IS_SECOND_OUTER` fire only where a + /// routing row ingests a pinned word, `MOE_OUTER_INDICES_PACKED` carries only pinned + /// values (zero in unpinned slots), and every *other* word of the opened blocks stays + /// prover witness, bound solely by the hash chain to `HASH_ROUTING`. Class (a) — derived + /// from the public MoE data ([`MoEStatement::routing_pins`]); empty for dense jobs. + pub routing_pins: Vec<(usize, u32)>, + /// The MoE scalar statement driving the offsets pins and the order chains; `None` for + /// dense jobs. Class (a) — public statement data. + pub moe: Option, + /// **FP16 fork addition.** Per-compression message-word pins, `(instruction index, 16 u32 + /// words)`. For each listed compression the engine pins all 16 message words to the given + /// public constants, driving the already-sound general `IS_WORD_PIN_FIRST`/`IS_WORD_PIN_SECOND` + /// equality constraint (`word_j == WORD_PIN_*`, `super::stark` constraint group 7) on every one + /// of its 8 rows: row `j` pins word `2j` to `words[2j]` and word `2j+1` to `words[2j+1]`. The + /// pin values are class (a) (recomputed by the batch verifier from `known_values`), so the + /// compression's whole 64-byte message is verifier-fixed rather than free witness — the + /// mechanism the FP16 noise binding uses to pin the keyed-XOF material blocks (the `noise-line` + /// label and each line's `side|factor|line` material). Empty for every other program; the + /// listed words MUST equal the compression's actual (`AuxBytes`) message words or the pin + /// constraint rejects. Entries are matched by instruction index, in any order. + pub msg_pins: Vec<(usize, [u32; 16])>, + /// **FP16 fork addition.** When `Some(bits)`, forces the trace height to `1 << bits` (which must + /// be at least the live rows' next power of two) instead of the default next-power-of-two. Lets + /// a batch-wired noise program snap its height onto a [`super::super::driver:: + /// FP16_REACHABLE_DEGREE_BITS`] member (the consensus fold ladder / universal-wrapper + /// prerequisite). `None` keeps the shared engine's next-power-of-two padding. + pub height_bits: Option, +} + +/// The public MoE scalars the offsets/routing schedule is derived from: the winner `w`, the +/// bracketing cumulative counts `O_{w-1}`/`O_w`, the total `O_{e-1}`, the expert count `e`, +/// and the A-row count `m` (the strict upper bound on routing values). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct MoeSchedule { + pub w: u32, + pub experts: u32, + pub o_w_prev: u32, + pub o_w: u32, + pub o_last: u32, + pub m: u32, +} + +impl MoeSchedule { + /// Assembles the schedule from the public MoE statement plus the expert count and `m`, + /// failing closed on a statement whose scalars violate the schedule's invariants + pub(crate) fn new(stmt: &MoEStatement, experts: u16, m: u32) -> Result { + let (w, experts, o_w_prev, o_w, o_last) = (u32::from(stmt.w), u32::from(experts), stmt.o_w_prev, stmt.o_w, stmt.o_last); + ensure!(experts >= 1 && w < experts, "malformed MoE schedule: w/e"); + ensure!(m >= 1, "malformed MoE schedule: m = 0"); + ensure!( + o_w_prev <= o_w && o_w <= o_last, + "malformed MoE schedule: O_{{w-1}} <= O_w <= O_{{e-1}}" + ); + ensure!(w > 0 || o_w_prev == 0, "O_{{w-1}} must be 0 for w = 0"); + ensure!(w + 1 < experts || o_w == o_last, "O_w must equal O_{{e-1}} for w = e-1"); + Ok(Self { + w, + experts, + o_w_prev, + o_w, + o_last, + m, + }) + } + + /// The pinned value of offsets-stream word `p`, `None` where the word is unpinned: + /// - words `w-1`, `w` and `e-1` carry the public `O_{w-1}`, `O_w` and `O_{e-1}`; + /// - every word past `e-1` is zero padding; + /// - for `w = 0` there is no word to pin `O_{w-1}` to, and for `w = e-1` the `O_w` and + /// `O_{e-1}` pins coincide. The statement then enforces `O_{w-1} = 0` respectively + /// `O_w = O_{e-1}` natively. + fn offsets_pin_at(&self, p: usize) -> Option { + let (w, e) = (self.w as usize, self.experts as usize); + if p >= e { + return Some(0); + } + if p + 1 == e { + return Some(self.o_last as u64); + } + if p == w { + return Some(self.o_w as u64); + } + (w > 0 && p == w - 1).then_some(self.o_w_prev as u64) + } + + /// Chain gates of the offsets row whose first stream word is `p`: `(intra, inter)` — + /// intra enforces `O_p <= O_{p+1}` in-row, inter `O_{p-1} <= O_p` against the carry. + /// Both stop at the pinned `O_{e-1}`; the zero padding is pinned, not chained. + fn offsets_chain_at(&self, p: usize) -> (bool, bool) { + let e = self.experts as usize; + (p + 1 < e, p >= 1 && p < e) + } + + /// First opened routing block (the routing stream's block base). + fn routing_block_base(&self) -> usize { + self.o_w_prev as usize * std::mem::size_of::() / BLAKE3_MSG_LEN + } + + /// Chain gates of the routing row whose first *global* routing word is `g`: + /// `(intra, inter, bound_first, bound_second)`. Intra/inter enforce strict increase over + /// the winner slice `[O_{w-1}, O_w)`; the bound flags mark the slice's last word, whose + /// row pins `m - 1` for the upper-bound check. + fn routing_chain_at(&self, g: u64) -> (bool, bool, bool, bool) { + let (lo, hi) = (u64::from(self.o_w_prev), u64::from(self.o_w)); + let in_slice = |x: u64| lo <= x && x < hi; + ( + in_slice(g) && in_slice(g + 1), + g > lo && in_slice(g), + hi > lo && g == hi - 1, + hi > lo && g + 1 == hi - 1, + ) + } +} + +impl Fp16RawBlake3Program { + // TODO: Consolidate `chip_program::BlakeProgram` and this STARK-specific + // `Fp16RawBlake3Program` into one canonical program representation. + /// Translates the deployed program compiler's output (`chip/blake3/program.rs`, compiled + /// by the verifier from public data only) into the in-table schedule, appending the + /// lottery compression (the deployed pipeline schedules the jackpot outside + /// `BlakeProgram`). The mapping is one-to-one: + /// - `is_cv_key` -> [`Fp16RawCvSource::KeyA`]/[`Fp16RawCvSource::KeyB`] by the `KeySource` side, and + /// `KeySource::Jackpot` -> [`Fp16RawCvSource::JackpotKey`]; otherwise [`Fp16RawCvSource::Chain`] of the + /// *previous* instruction (the deployed evaluator chains `cvs.last()`); + /// - `MatrixLeaf` -> [`Fp16RawMessageSource::PlaneBytes`]: the strip-list index and in-row offset + /// give the offset into the concatenated opened strips (the [`Fp16RawBlake3TraceInputs`] plane + /// streams) and the CTL key base — flat element index on values planes, block index on + /// scales planes, B bases past A's key range (`+ h*k` / `+ h*k/BLOCK_SIZE`). Scales + /// strips sit at list indices `h..2h` / `w..2w` (the deployed prequant convention). + /// A block spanning two adjacent opened strips stays one contiguous stream range; + /// - `SplitLeaf` -> [`Fp16RawMessageSource::PlaneBytesSplit`]: the opened dword window maps as + /// `MatrixLeaf`, the unopened remainder rides the auxiliary message; + /// - `RoutingLeaf { hotspot_idx }` -> `PlaneBytes` on the routing plane at + /// `64 * hotspot_idx` (the routing stream is the concatenated opened hotspot blocks); + /// - `OffsetsLeaf { block_idx }` -> `PlaneBytes` on the offsets plane at `64 * block_idx` + /// (the offsets tree is fully opened: the stream is the whole padded list); + /// - `AuxiliaryLeaf { idx }` -> [`Fp16RawMessageSource::AuxBytes`]; `Parent` -> `Parent` with + /// `CvType::Instruction/Auxiliary -> Fp16RawCvRef` verbatim (same witness indexing as + /// `PrivateProofParams::external_msgs/external_cvs`); + /// - the routing/offsets root flags -> `HashRouting` / `HashOffsets`; the four plane + /// roots stay unbound internal CVs — [`append_commit_fold`] wires them into the + /// `HASH_A`/`HASH_B` wrappers appended before the lottery. + /// + /// `routing_pins` is the MoE sampled-entry schedule (`MoEStatement::routing_pins`) and + /// `moe` the scalar statement driving the offsets pins and order chains (both empty/`None` + /// for a dense job); `Self::validate` cross-checks them against the instructions. + /// + /// Panics unless `program` is a **prequant four-plane** program (each of the A/B + /// values/scales roots produced exactly once). FP8 proves only the + /// prequant four-plane statement shape. + pub fn from_blake_program( + program: &chip_program::BlakeProgram, + k: usize, + routing_pins: Vec<(usize, u32)>, + moe: Option, + ) -> Self { + // Fail closed on the scheme using the four-plane shape; record the root indices the + // fold wrappers reference. + let mut plane_roots = [const { Vec::new() }; 4]; + for (i, instr) in program.instructions.iter().enumerate() { + // Bridge deployed chip field names to fp8 plane names. + let root_slot = match instr.out { + chip_program::HashOut::A => 0, + chip_program::HashOut::AScales => 1, + chip_program::HashOut::B => 2, + chip_program::HashOut::BScales => 3, + _ => continue, + }; + plane_roots[root_slot].push(i); + } + let [a_values_root, a_scales_root, b_values_root, b_scales_root] = plane_roots.map(|roots| { + assert_eq!( + roots.len(), + 1, + "not a prequant four-plane program (A/B values + scales roots each produced once)" + ); + roots[0] + }); + + let (h, w) = (program.num_a_rows, program.num_b_cols); + let scale_row_bytes = 2 * (k / BLOCK_SIZE); + let cv_ref = |cv: chip_program::CvType| match cv { + chip_program::CvType::Instruction { idx } => Fp16RawCvRef::Instruction(idx), + chip_program::CvType::Auxiliary { idx } => Fp16RawCvRef::Auxiliary(idx), + }; + // One dword's plane and byte offset in that plane's stream (the concatenated opened + // strips). Adjacent committed rows open to adjacent strips, so the stream offsets of + // a block straddling a row boundary stay contiguous. + let resolve_dword = |d: chip_program::MatDwordId| -> (Fp16RawPlaneId, usize) { + let side_strips = if d.is_b_strip { w } else { h }; + let is_scales = d.strip_idx >= side_strips; + let plane = match (d.is_b_strip, is_scales) { + (false, false) => Fp16RawPlaneId::AValues, + (false, true) => Fp16RawPlaneId::AScales, + (true, false) => Fp16RawPlaneId::BValues, + (true, true) => Fp16RawPlaneId::BScales, + }; + let row_bytes = if is_scales { scale_row_bytes } else { k }; + (plane, (d.strip_idx % side_strips) * row_bytes + d.idx_in_strip) + }; + let ctl_base = |plane: Fp16RawPlaneId, offset: usize| -> u64 { + match plane { + Fp16RawPlaneId::AValues => offset as u64, + Fp16RawPlaneId::BValues => (h * k + offset) as u64, + Fp16RawPlaneId::AScales => (offset / 2) as u64, + Fp16RawPlaneId::BScales => (h * k / BLOCK_SIZE + offset / 2) as u64, + Fp16RawPlaneId::Routing | Fp16RawPlaneId::Offsets => unreachable!(), + } + }; + + // + 3: one commitment fold per side plus the lottery. + let mut instructions = Vec::with_capacity(program.instructions.len() + 3); + for (i, instr) in program.instructions.iter().enumerate() { + let msg = match instr.msg { + chip_program::MessageType::MatrixLeaf { mat_data } => { + let (plane, offset) = resolve_dword(mat_data.dwords[0]); + debug_assert!( + mat_data + .dwords + .iter() + .enumerate() + .all(|(j, dw)| { resolve_dword(*dw) == (plane, offset + j * chip_program::DWORD_SIZE) }), + "matrix message must be 64 stream-contiguous bytes of one plane" + ); + Fp16RawMessageSource::PlaneBytes { + plane, + offset, + ctl_base: ctl_base(plane, offset), + } + } + chip_program::MessageType::SplitLeaf { mat_dwords, aux_idx } => { + let skip = mat_dwords.iter().position(|d| d.is_some()).expect("split leaf opens dwords"); + let take = mat_dwords[skip..].iter().take_while(|d| d.is_some()).count(); + assert!( + take < mat_dwords.len() && mat_dwords[skip + take..].iter().all(|d| d.is_none()), + "split leaf's opened dwords must be one proper contiguous window" + ); + let (plane, offset) = resolve_dword(mat_dwords[skip].unwrap()); + debug_assert!( + mat_dwords[skip..skip + take] + .iter() + .enumerate() + .all(|(j, dw)| { resolve_dword(dw.unwrap()) == (plane, offset + j * chip_program::DWORD_SIZE) }), + "split leaf's opened dwords must be stream-contiguous in one plane" + ); + Fp16RawMessageSource::PlaneBytesSplit { + plane, + offset, + ctl_base: ctl_base(plane, offset), + skip, + take, + aux_idx, + } + } + chip_program::MessageType::RoutingLeaf { hotspot_idx } => Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Routing, + offset: BLAKE3_MSG_LEN * hotspot_idx, + ctl_base: 0, + }, + chip_program::MessageType::OffsetsLeaf { block_idx } => Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Offsets, + offset: BLAKE3_MSG_LEN * block_idx, + ctl_base: 0, + }, + chip_program::MessageType::AuxiliaryLeaf { idx } => Fp16RawMessageSource::AuxBytes { idx }, + chip_program::MessageType::Parent { cv_low, cv_high } => Fp16RawMessageSource::Parent { + left: cv_ref(cv_low), + right: cv_ref(cv_high), + }, + }; + let bind = match instr.out { + chip_program::HashOut::Routing => Some(Fp16RawPublicBinding::HashRouting), + chip_program::HashOut::Offsets => Some(Fp16RawPublicBinding::HashOffsets), + _ => None, // Plane roots stay internal: the fold wrappers consume their CVs. + }; + assert!( + instr.key_source != chip_program::KeySource::Prev || i > 0, + "chained CV on the first instruction" + ); + instructions.push(Fp16RawBlake3Instruction { + cv: match instr.key_source { + chip_program::KeySource::KeyA => Fp16RawCvSource::KeyA, + chip_program::KeySource::KeyB => Fp16RawCvSource::KeyB, + chip_program::KeySource::Jackpot => Fp16RawCvSource::JackpotKey, + chip_program::KeySource::Prev => Fp16RawCvSource::Chain(i - 1), + }, + msg, + counter: u64::from(instr.tweak.counter_low) | (u64::from(instr.tweak.counter_high) << 32), + block_len: instr.tweak.block_len, + flags: instr.tweak.flags, + bind, + egress: None, + }); + } + // Append folding instructions -- to get one hash per side (keyed by the side's opening key). + append_commit_fold( + &mut instructions, + a_values_root, + a_scales_root, + Fp16RawPublicBinding::HashA, + Fp16RawCvSource::KeyA, + ); + append_commit_fold( + &mut instructions, + b_values_root, + b_scales_root, + Fp16RawPublicBinding::HashB, + Fp16RawCvSource::KeyB, + ); + instructions.push(Fp16RawBlake3Instruction::lottery()); + Self { + instructions, + num_aux_msgs: program.num_auxiliary_msgs, + num_aux_cvs: program.num_auxiliary_cvs, + routing_pins, + moe, + msg_pins: Vec::new(), + height_bits: None, + } + } + + /// Live (unpadded) trace rows. + pub fn num_live_rows(&self) -> usize { + ROWS_PER_COMPRESSION * self.instructions.len() + } + + /// The pinned outer-index value at stream word `pos`, `None` where the word is a free + /// witness neighbor (`routing_pins` is sorted by position — `validate`). + fn routing_pin_at(&self, pos: usize) -> Option { + self.routing_pins + .binary_search_by_key(&pos, |&(p, _)| p) + .ok() + .map(|i| self.routing_pins[i].1 as u64) + } + + /// Trace height: live rows padded to a power of two, or the forced [`Self::height_bits`] height + /// (for on-ladder batch wiring). + pub fn num_rows(&self) -> usize { + let default = self.num_live_rows().next_power_of_two(); + match self.height_bits { + Some(bits) => { + let forced = 1usize << bits; + assert!(forced >= default, "forced height 2^{bits} is below the live next-power-of-two {default}"); + forced + } + None => default, + } + } + + /// Schedule sanity: back-references only, witness indices in bounds, at most one + /// instruction per public binding, and the MoE pin schedule consistent with the routing + /// instructions — pins strictly ascending with values < 2^26 (the two-limb packing cap), + /// and every pin inside a *scheduled* routing block. The last check is the load-bearing + /// one: a pin whose block is never hashed in-table would silently drop that sampled + /// entry from the statement. (The converse — a scheduled routing block without pins — + /// is legitimate: such a block's words are simply free witness under the hash chain, + /// like the chunk-padding blocks of a dense fixture tree.) + fn validate(&self) { + let mut seen_binds = Vec::new(); + let mut routing_blocks = Vec::new(); + let mut offsets_blocks = Vec::new(); + let mut lottery_count = 0; + for (c, instr) in self.instructions.iter().enumerate() { + // TODO: Remove this runtime validation once `Fp16RawBlake3Program` construction is + // encapsulated and guarantees exactly one canonical lottery instruction. + let has_lottery_role = matches!(instr.cv, Fp16RawCvSource::JackpotKey) + || matches!(instr.msg, Fp16RawMessageSource::Lottery) + || instr.bind == Some(Fp16RawPublicBinding::HashJackpot); + if has_lottery_role { + assert!( + matches!(instr.cv, Fp16RawCvSource::JackpotKey) + && matches!(instr.msg, Fp16RawMessageSource::Lottery) + && instr.counter == 0 + && instr.block_len == BLAKE3_MSG_LEN as u32 + && instr.flags == (B3F_CHUNK_START | B3F_CHUNK_END | B3F_ROOT | B3F_KEYED_HASH) as u32 + && instr.bind == Some(Fp16RawPublicBinding::HashJackpot), + "instruction {c}: malformed lottery compression" + ); + lottery_count += 1; + } + if let Fp16RawCvSource::Chain(src) = instr.cv { + assert!(src < c, "instruction {c}: CV chain source {src} is not earlier"); + } + if instr.cv == Fp16RawCvSource::Iv { + assert_eq!( + instr.flags & B3F_KEYED_HASH as u32, + 0, + "instruction {c}: unkeyed compression carries the keyed flag" + ); + } + if let Fp16RawMessageSource::Parent { left, right } = instr.msg { + for child in [left, right] { + match child { + Fp16RawCvRef::Instruction(src) => assert!(src < c, "instruction {c}: child {src} is not earlier"), + Fp16RawCvRef::Auxiliary(idx) => assert!(idx < self.num_aux_cvs, "instruction {c}: aux CV {idx} OOB"), + } + } + } + if let Fp16RawMessageSource::AuxBytes { idx } = instr.msg { + assert!(idx < self.num_aux_msgs, "instruction {c}: aux msg {idx} OOB"); + } + if let Fp16RawMessageSource::PlaneBytesSplit { + plane, + skip, + take, + aux_idx, + .. + } = instr.msg + { + assert!(plane != Fp16RawPlaneId::Routing, "instruction {c}: routing blocks never split"); + assert!( + (1..ROWS_PER_COMPRESSION).contains(&take) && skip + take <= ROWS_PER_COMPRESSION, + "instruction {c}: a split block has both opened and unopened dwords" + ); + assert!(aux_idx < self.num_aux_msgs, "instruction {c}: split aux msg {aux_idx} OOB"); + } + if let Fp16RawMessageSource::PlaneBytes { plane, offset, .. } = instr.msg + && (plane == Fp16RawPlaneId::Routing || plane == Fp16RawPlaneId::Offsets) + { + assert_eq!(offset % 64, 0, "instruction {c}: routing/offsets block not 64-byte aligned"); + if plane == Fp16RawPlaneId::Routing { + routing_blocks.push((c, offset / 64)); + } else { + offsets_blocks.push((c, offset / 64)); + } + } + if let Some(bind) = instr.bind { + assert!(!seen_binds.contains(&bind), "binding {bind:?} set twice"); + seen_binds.push(bind); + } + } + assert!( + self.routing_pins.windows(2).all(|p| p[0].0 < p[1].0), + "routing pins must be strictly ascending by stream position" + ); + for &(pos, value) in &self.routing_pins { + assert!(value < 1 << 26, "routing pin value {value} does not fit 26 bits"); + assert!( + routing_blocks.iter().any(|&(_, b)| b == pos / 16), + "routing pin at stream word {pos} lies outside every scheduled routing block" + ); + } + + assert_eq!( + self.moe.is_some(), + !offsets_blocks.is_empty(), + "offsets sections and the MoE schedule imply each other" + ); + if let Some(s) = &self.moe { + // Both planes stream as blocks 0, 1, 2, ... in instruction order; the placement + // inside the tree is pinned by the recomputed tweak/chain schedule. + assert!( + offsets_blocks.iter().enumerate().all(|(i, &(_, b))| b == i), + "offsets blocks must be scheduled completely and in order" + ); + assert!( + routing_blocks.iter().enumerate().all(|(i, &(_, b))| b == i), + "routing blocks must be scheduled completely and in order" + ); + if let (Some(&(last_routing, _)), Some(&(first_offsets, _))) = (routing_blocks.last(), offsets_blocks.first()) { + assert!( + last_routing < first_offsets, + "routing blocks must all precede the offsets blocks (shared chain carry)" + ); + } + assert!( + s.experts as usize <= offsets_blocks.len() * 16, + "offsets stream too short for e words" + ); + if s.o_w > s.o_w_prev { + assert!( + s.routing_block_base() + routing_blocks.len() + >= (s.o_w as usize * std::mem::size_of::()).div_ceil(BLAKE3_MSG_LEN), + "routing stream must cover the winner slice's block range" + ); + let base = 16 * s.routing_block_base(); + for &(pos, _) in &self.routing_pins { + let g = (base + pos) as u64; + assert!( + u64::from(s.o_w_prev) <= g && g < u64::from(s.o_w), + "sampled routing pin at global word {g} lies outside the winner slice" + ); + } + } else { + assert!(routing_blocks.is_empty() && self.routing_pins.is_empty(), "empty slice"); + } + assert!( + seen_binds.contains(&Fp16RawPublicBinding::HashOffsets) && seen_binds.contains(&Fp16RawPublicBinding::HashRouting), + "MoE programs must bind HASH_ROUTING and HASH_OFFSETS" + ); + } else { + assert!( + routing_blocks.is_empty() && self.routing_pins.is_empty(), + "dense programs schedule no routing blocks" + ); + } + assert_eq!( + lottery_count, 1, + "Blake3 program must contain exactly one lottery compression" + ); + } + + /// Generates the Fp16RawBlake3Stark trace and public inputs. Bit-exact against native BLAKE3: with + /// a correctly compiled schedule the bound tree roots equal `pearl_blake3::MerkleTree` + /// roots over the chunk-padded full planes keyed with `key_a`/`key_b` (auxiliary CVs standing + /// in for the unopened subtrees), and `HASH_JACKPOT` equals + /// `blake3::keyed_hash(jackpot_key, lottery bytes)`. + pub fn generate_trace( + &self, + inputs: &Fp16RawBlake3TraceInputs<'_>, + ) -> (Vec<[F; NUM_FP16_RAW_BLAKE3_COLUMNS]>, [F; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS]) { + self.validate(); + assert_eq!( + inputs.aux_msgs.len(), + self.num_aux_msgs, + "aux msgs must match the compiled schedule" + ); + assert_eq!( + inputs.aux_cvs.len(), + self.num_aux_cvs, + "aux CVs must match the compiled schedule" + ); + // The witness routing words at pinned positions must equal the public outer indices + // (`parse_proof` guarantees it for an honest witness; failing fast here beats + // emitting a trace the known-column check then rejects). Unpinned words are free + // witness — any u32, no 26-bit cap. + for &(pos, value) in &self.routing_pins { + assert_eq!( + inputs.routing_words.get(pos).copied(), + Some(value), + "witness routing word at pinned stream position {pos} differs from the public outer index" + ); + } + + // ---- Plane byte streams, chunk-padded (the padding bytes are hashed). ---- + let routing_bytes: Vec = inputs.routing_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let offsets_bytes: Vec = inputs.offsets_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let raw_lens: [usize; NUM_PLANES] = [ + inputs.a_values.len(), + inputs.a_scales.len(), + inputs.b_values.len(), + inputs.b_scales.len(), + routing_bytes.len(), + offsets_bytes.len(), + ]; + let hash_id = |plane: Fp16RawPlaneId| match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::AScales => inputs.a_hash_id, + Fp16RawPlaneId::BValues | Fp16RawPlaneId::BScales => inputs.b_hash_id, + Fp16RawPlaneId::Routing => inputs.routing_hash_id, + Fp16RawPlaneId::Offsets => inputs.offsets_hash_id, + }; + let planes: [Vec; NUM_PLANES] = [ + hash_id(Fp16RawPlaneId::AValues).pad(inputs.a_values), + hash_id(Fp16RawPlaneId::AScales).pad(inputs.a_scales), + hash_id(Fp16RawPlaneId::BValues).pad(inputs.b_values), + hash_id(Fp16RawPlaneId::BScales).pad(inputs.b_scales), + hash_id(Fp16RawPlaneId::Routing).pad(&routing_bytes), + hash_id(Fp16RawPlaneId::Offsets).pad(&offsets_bytes), + ]; + + // ---- Phase A: evaluate every compression natively (messages, CV chain, outputs). ---- + let aux_cv_words = |idx: usize| -> [u32; 8] { + core::array::from_fn(|i| u32::from_le_bytes(inputs.aux_cvs[idx][4 * i..4 * i + 4].try_into().unwrap())) + }; + let instrs = &self.instructions; + let mut msgs: Vec<[u32; 16]> = Vec::with_capacity(instrs.len()); + let mut cvs_in: Vec<[u32; 8]> = Vec::with_capacity(instrs.len()); + let mut cvs_out: Vec<[u32; 8]> = Vec::with_capacity(instrs.len()); + for instr in instrs { + let m: [u32; 16] = match instr.msg { + Fp16RawMessageSource::PlaneBytes { plane, offset, .. } => { + let bytes = &planes[plane.index()][offset..offset + 64]; + core::array::from_fn(|i| u32::from_le_bytes(bytes[4 * i..4 * i + 4].try_into().unwrap())) + } + Fp16RawMessageSource::PlaneBytesSplit { + plane, + offset, + skip, + take, + aux_idx, + .. + } => { + // Opened dwords from the plane stream, the rest from the auxiliary block. + let mut bytes = inputs.aux_msgs[aux_idx]; + let stream = &planes[plane.index()][offset..offset + NUM_UINT8 * take]; + bytes[NUM_UINT8 * skip..NUM_UINT8 * (skip + take)].copy_from_slice(stream); + core::array::from_fn(|i| u32::from_le_bytes(bytes[4 * i..4 * i + 4].try_into().unwrap())) + } + Fp16RawMessageSource::AuxBytes { idx } => { + let bytes = &inputs.aux_msgs[idx]; + core::array::from_fn(|i| u32::from_le_bytes(bytes[4 * i..4 * i + 4].try_into().unwrap())) + } + Fp16RawMessageSource::Parent { left, right } => { + let side = |child: Fp16RawCvRef| -> [u32; 8] { + match child { + Fp16RawCvRef::Instruction(src) => cvs_out[src], + Fp16RawCvRef::Auxiliary(idx) => aux_cv_words(idx), + } + }; + let (l, r) = (side(left), side(right)); + core::array::from_fn(|i| if i < 8 { l[i] } else { r[i - 8] }) + } + Fp16RawMessageSource::Lottery => inputs.lottery_words, + }; + let cv: [u32; 8] = match instr.cv { + Fp16RawCvSource::KeyA => inputs.key_a, + Fp16RawCvSource::KeyB => inputs.key_b, + Fp16RawCvSource::JackpotKey => inputs.jackpot_key, + Fp16RawCvSource::Iv => BLAKE3_IV, + Fp16RawCvSource::Chain(src) => cvs_out[src], + }; + let state = native_compress_state(&cv, &m, instr.counter, instr.block_len, instr.flags); + msgs.push(m); + cvs_in.push(cv); + cvs_out.push(core::array::from_fn(|i| state[i] ^ state[8 + i])); + } + + // ---- Phase B: fill the rows. ---- + let num_live = self.num_live_rows(); + let num_rows = self.num_rows(); + let mut rows: Vec<[F; NUM_FP16_RAW_BLAKE3_COLUMNS]> = vec![[F::ZERO; NUM_FP16_RAW_BLAKE3_COLUMNS]; num_rows]; + let mut freq = vec![0u64; num_rows]; + // Deferred slice-bound limbs for the row after IS_BOUND_SECOND (at most one per job). + let mut bound_write: Option<(usize, [F; 2])> = None; + + for (c, instr) in instrs.iter().enumerate() { + let r0 = ROWS_PER_COMPRESSION * c; + let m = msgs[c]; + + // Flags, program columns, message bytes (the buffer itself is filled globally). + for j in 0..ROWS_PER_COMPRESSION { + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + j].borrow_mut(); + row.trace_row_index = F::from_canonical_usize(r0 + j); + if j == 0 { + row.is_new_blake = F::ONE; + match instr.cv { + Fp16RawCvSource::KeyA => row.is_use_key_a = F::ONE, + Fp16RawCvSource::KeyB => row.is_use_key_b = F::ONE, + Fp16RawCvSource::JackpotKey => row.is_use_jackpot_key = F::ONE, + Fp16RawCvSource::Iv => row.is_use_iv = F::ONE, + Fp16RawCvSource::Chain(_) => {} // IS_CV_IN doubles as the mux selector (fetch below). + } + for i in 0..8 { + row.blake3_cv[i] = F::from_canonical_u32(cvs_in[c][i]); + } + } + if j == 1 { + row.cv_route_key_or_tweak = F::from_canonical_u64(instr.tweak_packed()); + } + if j == ROWS_PER_COMPRESSION - 1 { + row.is_last_round = F::ONE; + match instr.bind { + Some(Fp16RawPublicBinding::HashA) => row.is_bind_hash_a = F::ONE, + Some(Fp16RawPublicBinding::HashB) => row.is_bind_hash_b = F::ONE, + Some(Fp16RawPublicBinding::HashRouting) => row.is_bind_routing_hash = F::ONE, + Some(Fp16RawPublicBinding::HashOffsets) => row.is_bind_offsets_hash = F::ONE, + _ => {} + } + // FP16 fork addition: output egress on the finalization row. CV_EGRESS_LIMBS + // is filled from CV_OUT below (once the finalization CV is known). The egress + // key reuses CTL_KEY_BASE, which is otherwise 0 on finalization rows. + if let Some(base) = instr.egress { + row.is_egress_cv = F::ONE; + row.ctl_key_base = F::from_canonical_u64(base); + } + } + if instr.bind == Some(Fp16RawPublicBinding::HashJackpot) { + row.is_bind_jackpot_hash = F::ONE; // All 8 rows (CTL filter; see columns.rs). + } + + match instr.msg { + Fp16RawMessageSource::PlaneBytes { plane, offset, ctl_base } => { + let byte_offset = offset + NUM_UINT8 * j; + let is_moe_plane = plane == Fp16RawPlaneId::Routing || plane == Fp16RawPlaneId::Offsets; + set_msg_mode(row, if is_moe_plane { MODE_AUX } else { MODE_BYTES }); + let bytes = &planes[plane.index()][byte_offset..byte_offset + NUM_UINT8]; + for (i, &b) in bytes.iter().enumerate() { + row.uint8_data[i] = F::from_canonical_u8(b); + } + // MoE order chains: the gates and their limb witnesses. + // `set_moe_chain` fails fast if the witness words are out of order. + let stream_word = + |i: usize| u32::from_le_bytes(planes[plane.index()][4 * i..4 * i + 4].try_into().unwrap()); + let live = byte_offset + NUM_UINT8 <= raw_lens[plane.index()]; + match plane { + // One flag per channel serves both sides: `ctl_base` already + // carries the B-plane key offset, keeping the key spaces disjoint. + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues if live => { + row.is_int8_message = F::ONE; + row.ctl_key_base = F::from_canonical_u64(ctl_base + (NUM_UINT8 * j) as u64); + } + Fp16RawPlaneId::AScales | Fp16RawPlaneId::BScales if live => { + row.is_scale_message = F::ONE; + row.ctl_key_base = F::from_canonical_u64(ctl_base + (NUM_UINT8 * j / 2) as u64); + } + Fp16RawPlaneId::Routing => { + let base = offset / 4 + 2 * j; + set_outer(row, self.routing_pin_at(base), self.routing_pin_at(base + 1)); + let s = self.moe.as_ref().expect("routing rows imply a MoE schedule"); + row.is_chain_data = F::ONE; + row.is_chain_strict = F::ONE; + let g = (16 * s.routing_block_base() + base) as u64; + let (intra, inter, bound_first, bound_second) = s.routing_chain_at(g); + if intra { + row.is_chain_intra = F::ONE; + set_moe_chain(&mut row.chain_intra_limbs, stream_word(base + 1), stream_word(base), 1); + } + if inter { + row.is_chain_inter = F::ONE; + set_moe_chain(&mut row.chain_inter_limbs, stream_word(base), stream_word(base - 1), 1); + } + if bound_first { + // The slice's last value is `word0`: the intra gate is + // off, so its limbs hold `m - 1 - word0` instead. + debug_assert!(!intra, "the intra gate must be idle on the bound row"); + row.is_bound_first = F::ONE; + row.word_pin_first = F::from_canonical_u32(s.m - 1); + set_moe_chain(&mut row.chain_intra_limbs, s.m - 1, stream_word(base), 0); + } + if bound_second { + // The slice's last value is `word1`: the next row's + // inter gate is off, so its limbs hold `m - 1 - word1`. + // Written after the fill loop, since that row may + // belong to the next compression. + row.is_bound_second = F::ONE; + row.word_pin_second = F::from_canonical_u32(s.m - 1); + let mut limbs = [F::ZERO; 2]; + set_moe_chain(&mut limbs, s.m - 1, stream_word(base + 1), 0); + bound_write = Some((r0 + j + 1, limbs)); + } + } + Fp16RawPlaneId::Offsets => { + let s = self.moe.as_ref().expect("offsets rows imply a MoE schedule"); + row.is_chain_data = F::ONE; + let p = offset / 4 + 2 * j; + for (slot, flag, pin) in [ + (p, &mut row.is_word_pin_first, &mut row.word_pin_first), + (p + 1, &mut row.is_word_pin_second, &mut row.word_pin_second), + ] { + if let Some(v) = s.offsets_pin_at(slot) { + assert_eq!( + u64::from(stream_word(slot)), + v, + "offsets word {slot} differs from its public pin" + ); + *flag = F::ONE; + *pin = F::from_canonical_u64(v); + } + } + let (intra, inter) = s.offsets_chain_at(p); + if intra { + row.is_chain_intra = F::ONE; + set_moe_chain(&mut row.chain_intra_limbs, stream_word(p + 1), stream_word(p), 0); + } + if inter { + row.is_chain_inter = F::ONE; + set_moe_chain(&mut row.chain_inter_limbs, stream_word(p), stream_word(p - 1), 0); + } + } + _ => {} // Chunk-padding row: channel filters stay off. + } + } + Fp16RawMessageSource::PlaneBytesSplit { + plane, + offset, + ctl_base, + skip, + take, + aux_idx, + } => { + if (skip..skip + take).contains(&j) { + // Opened dword: exactly a `PlaneBytes` row of the window. + let byte_offset = offset + NUM_UINT8 * (j - skip); + set_msg_mode(row, MODE_BYTES); + let bytes = &planes[plane.index()][byte_offset..byte_offset + NUM_UINT8]; + for (i, &b) in bytes.iter().enumerate() { + row.uint8_data[i] = F::from_canonical_u8(b); + } + let live = byte_offset + NUM_UINT8 <= raw_lens[plane.index()]; + match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues if live => { + row.is_int8_message = F::ONE; + row.ctl_key_base = F::from_canonical_u64(ctl_base + (NUM_UINT8 * (j - skip)) as u64); + } + Fp16RawPlaneId::AScales | Fp16RawPlaneId::BScales if live => { + row.is_scale_message = F::ONE; + row.ctl_key_base = F::from_canonical_u64(ctl_base + (NUM_UINT8 * (j - skip) / 2) as u64); + } + _ => {} + } + } else { + // Unopened-neighbor dword: an auxiliary-bytes row, filters off. + set_msg_mode(row, MODE_AUX); + for i in 0..NUM_UINT8 { + row.uint8_data[i] = F::from_canonical_u8(inputs.aux_msgs[aux_idx][NUM_UINT8 * j + i]); + } + } + } + Fp16RawMessageSource::AuxBytes { idx } => { + set_msg_mode(row, MODE_AUX); + for i in 0..NUM_UINT8 { + row.uint8_data[i] = F::from_canonical_u8(inputs.aux_msgs[idx][NUM_UINT8 * j + i]); + } + } + Fp16RawMessageSource::Parent { left, right } => { + let (child, local) = if j < 4 { (left, j) } else { (right, j - 4) }; + match child { + // An auxiliary sibling CV: its 32 bytes enter as 4 dword rows. + Fp16RawCvRef::Auxiliary(idx) => { + set_msg_mode(row, MODE_AUX); + for i in 0..NUM_UINT8 { + row.uint8_data[i] = F::from_canonical_u8(inputs.aux_cvs[idx][NUM_UINT8 * local + i]); + } + } + // An in-table child: one CV-window fetch on the half's last row. + Fp16RawCvRef::Instruction(_) if local == 3 => set_msg_mode(row, MODE_CV), + Fp16RawCvRef::Instruction(_) => {} + } + } + Fp16RawMessageSource::Lottery => { + // The 16 folded words as witness bytes (BYTES2-checked like any block); + // the XorFold CTL pins BLAKE3_MSG on row 0. + set_msg_mode(row, MODE_AUX); + for i in 0..NUM_UINT8 { + row.uint8_data[i] = F::from_canonical_u8(m[2 * j + i / 4].to_le_bytes()[i % 4]); + } + } + } + } + + // FP16 fork addition: per-compression message-word pins. Set IS_WORD_PIN_FIRST/SECOND and + // the class (a) WORD_PIN_FIRST/SECOND on every row so the general pin constraint fixes all + // 16 message words to the public constants (the noise keyed-XOF material blocks). pack_control + // (below) re-packs the two flag bits. + if let Some((_, pins)) = self.msg_pins.iter().find(|(idx, _)| *idx == c) { + for j in 0..ROWS_PER_COMPRESSION { + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + j].borrow_mut(); + row.is_word_pin_first = F::ONE; + row.word_pin_first = F::from_canonical_u32(pins[2 * j]); + row.is_word_pin_second = F::ONE; + row.word_pin_second = F::from_canonical_u32(pins[2 * j + 1]); + } + } + + // CV-routing fetches. + for (j, src) in instr.fetches() { + let src_row = ROWS_PER_COMPRESSION * src + (ROWS_PER_COMPRESSION - 1); + freq[src_row] += 1; + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + j].borrow_mut(); + row.is_cv_in = F::ONE; + row.cv_route_key_or_tweak = F::from_canonical_usize(src_row); + for i in 0..8 { + row.cv_in[i] = F::from_canonical_u32(cvs_out[src][i]); + // The mux (constraint 3) holds on every row: with IS_CV_IN set it forces + // BLAKE3_CV = CV_IN here too (harmless off IS_NEW_BLAKE rows). + row.blake3_cv[i] = F::from_canonical_u32(cvs_out[src][i]); + } + // Row-0 fetches are chunk chaining (mux path); rows 3/7 are parent window + // fetches — the fetched CV words ARE message words, so the sliding buffer + // below already carries them and the window constraint (5) closes. + } + + // Message words: row 0 holds the message; each next row is the permutation of the + // previous (permute^8 = id closes against the buffer at row 7). + let mut msg_j = m; + for j in 0..ROWS_PER_COMPRESSION { + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + j].borrow_mut(); + for i in 0..16 { + row.blake3_msg[i] = F::from_canonical_u32(msg_j[i]); + } + blake3_permute(&mut msg_j); + } + debug_assert_eq!(msg_j, m); + + // Round states (rows 0..6) and per-row CV_OUT, the deployed fill. + let mut state = init_state(&cvs_in[c], instr); + let mut msg_j = m; + for j in 0..ROWS_PER_COMPRESSION - 1 { + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + j].borrow_mut(); + write_state(&mut row.round[0], &state); + let row_input = state; + let states = compute_blake3_round(&mut state, &msg_j); + for (t, s) in states[..3].iter().enumerate() { + write_state(&mut row.round[t + 1], s); + } + for i in 0..8 { + // The unconditional CV_OUT = finalize-expression identity, on round rows. + let v = if i < 4 { + states[0][4 + i] ^ states[0][12 + i] + } else { + row_input[i] ^ row_input[8 + i] + }; + row.cv_out[i] = F::from_canonical_u32(v); + } + blake3_permute(&mut msg_j); + } + let row: &mut Fp16RawBlake3ColumnsView = rows[r0 + ROWS_PER_COMPRESSION - 1].borrow_mut(); + write_state(&mut row.round[0], &state); + for i in 0..8 { + row.cv_out[i] = F::from_canonical_u32(state[i] ^ state[8 + i]); + debug_assert_eq!(row.cv_out[i], F::from_canonical_u32(cvs_out[c][i])); + } + // FP16 fork addition: fill the egress limbs from the finalization CV. The constraint + // (gated by IS_EGRESS_CV) pins cv_egress_limbs[2w] + 2^16*cv_egress_limbs[2w+1] to + // cv_out[w]; off-egress compressions leave the (zero-initialized) limbs alone. + if instr.egress.is_some() { + for w in 0..8 { + let word = state[w] ^ state[8 + w]; + row.cv_egress_limbs[2 * w] = F::from_canonical_u32(word & 0xFFFF); + row.cv_egress_limbs[2 * w + 1] = F::from_canonical_u32(word >> 16); + } + } + } + + // ---- Padding rows: IS_NEW_BLAKE with the zero CV / zero tweak / zero message. ---- + for (r, row) in rows.iter_mut().enumerate().take(num_rows).skip(num_live) { + let row: &mut Fp16RawBlake3ColumnsView = row.borrow_mut(); + row.is_new_blake = F::ONE; + row.trace_row_index = F::from_canonical_usize(r); // Constraint 8 spans padding too. + for i in 0..4 { + row.round[0].row3[i] = F::from_canonical_u32(BLAKE3_IV[i]); + // The finalize expression on padding rows: [IV[0..4] ^ 0, 0 ^ 0]. + row.cv_out[i] = F::from_canonical_u32(BLAKE3_IV[i]); + } + } + + // ---- Sliding message buffer: a 16-word window over the concatenated message stream + // ---- (2 words appended per live row; padding rows append nothing and shift zeros + // ---- in). This makes the unconditional shift-by-2 (constraint 5a) hold everywhere, + // ---- and the CV-window pins (5b) are consistent automatically because the fetched + // ---- CVs are message words. Matches the deployed generator's row layout. + let mut buffer = [0u32; 16]; + for r in 0..num_rows { + buffer = shift_buffer(&buffer); + if r < num_live { + let (c, j) = (r / ROWS_PER_COMPRESSION, r % ROWS_PER_COMPRESSION); + buffer[14] = msgs[c][2 * j]; + buffer[15] = msgs[c][2 * j + 1]; + } + let row: &mut Fp16RawBlake3ColumnsView = rows[r].borrow_mut(); + for i in 0..16 { + row.blake3_msg_buffer[i] = F::from_canonical_u32(buffer[i]); + } + if r % ROWS_PER_COMPRESSION == ROWS_PER_COMPRESSION - 1 && r < num_live { + debug_assert_eq!(buffer, msgs[r / ROWS_PER_COMPRESSION], "buffer(7) must be the message"); + } + } + // Wrap fixup: the unconditional shift also binds the last -> first row pair, so rows + // 0..6 must carry the shifted-out residue of the last row's buffer in their prefixes + // (the residue never reaches any message; the deployed generator does the same). + let mut fwd = buffer; + for off in 1..=(ROWS_PER_COMPRESSION - 1) { + fwd = shift_buffer(&fwd); + let row: &mut Fp16RawBlake3ColumnsView = rows[(num_rows - 1 + off) % num_rows].borrow_mut(); + for i in 0..16 - 2 * off { + row.blake3_msg_buffer[i] = F::from_canonical_u32(fwd[i]); + } + } + + // ---- Write the deferred slice bound into the row after IS_BOUND_SECOND: its inter + // ---- limbs are idle, since that row's word pair starts past the slice. + if let Some((r, limbs)) = bound_write { + let row: &mut Fp16RawBlake3ColumnsView = rows[r].borrow_mut(); + assert_eq!( + row.is_chain_inter, + F::ZERO, + "the bound target row must have its inter gate down" + ); + row.chain_inter_limbs = limbs; + } + + // ---- Fill `chain_carry`: each row holds the last routing/offsets word before it. + // ---- Data rows overwrite it with their second word, all other rows copy it. The + // ---- first pass computes the end-of-trace value: the constraint is cyclic, so + // ---- row 0 checks against the last row. + let carry_after = |row: &Fp16RawBlake3ColumnsView, prev: F| -> F { + if row.is_chain_data == F::ONE { + F::from_canonical_u64((0..4).map(|i| row.uint8_data[4 + i].to_canonical_u64() << (8 * i)).sum()) + } else { + prev + } + }; + let mut carry = F::ZERO; + for row in &rows { + carry = carry_after(row.borrow(), carry); + } + for row in rows.iter_mut() { + let row: &mut Fp16RawBlake3ColumnsView = row.borrow_mut(); + row.chain_carry = carry; + carry = carry_after(row, carry); + } + + // ---- Postprocess rows whose next row starts a compression (real finalization rows, + // ---- padding rows, and the cyclic wrap): fill STATE1..3 so the unconditional + // ---- add2/add3 constraints hold and STATE1 carries the finalize bit decompositions. + for r in 0..num_rows { + let next = (r + 1) % num_rows; + { + let next_row: &Fp16RawBlake3ColumnsView = rows[next].borrow(); + if next_row.is_new_blake != F::ONE { + continue; + } + } + let (nr1, nr3, nr4) = { + let next_row: &Fp16RawBlake3ColumnsView = rows[next].borrow(); + ( + read_words(&next_row.round[0].row1), + read_words(&next_row.round[0].row3), + read_bits(&next_row.round[0].row4), + ) + }; + let row: &mut Fp16RawBlake3ColumnsView = rows[r].borrow_mut(); + let msg: [u32; 16] = core::array::from_fn(|i| row.blake3_msg[i].to_canonical_u64() as u32); + let r1 = read_words(&row.round[0].row1); + let r2 = read_bits(&row.round[0].row2); + let r3 = read_words(&row.round[0].row3); + + // STATE1: row2/row4 repurposed as the finalize decompositions of row1/row3. + let s1r1: [u32; 4] = core::array::from_fn(|i| r1[i].wrapping_add(r2[i]).wrapping_add(msg[2 * i])); + let s1r3: [u32; 4] = core::array::from_fn(|i| r3[i].wrapping_add(r3[i])); + write_words(&mut row.round[1].row1, &s1r1); + write_bits(&mut row.round[1].row2, &r1); + write_words(&mut row.round[1].row3, &s1r3); + write_bits(&mut row.round[1].row4, &r3); + + // STATE2: bit halves zero; word halves from the unconditional adds. + let s2r1: [u32; 4] = core::array::from_fn(|i| s1r1[i].wrapping_add(r1[i]).wrapping_add(msg[2 * i + 1])); + write_words(&mut row.round[2].row1, &s2r1); + write_bits(&mut row.round[2].row2, &[0; 4]); + write_words(&mut row.round[2].row3, &s1r3); + write_bits(&mut row.round[2].row4, &[0; 4]); + + // STATE3: solved backwards from the next row's input state (diagonal adds). + let s3r1: [u32; 4] = core::array::from_fn(|i| s2r1[i].wrapping_add(msg[8 + 2 * i])); + let (mut s3r2, mut s3r3, mut s3r4) = ([0u32; 4], [0u32; 4], [0u32; 4]); + for i in 0..4 { + let (b, c, d) = ((i + 1) % 4, (i + 2) % 4, (i + 3) % 4); + s3r3[c] = nr3[c].wrapping_sub(nr4[d]); + s3r4[d] = s3r3[c].wrapping_sub(s1r3[c]); + s3r2[b] = nr1[i].wrapping_sub(s3r1[i]).wrapping_sub(msg[8 + 2 * i + 1]); + } + write_words(&mut row.round[3].row1, &s3r1); + write_bits(&mut row.round[3].row2, &s3r2); + write_words(&mut row.round[3].row3, &s3r3); + write_bits(&mut row.round[3].row4, &s3r4); + } + + // ---- CV-routing multiplicities and the ROW_FLAGS_PACKED packing. ---- + for (r, row) in rows.iter_mut().enumerate() { + let row: &mut Fp16RawBlake3ColumnsView = row.borrow_mut(); + row.cv_out_freq = F::from_canonical_u64(freq[r]); + row.row_flags_packed = pack_control(row); + } + + // ---- Public inputs. ---- + let bound_cv = |bind: Fp16RawPublicBinding| -> [u32; 8] { + instrs + .iter() + .position(|i| i.bind == Some(bind)) + .map(|i| cvs_out[i]) + .unwrap_or([0; 8]) + }; + let mut pis = [F::ZERO; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS]; + let mut set = |base: usize, words: &[u32; 8]| { + for i in 0..8 { + pis[base + i] = F::from_canonical_u32(words[i]); + } + }; + set(PI_KEY_A, &inputs.key_a); + set(PI_KEY_B, &inputs.key_b); + set(PI_JACKPOT_KEY, &inputs.jackpot_key); + set(PI_HASH_A, &bound_cv(Fp16RawPublicBinding::HashA)); + set(PI_HASH_B, &bound_cv(Fp16RawPublicBinding::HashB)); + set(PI_HASH_ROUTING, &bound_cv(Fp16RawPublicBinding::HashRouting)); + set(PI_HASH_OFFSETS, &bound_cv(Fp16RawPublicBinding::HashOffsets)); + set(PI_HASH_JACKPOT, &bound_cv(Fp16RawPublicBinding::HashJackpot)); + + (rows, pis) + } + + /// The class (a) ("known") column values — the leading + /// [`NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS`](super::columns::NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS) trace columns in + /// their `columns.rs` order — recomputed from the compiled program and the public + /// byte-stream geometry alone (no witness bytes). Bit-exact with + /// [`Self::generate_trace`]'s fill (asserted by the stark's tests and by + /// `super::super::consistency`): the batch verifier recomputes exactly this and checks the + /// trace-commitment openings against it (`starky`'s `BatchKnownColumns`), so the schedule + /// wiring is consensus data even though the columns are committed with the trace. + pub fn known_values(&self, inputs: &Fp16RawBlake3KnownInputs) -> Vec> { + self.validate(); + let num_live = self.num_live_rows(); + let num_rows = self.num_rows(); + // The routing/offsets planes have no liveness length: their rows' class (a) data + // (selectors, pins, chain gates) is driven by the MoE schedule, never by a byte count. + let raw_lens: [usize; NUM_PLANES] = [ + inputs.a_values_len, + inputs.a_scales_len, + inputs.b_values_len, + inputs.b_scales_len, + 0, + 0, + ]; + + // `ROW_FLAGS_PACKED` bit packing (the `pack_control` weights). + const MODE_BYTES_BITS: u64 = 1 << 11; + const MODE_AUX_BITS: u64 = (1 << 12) | (1 << 13); + const MODE_CV_BITS: u64 = 1 << 13; + + let mut row_flags_packed = vec![0u64; num_rows]; + let mut ctl_key_base = vec![F::ZERO; num_rows]; + let mut is_int8_message = vec![F::ZERO; num_rows]; + let mut is_scale_message = vec![F::ZERO; num_rows]; + let mut cv_route_key_or_tweak = vec![F::ZERO; num_rows]; + let mut moe_outer_indices_packed = vec![F::ZERO; num_rows]; + let mut word_pin_first = vec![F::ZERO; num_rows]; + let mut word_pin_second = vec![F::ZERO; num_rows]; + + for (c, instr) in self.instructions.iter().enumerate() { + let r0 = ROWS_PER_COMPRESSION * c; + for j in 0..ROWS_PER_COMPRESSION { + let r = r0 + j; + let mut bits = 0u64; + if j == 0 { + bits |= 1 << 9; // IS_NEW_BLAKE + match instr.cv { + Fp16RawCvSource::KeyA => bits |= 1 << 0, + Fp16RawCvSource::KeyB => bits |= 1 << 1, + Fp16RawCvSource::JackpotKey => bits |= 1 << 2, + Fp16RawCvSource::Iv => bits |= 1 << 3, + Fp16RawCvSource::Chain(_) => {} // the row-0 fetch below carries IS_CV_IN instead + } + } + if j == 1 { + cv_route_key_or_tweak[r] = F::from_canonical_u64(instr.tweak_packed()); + } + if j == ROWS_PER_COMPRESSION - 1 { + bits |= 1 << 10; // IS_LAST_ROUND + match instr.bind { + Some(Fp16RawPublicBinding::HashA) => bits |= 1 << 4, + Some(Fp16RawPublicBinding::HashB) => bits |= 1 << 5, + Some(Fp16RawPublicBinding::HashRouting) => bits |= 1 << 6, + Some(Fp16RawPublicBinding::HashOffsets) => bits |= 1 << 16, + _ => {} + } + // FP16 fork addition: IS_EGRESS_CV (bit 25) and the egress key on CTL_KEY_BASE. + // Both are class (a) (recomputed by the batch verifier); the egress key reuses + // CTL_KEY_BASE, which is 0 on finalization rows of non-egressing compressions. + if let Some(base) = instr.egress { + bits |= 1 << 25; + ctl_key_base[r] = F::from_canonical_u64(base); + } + } + if instr.bind == Some(Fp16RawPublicBinding::HashJackpot) { + bits |= 1 << 7; // all 8 rows (the lottery CTL filter, see columns.rs) + } + + match instr.msg { + Fp16RawMessageSource::PlaneBytes { plane, offset, ctl_base } => { + bits |= if plane == Fp16RawPlaneId::Routing || plane == Fp16RawPlaneId::Offsets { + MODE_AUX_BITS + } else { + MODE_BYTES_BITS + }; + let byte_offset = offset + NUM_UINT8 * j; + let live = byte_offset + NUM_UINT8 <= raw_lens[plane.index()]; + match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues if live => { + is_int8_message[r] = F::ONE; + ctl_key_base[r] = F::from_canonical_u64(ctl_base + (NUM_UINT8 * j) as u64); + } + Fp16RawPlaneId::AScales | Fp16RawPlaneId::BScales if live => { + is_scale_message[r] = F::ONE; + ctl_key_base[r] = F::from_canonical_u64(ctl_base + (NUM_UINT8 * j / 2) as u64); + } + Fp16RawPlaneId::Routing => { + // Selective pinning, exactly the deployed chip: a selector + // fires only where this row ingests a sampled entry, and the + // packed word carries only the pinned public values. + let base = offset / 4 + 2 * j; + let (w0, w1) = (self.routing_pin_at(base), self.routing_pin_at(base + 1)); + if w0.is_some() { + bits |= 1 << 14; // IS_FIRST_OUTER + } + if w1.is_some() { + bits |= 1 << 15; // IS_SECOND_OUTER + } + moe_outer_indices_packed[r] = F::from_canonical_u64(w0.unwrap_or(0) + (w1.unwrap_or(0) << 26)); + let s = self.moe.as_ref().expect("routing rows imply a MoE schedule"); + bits |= 1 << 21; // IS_CHAIN_STRICT + bits |= 1 << 24; // IS_CHAIN_DATA + let g = (16 * s.routing_block_base() + base) as u64; + let (intra, inter, bound_first, bound_second) = s.routing_chain_at(g); + bits |= u64::from(intra) << 19; + bits |= u64::from(inter) << 20; + bits |= u64::from(bound_first) << 22; + bits |= u64::from(bound_second) << 23; + if bound_first { + word_pin_first[r] = F::from_canonical_u32(s.m - 1); + } + if bound_second { + word_pin_second[r] = F::from_canonical_u32(s.m - 1); + } + } + Fp16RawPlaneId::Offsets => { + let s = self.moe.as_ref().expect("offsets rows imply a MoE schedule"); + bits |= 1 << 24; // IS_CHAIN_DATA + let p = offset / 4 + 2 * j; + if let Some(v) = s.offsets_pin_at(p) { + bits |= 1 << 17; // IS_WORD_PIN_FIRST + word_pin_first[r] = F::from_canonical_u64(v); + } + if let Some(v) = s.offsets_pin_at(p + 1) { + bits |= 1 << 18; // IS_WORD_PIN_SECOND + word_pin_second[r] = F::from_canonical_u64(v); + } + let (intra, inter) = s.offsets_chain_at(p); + bits |= u64::from(intra) << 19; + bits |= u64::from(inter) << 20; + } + _ => {} // Chunk-padding row: channel filters stay off. + } + } + Fp16RawMessageSource::PlaneBytesSplit { + plane, + ctl_base, + offset, + skip, + take, + .. + } => { + if (skip..skip + take).contains(&j) { + bits |= MODE_BYTES_BITS; + let byte_offset = offset + NUM_UINT8 * (j - skip); + let live = byte_offset + NUM_UINT8 <= raw_lens[plane.index()]; + match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues if live => { + is_int8_message[r] = F::ONE; + ctl_key_base[r] = F::from_canonical_u64(ctl_base + (NUM_UINT8 * (j - skip)) as u64); + } + Fp16RawPlaneId::AScales | Fp16RawPlaneId::BScales if live => { + is_scale_message[r] = F::ONE; + ctl_key_base[r] = F::from_canonical_u64(ctl_base + (NUM_UINT8 * (j - skip) / 2) as u64); + } + _ => {} + } + } else { + bits |= MODE_AUX_BITS; + } + } + Fp16RawMessageSource::AuxBytes { .. } | Fp16RawMessageSource::Lottery => bits |= MODE_AUX_BITS, + Fp16RawMessageSource::Parent { left, right } => { + let child = if j < ROWS_PER_COMPRESSION / 2 { left } else { right }; + match child { + Fp16RawCvRef::Auxiliary(_) => bits |= MODE_AUX_BITS, + Fp16RawCvRef::Instruction(_) if j % 4 == 3 => bits |= MODE_CV_BITS, + Fp16RawCvRef::Instruction(_) => {} + } + } + } + row_flags_packed[r] = bits; + } + + // CV-routing fetches: IS_CV_IN plus the source-row pointer (rows 0/3/7 — never the + // tweak row 1). + for (j, src) in instr.fetches() { + row_flags_packed[r0 + j] |= 1 << 8; + cv_route_key_or_tweak[r0 + j] = F::from_canonical_usize(ROWS_PER_COMPRESSION * src + (ROWS_PER_COMPRESSION - 1)); + } + } + + // FP16 fork addition: per-compression message-word pins (class a). Set IS_WORD_PIN_FIRST (bit + // 17) / IS_WORD_PIN_SECOND (bit 18) and the pinned words on every row of each listed + // compression, bit-exact with the `generate_trace` population above. + for (c, pins) in &self.msg_pins { + let r0 = ROWS_PER_COMPRESSION * c; + for j in 0..ROWS_PER_COMPRESSION { + let r = r0 + j; + row_flags_packed[r] |= (1 << 17) | (1 << 18); + word_pin_first[r] = F::from_canonical_u32(pins[2 * j]); + word_pin_second[r] = F::from_canonical_u32(pins[2 * j + 1]); + } + } + + // Padding rows carry IS_NEW_BLAKE alone. + for bits in row_flags_packed.iter_mut().take(num_rows).skip(num_live) { + *bits = 1 << 9; + } + + let row_flags_packed: Vec = row_flags_packed.into_iter().map(F::from_canonical_u64).collect(); + [ + row_flags_packed, + ctl_key_base, + is_int8_message, + is_scale_message, + cv_route_key_or_tweak, + moe_outer_indices_packed, + word_pin_first, + word_pin_second, + ] + .into_iter() + .map(PolynomialValues::new) + .collect() + } +} + +/// Witness inputs of one job's hashing trace: the committed plane bytes (opened strips), the +/// auxiliary Merkle material (unopened blocks / sibling CVs), the lottery words and the keys. +#[derive(Clone, Debug)] +pub struct Fp16RawBlake3TraceInputs<'a> { + /// A-side int8 values plane, raw bytes (the sampled strip rows, row-major). + pub a_values: &'a [u8], + /// A-side bf16 scales plane, raw bytes (LE bf16 code per 8-element block). + pub a_scales: &'a [u8], + /// B-side int8 values plane, raw bytes. + pub b_values: &'a [u8], + /// B-side bf16 scales plane, raw bytes. + pub b_scales: &'a [u8], + /// The opened routing hotspot blocks as u32 words, 16 per block, hotspot order. **Witness + /// data**: only the words at [`Fp16RawBlake3Program::routing_pins`] positions are publicly + /// pinned (and must equal the pinned values); the rest are free neighbors, bound only by + /// the hash chain to `HASH_ROUTING`. + pub routing_words: &'a [u32], + /// The full offsets list `O` as u32 words (chunk padding appended by the trace generator). + /// **Witness data** bound to `HASH_OFFSETS`; the [`MoeSchedule`] scalars are pinned + /// in-circuit at their stream positions. Empty for dense jobs. + pub offsets_words: &'a [u32], + /// Auxiliary 64-byte messages (unopened blocks, plus the full block of every split leaf), + /// indexed by [`Fp16RawMessageSource::AuxBytes`] / [`Fp16RawMessageSource::PlaneBytesSplit`]. + pub aux_msgs: &'a [[u8; 64]], + /// Auxiliary sibling CVs (unopened subtree roots), indexed by [`Fp16RawCvRef::Auxiliary`]. + pub aux_cvs: &'a [[u8; 32]], + /// The 16 folded lottery words (XorFoldStark's `FOLD_OUT`s). + pub lottery_words: [u32; 16], + /// `KEY_A` as 8 LE u32 limbs of the 32-byte A-side tree key. + pub key_a: [u32; 8], + /// `KEY_B` limbs (the B-side tree key). + pub key_b: [u32; 8], + /// `JACKPOT_KEY` limbs (the lottery key). + pub jackpot_key: [u32; 8], + /// Merkle leaf sizes from the job `HashId`s (routing is 1024 when dense). + pub a_hash_id: HashId, + pub b_hash_id: HashId, + pub routing_hash_id: HashId, + pub offsets_hash_id: HashId, +} + +impl Fp16RawBlake3TraceInputs<'_> { + /// The public projection of these inputs (what [`Fp16RawBlake3Program::known_values`] runs on): + /// raw plane lengths only — no witness bytes. The MoE pin schedule is part of the + /// [`Fp16RawBlake3Program`] itself ([`Fp16RawBlake3Program::routing_pins`]), not of these inputs. + pub fn known_inputs(&self) -> Fp16RawBlake3KnownInputs { + Fp16RawBlake3KnownInputs { + a_values_len: self.a_values.len(), + a_scales_len: self.a_scales.len(), + b_values_len: self.b_values.len(), + b_scales_len: self.b_scales.len(), + } + } +} + +/// The public inputs of [`Fp16RawBlake3Program::known_values`]: the raw (pre-chunk-padding) plane +/// byte lengths — they gate which message rows are *live* for the CTL channels. All +/// verifier-side data; the MoE outer-index pins live on the [`Fp16RawBlake3Program`] itself. +#[derive(Clone, Copy, Debug)] +pub struct Fp16RawBlake3KnownInputs { + /// `Fp16RawBlake3TraceInputs::a_values.len()` (raw A-side int8 plane bytes). + pub a_values_len: usize, + /// Raw A-side scales plane byte length. + pub a_scales_len: usize, + /// Raw B-side values plane byte length. + pub b_values_len: usize, + /// Raw B-side scales plane byte length. + pub b_scales_len: usize, +} + +/// `IS_MSG_BITS` encodings (deployed `encode_is_msg_bits`): committed plane bytes, auxiliary / +/// routing / lottery bytes, the parent CV window. `010` (deployed jackpot) is outlawed. +const MODE_BYTES: [bool; 3] = [true, false, false]; +const MODE_AUX: [bool; 3] = [false, true, true]; +const MODE_CV: [bool; 3] = [false, false, true]; + +fn set_msg_mode(row: &mut Fp16RawBlake3ColumnsView, mode: [bool; 3]) { + for i in 0..3 { + row.is_msg_bits[i] = F::from_bool(mode[i]); + } +} + +/// The deployed chip's selective outer-index fill on one routing row: each of the two +/// ingested u32 slots is pinned (`Some(outer)`) only where the schedule sampled it — the +/// selector fires and the 13-bit limbs carry the public value — and stays dark otherwise +/// (selector off, limbs zero; the word is free witness under the hash chain). The packed +/// class (a) word carries only pinned values, matching `known_values` bit for bit. +fn set_outer(row: &mut Fp16RawBlake3ColumnsView, w0: Option, w1: Option) { + if let Some(w0) = w0 { + assert!(w0 < 1 << 26, "outer-index words must fit 26 bits"); + row.is_first_outer = F::ONE; + row.outer_index_first = [F::from_canonical_u64(w0 & 0x1FFF), F::from_canonical_u64(w0 >> 13)]; + } + if let Some(w1) = w1 { + assert!(w1 < 1 << 26, "outer-index words must fit 26 bits"); + row.is_second_outer = F::ONE; + row.outer_index_second = [F::from_canonical_u64(w1 & 0x1FFF), F::from_canonical_u64(w1 >> 13)]; + } + row.moe_outer_indices_packed = F::from_canonical_u64(w0.unwrap_or(0) + (w1.unwrap_or(0) << 26)); +} + +/// Writes `hi - lo - strict` as the 16-bit limb pair of a gated order chain (the AIR proves +/// `lo + strict <= hi` by exhibiting the difference in `[0, 2^32)`). +fn set_moe_chain(limbs: &mut [F; 2], hi: u32, lo: u32, strict: u32) { + let d = u64::from(hi) + .checked_sub(u64::from(lo) + u64::from(strict)) + .expect("MoE order violated in the trace inputs"); + limbs[0] = F::from_canonical_u64(d & 0xFFFF); + limbs[1] = F::from_canonical_u64(d >> 16); +} + +/// Packs the [`NUM_UNPACK_FLAGS`] unpack flags (already written on the row) into +/// `ROW_FLAGS_PACKED`, bit `j` = flag `j` in the [`super::columns::unpack_flag_cols`] order. +fn pack_control(row: &Fp16RawBlake3ColumnsView) -> F { + let flags = [ + row.is_use_key_a, + row.is_use_key_b, + row.is_use_jackpot_key, + row.is_use_iv, + row.is_bind_hash_a, + row.is_bind_hash_b, + row.is_bind_routing_hash, + row.is_bind_jackpot_hash, + row.is_cv_in, + row.is_new_blake, + row.is_last_round, + row.is_msg_bits[0], + row.is_msg_bits[1], + row.is_msg_bits[2], + row.is_first_outer, + row.is_second_outer, + row.is_bind_offsets_hash, + row.is_word_pin_first, + row.is_word_pin_second, + row.is_chain_intra, + row.is_chain_inter, + row.is_chain_strict, + row.is_bound_first, + row.is_bound_second, + row.is_chain_data, + row.is_egress_cv, // FP16 fork addition (bit 25). + ]; + debug_assert_eq!(flags.len(), NUM_UNPACK_FLAGS); + let mut packed = 0u64; + for (j, f) in flags.into_iter().enumerate() { + debug_assert!(f == F::ZERO || f == F::ONE); + packed |= ((f == F::ONE) as u64) << j; + } + F::from_canonical_u64(packed) +} + +/// The compression's initial 16-word state: `cv | IV[0..4] | counter | block_len | flags`. +fn init_state(cv: &[u32; 8], instr: &Fp16RawBlake3Instruction) -> [u32; 16] { + core::array::from_fn(|i| match i { + 0..=7 => cv[i], + 8..=11 => BLAKE3_IV[i - 8], + 12 => instr.counter as u32, + 13 => (instr.counter >> 32) as u32, + 14 => instr.block_len, + _ => instr.flags, + }) +} + +/// `next_buffer[0..14] = buffer[2..16]`, tail zeroed (the AIR's unconditional shift). +fn shift_buffer(buffer: &[u32; 16]) -> [u32; 16] { + core::array::from_fn(|i| if i < 14 { buffer[i + 2] } else { 0 }) +} + +/// One half quarter-round (the native mirror of the AIR's `half_g`). +fn half_quarter_round(mut a: u32, mut b: u32, mut c: u32, mut d: u32, m: u32, second_half: bool) -> (u32, u32, u32, u32) { + let (rot_1, rot_2) = if second_half { (8, 7) } else { (16, 12) }; + a = a.wrapping_add(b).wrapping_add(m); + d = (d ^ a).rotate_right(rot_1); + c = c.wrapping_add(d); + b = (b ^ c).rotate_right(rot_2); + (a, b, c, d) +} + +/// One full BLAKE3 round; returns the 4 intermediate states (the 4th is the next row's input). +fn compute_blake3_round(state: &mut [u32; 16], msg: &[u32; 16]) -> [[u32; 16]; 4] { + let mut states = [[0u32; 16]; 4]; + for i in 0..4 { + let (a, b, c, d) = half_quarter_round(state[i], state[4 + i], state[8 + i], state[12 + i], msg[2 * i], false); + (state[i], state[4 + i], state[8 + i], state[12 + i]) = (a, b, c, d); + } + states[0] = *state; + for i in 0..4 { + let (a, b, c, d) = half_quarter_round(state[i], state[4 + i], state[8 + i], state[12 + i], msg[2 * i + 1], true); + (state[i], state[4 + i], state[8 + i], state[12 + i]) = (a, b, c, d); + } + states[1] = *state; + for i in 0..4 { + let (b, c, d) = (4 + (i + 1) % 4, 8 + (i + 2) % 4, 12 + (i + 3) % 4); + let (na, nb, nc, nd) = half_quarter_round(state[i], state[b], state[c], state[d], msg[8 + 2 * i], false); + (state[i], state[b], state[c], state[d]) = (na, nb, nc, nd); + } + states[2] = *state; + for i in 0..4 { + let (b, c, d) = (4 + (i + 1) % 4, 8 + (i + 2) % 4, 12 + (i + 3) % 4); + let (na, nb, nc, nd) = half_quarter_round(state[i], state[b], state[c], state[d], msg[8 + 2 * i + 1], true); + (state[i], state[b], state[c], state[d]) = (na, nb, nc, nd); + } + states[3] = *state; + states +} + +/// The 16-word state after the 7 rounds (the finalization row's input; the CV output is +/// `state[i] ^ state[8 + i]`). +fn native_compress_state(cv: &[u32; 8], m: &[u32; 16], counter: u64, block_len: u32, flags: u32) -> [u32; 16] { + let mut state: [u32; 16] = core::array::from_fn(|i| match i { + 0..=7 => cv[i], + 8..=11 => BLAKE3_IV[i - 8], + 12 => counter as u32, + 13 => (counter >> 32) as u32, + 14 => block_len, + _ => flags, + }); + let mut msg = *m; + for _ in 0..7 { + compute_blake3_round(&mut state, &msg); + blake3_permute(&mut msg); + } + state +} + +fn write_state(dst: &mut Fp16RawBlake3StateCols, state: &[u32; 16]) { + write_words(&mut dst.row1, &core::array::from_fn(|i| state[i])); + write_bits(&mut dst.row2, &core::array::from_fn(|i| state[4 + i])); + write_words(&mut dst.row3, &core::array::from_fn(|i| state[8 + i])); + write_bits(&mut dst.row4, &core::array::from_fn(|i| state[12 + i])); +} + +fn write_words(dst: &mut [F; 4], words: &[u32; 4]) { + for i in 0..4 { + dst[i] = F::from_canonical_u32(words[i]); + } +} + +fn write_bits(dst: &mut [[F; 32]; 4], words: &[u32; 4]) { + for i in 0..4 { + for b in 0..32 { + dst[i][b] = F::from_canonical_u32((words[i] >> b) & 1); + } + } +} + +fn read_words(src: &[F; 4]) -> [u32; 4] { + core::array::from_fn(|i| src[i].to_canonical_u64() as u32) +} + +fn read_bits(src: &[[F; 32]; 4]) -> [u32; 4] { + core::array::from_fn(|i| (0..32).fold(0u32, |acc, b| acc | (((src[i][b] == F::ONE) as u32) << b))) +} + +// ================================================================================================== +// Constraints, written once against the generic `Evaluator` +// ================================================================================================== + +/// Evaluates every arithmetic constraint of Fp16RawBlake3Stark. The CV-routing lookup is +/// declared in [`Fp16RawBlake3Stark::lookups`] and evaluated by the framework; the BYTES2/RC16 +/// instances and the CTL halves are declared in `super::ctl` and assembled by the batch +/// driver (module docs). +pub(crate) fn eval_blake3_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_FP16_RAW_BLAKE3_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &Fp16RawBlake3ColumnsView = lv.borrow(); + let nv: &[V; NUM_FP16_RAW_BLAKE3_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let nv: &Fp16RawBlake3ColumnsView = nv.borrow(); + let pis = vars.get_public_inputs(); + let public8 = |eval: &mut E, base: usize| -> [V; 8] { core::array::from_fn(|i| eval.scalar(pis[base + i])) }; + let key_a = public8(eval, PI_KEY_A); + let key_b = public8(eval, PI_KEY_B); + let jackpot_key = public8(eval, PI_JACKPOT_KEY); + let hash_a = public8(eval, PI_HASH_A); + let hash_b = public8(eval, PI_HASH_B); + let hash_routing = public8(eval, PI_HASH_ROUTING); + let hash_offsets = public8(eval, PI_HASH_OFFSETS); + let hash_jackpot = public8(eval, PI_HASH_JACKPOT); + + let one = eval.i32(1); + let two = eval.i32(2); + let c256 = eval.i32(256); + + // ---- 2. Unpack/repack: every flag boolean, weighted sum = ROW_FLAGS_PACKED. ---- + let flags = [ + lv.is_use_key_a, + lv.is_use_key_b, + lv.is_use_jackpot_key, + lv.is_use_iv, + lv.is_bind_hash_a, + lv.is_bind_hash_b, + lv.is_bind_routing_hash, + lv.is_bind_jackpot_hash, + lv.is_cv_in, + lv.is_new_blake, + lv.is_last_round, + lv.is_msg_bits[0], + lv.is_msg_bits[1], + lv.is_msg_bits[2], + lv.is_first_outer, + lv.is_second_outer, + lv.is_bind_offsets_hash, + lv.is_word_pin_first, + lv.is_word_pin_second, + lv.is_chain_intra, + lv.is_chain_inter, + lv.is_chain_strict, + lv.is_bound_first, + lv.is_bound_second, + lv.is_chain_data, + lv.is_egress_cv, // FP16 fork addition (bit 25). + ]; + debug_assert_eq!(flags.len(), NUM_UNPACK_FLAGS); + for f in flags { + eval.constraint_bool(f); + } + let repacked = eval.polyval(&flags, two); + eval.constraint_eq(repacked, lv.row_flags_packed); + // With every flag boolean, the unpack is the unique binary decomposition of ROW_FLAGS_PACKED — + // and ROW_FLAGS_PACKED is class (a), re-derived by the batch verifier and checked against the + // trace openings. The flags are therefore the *program's* bits, which carries two facts the + // deployed chip reads off its preprocessed schedule and this AIR needs but does not state: + // the five CV-source selectors are one-hot-or-zero (a two-hot row would open the mux to CV + // forgeries), and row 0 starts a compression (the plain, cyclically wrapping + // buffer/message/round constraints rely on it). + + // ---- 3. CV-source one-hot mux (the deployed mux + the per-side key sources + IV). ---- + for i in 0..8 { + let iv = eval.u64(u64::from(BLAKE3_IV[i])); + let mut acc = eval.mul(lv.is_use_key_a, key_a[i]); + acc = eval.mad(lv.is_use_key_b, key_b[i], acc); + acc = eval.mad(lv.is_use_jackpot_key, jackpot_key[i], acc); + acc = eval.mad(lv.is_use_iv, iv, acc); + acc = eval.mad(lv.is_cv_in, lv.cv_in[i], acc); + eval.constraint_eq(lv.blake3_cv[i], acc); + } + + // ---- 4. Public bindings: the side digests, routing/offsets hashes, the lottery output. ---- + for (flag, target) in [ + (lv.is_bind_hash_a, hash_a), + (lv.is_bind_hash_b, hash_b), + (lv.is_bind_routing_hash, hash_routing), + (lv.is_bind_offsets_hash, hash_offsets), + ] { + for i in 0..8 { + let diff = eval.sub(lv.cv_out[i], target[i]); + let c = eval.mul(flag, diff); + eval.constraint(c); + } + } + for i in 0..8 { + // IS_BIND_JACKPOT_HASH spans all 8 lottery rows (the XorFold CTL filter needs it on the + // load row), so the binding is anchored at the finalization row explicitly (degree 3). + let diff = eval.sub(lv.cv_out[i], hash_jackpot[i]); + let gate = eval.mul(lv.is_bind_jackpot_hash, lv.is_last_round); + let c = eval.mul(gate, diff); + eval.constraint(c); + } + + // ---- 4b. FP16 fork addition: output-egress CV limbs. On IS_EGRESS_CV rows (a finalization + // ---- row the program flagged), each output word is pinned to its two 16-bit egress limbs, + // ---- cv_out[w] = CV_EGRESS_LIMBS[2w] + 2^16 * CV_EGRESS_LIMBS[2w+1]. The limbs are RC16-bound + // ---- < 2^16 on every row (`super::ctl::blake3_lut_lookups`), so the recomposition (< 2^32, + // ---- no field wrap) is unique and the egress channel exports cv_out faithfully. Degree 2 + // ---- (flag * linear). Off-egress rows IS_EGRESS_CV = 0, so nothing is pinned and the limbs + // ---- stay at their zero (in-domain) witness — the shared engine is unchanged when it is 0. + let two16 = eval.u64(1 << 16); + for w in 0..8 { + let hi = eval.mul(two16, lv.cv_egress_limbs[2 * w + 1]); + let recompose = eval.add(lv.cv_egress_limbs[2 * w], hi); + let diff = eval.sub(lv.cv_out[w], recompose); + let c = eval.mul(lv.is_egress_cv, diff); + eval.constraint(c); + } + + // ---- 5. Message ingestion (deployed modes; `decode_is_msg_bits` is the deployed + // ---- decoder). ---- + // The unconditional shift-by-2 (plain, incl. the wrap — the generator's wrap fixup keeps + // the wrapped instance honest; it never reaches a message). + for i in 0..14 { + eval.constraint_eq(nv.blake3_msg_buffer[i], lv.blake3_msg_buffer[i + 2]); + } + let (is_msg_jackpot, is_msg_uint8_data, is_msg_cv) = decode_is_msg_bits(eval, one, lv.is_msg_bits); + // The deployed jackpot whole-buffer mode (010) is outlawed: the lottery message arrives as + // auxiliary bytes and is pinned by the XorFold CTL against BLAKE3_MSG on the load row. + eval.constraint(is_msg_jackpot); + // Byte-ingestion rows (plane or auxiliary bytes) load the packed byte pairs into the tail. + let word0 = eval.polyval(&lv.uint8_data[0..4], c256); + let word1 = eval.polyval(&lv.uint8_data[4..8], c256); + eval.constraint_eq_if(is_msg_uint8_data, lv.blake3_msg_buffer[14], word0); + eval.constraint_eq_if(is_msg_uint8_data, lv.blake3_msg_buffer[15], word1); + // CV-window rows (parent child fetches, rows 3 and 7): the fetched CV fills words + // 0..8 / 8..16 through the shift. + for i in 0..8 { + eval.constraint_eq_if(is_msg_cv, lv.blake3_msg_buffer[8 + i], lv.cv_in[i]); + } + // Round-to-round message permutation, and the row-7 closure against the buffer + // (permute^8 = id, so buffer(7) is the message the compression consumed). + let mut permuted = lv.blake3_msg; + blake3_permute(&mut permuted); + let next_same_blake = eval.sub(one, nv.is_new_blake); + for i in 0..16 { + eval.constraint_eq_if(next_same_blake, permuted[i], nv.blake3_msg[i]); + eval.constraint_eq_if(lv.is_last_round, permuted[i], lv.blake3_msg_buffer[i]); + } + + // ---- 1. Round block (the deployed chip's constraint set, re-expressed on this layout). -- + let states = [&lv.round[0], &lv.round[1], &lv.round[2], &lv.round[3], &nv.round[0]]; + verify_round(eval, &states, &lv.blake3_msg, next_same_blake); + let blake3_output = finalize_blake(eval, states[0], states[1], nv.is_new_blake); + for i in 0..8 { + eval.constraint_eq(lv.cv_out[i], blake3_output[i]); + } + // The packed tweak rides the *next* row's CV_ROUTE_KEY_OR_TWEAK (row 1 of the compression). + verify_init_state(eval, states[0], lv.is_new_blake, &lv.blake3_cv, nv.cv_route_key_or_tweak); + + // ---- 6. MoE outer indices (deployed packing layout, deployed selective pinning). ---- + // `MOE_OUTER_INDICES_PACKED`, `IS_FIRST_OUTER` and `IS_SECOND_OUTER` are known columns: + // the verifier recomputes them from the public pin schedule, so on a routing row the + // packed word carries exactly the pinned outer indices (zero in unpinned slots) and a + // selector is up iff its slot is pinned. The unconditional packed equality plus the + // *unfiltered* 13-bit limb bounds (`super::ctl::blake3_lut_lookups`) give a + // unique decomposition — sum of four 13-bit limbs with weights 1, 2^13, 2^26, 2^39 stays + // below 2^52, no field wrap — so a pinned slot's limbs are forced to the public value and + // the gated word pin transfers it onto the ingested message word. An unpinned slot's + // limbs are forced to zero and its ingested word stays free witness (neighbor entries, + // bound only by the hash chain to `HASH_ROUTING`) — the deployed chip's exact semantics. + let limb_base = eval.u64(1 << 13); + let outer_first = eval.polyval(&lv.outer_index_first, limb_base); + let outer_second = eval.polyval(&lv.outer_index_second, limb_base); + let c2_26 = eval.u64(1 << 26); + let moe_outer_indices_packed = eval.mad(outer_second, c2_26, outer_first); + eval.constraint_eq(lv.moe_outer_indices_packed, moe_outer_indices_packed); + eval.constraint_eq_if(lv.is_first_outer, word0, outer_first); + eval.constraint_eq_if(lv.is_second_outer, word1, outer_second); + + // ---- 7. MoE offsets/routing order machinery. + // We need to check: + // 1. `O_i` <= `O_{i+1}` for all i, + // 2. `R[w][i]` < `R[w][i+1]` for all i (the winner slice is strictly increasing), + // 3. the three public offsets `O_{w-1}`, `O_w` and `O_{e-1}` sit at their positions in + // the hashed offsets stream (bound to `HO`), and the words after `O_{e-1}` are zero, + // 4. every value in the winner slice is < m. + // All the gate flags and pins below are known columns, recomputed from public data. + // Note that for `w = 0` there is no stream word to pin `O_{w-1}` to, and for `w = e-1` + // the `O_w` and `O_{e-1}` pins coincide: `O_{w-1} = 0` and `O_w = O_{e-1}` are then + // enforced natively (`MoEStatement::check`). + + // Check 3: `word_pin_first` and `word_pin_second` hold the public offset (or padding + // zero) the row's words are pinned to. + eval.constraint_eq_if(lv.is_word_pin_first, word0, lv.word_pin_first); + eval.constraint_eq_if(lv.is_word_pin_second, word1, lv.word_pin_second); + + // Checks 1 and 2. If both words belong to the checked range, then: + // word1 - word0 - is_chain_strict = chain_intra_limbs[0] + 2^16 * chain_intra_limbs[1] + // (`is_chain_strict` is 1 exactly on routing rows). The limbs are RC16-bounded, so the + // difference lies in [0, 2^32) and a wrapped negative can never satisfy the equality. + let c2_16 = eval.u64(1 << 16); + let intra = eval.polyval(&lv.chain_intra_limbs, c2_16); + let inter = eval.polyval(&lv.chain_inter_limbs, c2_16); + let inter_next = eval.polyval(&nv.chain_inter_limbs, c2_16); + let d_intra = eval.sub(word1, word0); + let d_intra = eval.sub(d_intra, lv.is_chain_strict); + eval.constraint_eq_if(lv.is_chain_intra, d_intra, intra); + // Then, we need to chain with the next leaf value: + // word0 - chain_carry - is_chain_strict = chain_inter_limbs[0] + 2^16 * chain_inter_limbs[1] + let d_inter = eval.sub(word0, lv.chain_carry); + let d_inter = eval.sub(d_inter, lv.is_chain_strict); + eval.constraint_eq_if(lv.is_chain_inter, d_inter, inter); + // Check 4: the slice is strictly increasing, so bounding its last value by + // `word_pin_* = m - 1` bounds the whole slice. The difference reuses a limb pair that + // is idle on its row: this row's intra pair when the last value is `word0`, or the + // next row's inter pair when it is `word1`. + let d_bound_first = eval.sub(lv.word_pin_first, word0); + eval.constraint_eq_if(lv.is_bound_first, d_bound_first, intra); + let d_bound_second = eval.sub(lv.word_pin_second, word1); + eval.constraint_eq_if(lv.is_bound_second, d_bound_second, inter_next); + + // We update `chain_carry`: on routing/offsets rows it becomes the row's second word; + // on all other rows (the Merkle parents in between) it copies from the previous row, + // so the inter check above always compares against the stream-previous word. + let carry_step = eval.sub(word1, lv.chain_carry); + let carry_next = eval.mad(lv.is_chain_data, carry_step, lv.chain_carry); + eval.constraint_eq(nv.chain_carry, carry_next); + + // ---- 8. Row counter: transition (the cyclic wrap cannot apply to a strict increment), + // ---- first-row anchor 0. ---- + let incremented = eval.add(lv.trace_row_index, one); + let diff = eval.sub(nv.trace_row_index, incremented); + eval.constraint_transition(diff); + eval.constraint_first_row(lv.trace_row_index); +} + +/// One half quarter-round of the G-function cascade (the deployed chip's `half_g`): +/// `ea = a + packed(b) + m` (mod 2^32, unconditional), `ea = d ^ (ed <<< rot1)` (gated), +/// `ec = c + packed(ed)` (mod 2^32, unconditional), `ec = b ^ (eb <<< rot2)` (gated); +/// the produced bit columns `eb`/`ed` are boolean-checked unconditionally. +#[allow(clippy::too_many_arguments)] +fn half_g( + eval: &mut E, + a: V, + b: &[V; 32], + c: V, + d: &[V; 32], + m: V, + second_half: bool, + expected_a: V, + expected_b: &[V; 32], + expected_c: V, + expected_d: &[V; 32], + is_activated: V, +) where + V: Copy, + S: Copy, + E: Evaluator, +{ + let (rot_1, rot_2) = if second_half { (8, 7) } else { (16, 12) }; + let two = eval.i32(2); + let b_packed = eval.polyval(b, two); + add3_unchecked(eval, expected_a, a, b_packed, m); + xor_32_shift_if(eval, expected_a, d, expected_d, is_activated, rot_1); + let expected_d_packed = eval.polyval(expected_d, two); + add2_unchecked(eval, expected_c, c, expected_d_packed); + xor_32_shift_if(eval, expected_c, b, expected_b, is_activated, rot_2); +} + +/// One full round between `states[0]` and `states[4]` (= the next row's input state): two +/// column half-rounds then two diagonal half-rounds, message words in schedule order. +fn verify_round(eval: &mut E, states: &[&Fp16RawBlake3StateCols; 5], msg: &[V; 16], is_activated: V) +where + V: Copy, + S: Copy, + E: Evaluator, +{ + for i in 0..4 { + half_g( + eval, + states[0].row1[i], + &states[0].row2[i], + states[0].row3[i], + &states[0].row4[i], + msg[2 * i], + false, + states[1].row1[i], + &states[1].row2[i], + states[1].row3[i], + &states[1].row4[i], + is_activated, + ); + } + for i in 0..4 { + half_g( + eval, + states[1].row1[i], + &states[1].row2[i], + states[1].row3[i], + &states[1].row4[i], + msg[2 * i + 1], + true, + states[2].row1[i], + &states[2].row2[i], + states[2].row3[i], + &states[2].row4[i], + is_activated, + ); + } + for i in 0..4 { + half_g( + eval, + states[2].row1[i], + &states[2].row2[(i + 1) % 4], + states[2].row3[(i + 2) % 4], + &states[2].row4[(i + 3) % 4], + msg[8 + 2 * i], + false, + states[3].row1[i], + &states[3].row2[(i + 1) % 4], + states[3].row3[(i + 2) % 4], + &states[3].row4[(i + 3) % 4], + is_activated, + ); + } + for i in 0..4 { + half_g( + eval, + states[3].row1[i], + &states[3].row2[(i + 1) % 4], + states[3].row3[(i + 2) % 4], + &states[3].row4[(i + 3) % 4], + msg[8 + 2 * i + 1], + true, + states[4].row1[i], + &states[4].row2[(i + 1) % 4], + states[4].row3[(i + 2) % 4], + &states[4].row4[(i + 3) % 4], + is_activated, + ); + } +} + +/// The finalization identity (deployed `finalize_blake`): on `is_activated` rows STATE1's bit +/// halves are repurposed as decompositions of STATE0's packed halves, and the returned output +/// expression is `v[i] ^ v[8+i]` — a bona-fide u32 because it is packed from boolean-checked +/// bits. +fn finalize_blake(eval: &mut E, state0: &Fp16RawBlake3StateCols, state1: &Fp16RawBlake3StateCols, is_activated: V) -> [V; 8] +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let two = eval.i32(2); + for i in 0..4 { + let row2_packed = eval.polyval(&state1.row2[i], two); + eval.constraint_eq_if(is_activated, state0.row1[i], row2_packed); + let row4_packed = eval.polyval(&state1.row4[i], two); + eval.constraint_eq_if(is_activated, state0.row3[i], row4_packed); + } + core::array::from_fn(|i| { + if i < 4 { + xor_32(eval, &state1.row2[i], &state1.row4[i]) + } else { + xor_32(eval, &state0.row2[i - 4], &state0.row4[i - 4]) + } + }) +} + +/// The init-state check on `IS_NEW_BLAKE` rows (deployed `verify_init_state`): words 0..8 equal +/// the muxed CV, words 8..12 the BLAKE3 IV, and the row4 bit block packs to the tweak +/// (`counter(48) | flags(8) | block_len(7)` window, remaining bits zero). +fn verify_init_state(eval: &mut E, init_state: &Fp16RawBlake3StateCols, is_new_blake: V, cv: &[V; 8], blake3_tweak: V) +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let two = eval.i32(2); + for i in 0..4 { + eval.constraint_eq_if(is_new_blake, init_state.row1[i], cv[i]); + let iv = eval.u64(BLAKE3_IV[i] as u64); + eval.constraint_eq_if(is_new_blake, init_state.row3[i], iv); + let row2_packed = eval.polyval(&init_state.row2[i], two); + eval.constraint_eq_if(is_new_blake, row2_packed, cv[i + 4]); + } + let active_bits: Vec = init_state.row4[0] + .iter() + .chain(&init_state.row4[1][0..16]) + .chain(&init_state.row4[3][0..8]) + .chain(&init_state.row4[2][0..7]) + .copied() + .collect(); + let packed = eval.polyval(&active_bits, two); + eval.constraint_eq_if(is_new_blake, packed, blake3_tweak); + let zero_bits: Vec = init_state.row4[1][16..] + .iter() + .chain(&init_state.row4[2][7..]) + .chain(&init_state.row4[3][8..]) + .copied() + .collect(); + for bit in zero_bits { + let zeroed = eval.mul(is_new_blake, bit); + eval.constraint(zeroed); + } +} + +/// `res = a + b + c (mod 2^32)`: `(diff)(diff - 2^32)(diff - 2^33) = 0` — unconditional +/// (finalization rows satisfy it via the postprocess fill). The mod-2^32 reading is sound only +/// because every operand is elsewhere bounded (packed bits, byte packings, or the routing +/// lookup's 2^34-injective keys). +fn add3_unchecked(eval: &mut E, res: V, a: V, b: V, c: V) +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let sum = eval.add(a, b); + let sum = eval.add(sum, c); + let c2_32 = eval.u64(1 << 32); + let diff = eval.sub(sum, res); + let diff_1 = eval.sub(diff, c2_32); + let diff_2 = eval.sub(diff_1, c2_32); + let poly = eval.mul(diff, diff_1); + let poly = eval.mul(poly, diff_2); + eval.constraint(poly); +} + +/// `res = a + b (mod 2^32)`: `(diff)(diff - 2^32) = 0` — unconditional. +fn add2_unchecked(eval: &mut E, res: V, a: V, b: V) +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let sum = eval.add(a, b); + let diff = eval.sub(sum, res); + let c2_32 = eval.u64(1 << 32); + let diff_1 = eval.sub(diff, c2_32); + let c = eval.mul(diff, diff_1); + eval.constraint(c); +} + +/// If activated, `res = a ^ (b <<< shift)` over the bit columns (i.e. `b = (res ^ a) >>> shift`, +/// the rotation absorbed into the reindexing); `b`'s bits are boolean-checked unconditionally, +/// which is what makes every packed state word a range-checked u32. +fn xor_32_shift_if(eval: &mut E, res: V, a: &[V; 32], b: &[V; 32], is_activated: V, shift: usize) +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let two = eval.i32(2); + for &bit in b.iter() { + eval.constraint_bool(bit); + } + let xor_bits: [V; 32] = core::array::from_fn(|i| { + let a_bit = a[i]; + let b_bit = b[(i + 32 - shift) % 32]; + eval.xor_bit(a_bit, b_bit) + }); + let xor = eval.polyval(&xor_bits, two); + eval.constraint_eq_if(is_activated, res, xor); +} + +/// The packed XOR of two boolean-checked bit columns (no new constraints; degree 2). +fn xor_32(eval: &mut E, a: &[V; 32], b: &[V; 32]) -> V +where + V: Copy, + S: Copy, + E: Evaluator, +{ + let two = eval.i32(2); + let xor_bits: [V; 32] = core::array::from_fn(|i| eval.xor_bit(a[i], b[i])); + eval.polyval(&xor_bits, two) +} + +// ================================================================================================== +// Stark impl +// ================================================================================================== + +/// Fp16RawBlake3Stark. A CTL party of the fp8 batch (`requires_ctls()`): its proofs carry the +/// cross-table openings of the channels declared in `super::ctl`, so the batch driver is the +/// only supported proving path — there is no standalone uni-STARK proof object. +#[derive(Clone, Debug)] +pub struct Fp16RawBlake3Stark, const D: usize> { + pub program: Fp16RawBlake3Program, + _phantom: PhantomData, +} + +impl, const D: usize> Fp16RawBlake3Stark { + pub fn new(program: Fp16RawBlake3Program) -> Self { + Self { + program, + _phantom: PhantomData, + } + } +} + +impl, const D: usize> Stark for Fp16RawBlake3Stark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, ExtensionTarget, NUM_FP16_RAW_BLAKE3_COLUMNS, NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_blake3_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_blake3_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + // Party to the strip-bytes, block-scales and lottery-words channels, plus the committed + // LUT channels (declared in `super::ctl`). + fn requires_ctls(&self) -> bool { + true + } + + /// The CV-routing lookup: every row publishes `CV_OUT` at key + /// `TRACE_ROW_INDEX` with witness multiplicity `CV_OUT_FREQ`; fetch rows (`IS_CV_IN`) consume + /// `CV_IN` at key `CV_ROUTE_KEY_OR_TWEAK`. One [`Lookup`] per CV word, all sharing the + /// multiplicity column (a consumer fetches the 8 words together under the same filter). + /// Keys are `word + 2^34 * row` — injective because the round block bounds any accepted + /// word below 2^34 (the `CV_ROUTING_KEY_FACTOR` bound) and `TRACE_ROW_INDEX` is a committed + /// counter. + fn lookups(&self) -> Vec> { + let m = &FP16_RAW_BLAKE3_COL_MAP; + let factor = F::from_canonical_u64(CV_ROUTING_KEY_FACTOR); + (0..8) + .map(|i| Lookup { + columns: vec![Column::linear_combination([ + (m.cv_in[i], F::ONE), + (m.cv_route_key_or_tweak, factor), + ])], + table_column: Column::linear_combination([(m.cv_out[i], F::ONE), (m.trace_row_index, factor)]), + frequencies_column: Column::single(m.cv_out_freq), + filter_columns: vec![Filter::from_column(Column::single(m.is_cv_in))], + }) + .collect() + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use pearl_blake3::{ + B3F_CHUNK_END, B3F_CHUNK_START, B3F_KEYED_HASH, B3F_PARENT, B3F_ROOT, BLAKE3_CHUNK_LEN, BLAKE3_MSG_LEN, Blake3Hasher, + MerkleTree, blake3_digest, pad_to_chunk_boundary, padded_chunk_len, + }; + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + + use super::super::columns::NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS; + use super::*; + use crate::api::layout::{AxisPattern, DimType}; + use crate::api::proof_utils::operand_digest_fp10; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type S = Fp16RawBlake3Stark; + + /// 64-byte blocks per 1024-byte chunk. + const BLOCKS_PER_CHUNK: usize = BLAKE3_CHUNK_LEN / BLAKE3_MSG_LEN; + + /// Test-side program compiler: the keyed chunk tree over one chunk-padded plane + /// (`pearl_blake3::MerkleTree` semantics — adjacent pairing, odd tail promoted, ROOT flag + /// on the top merge / the single chunk's last block). With `subtree` the ROOT flag is + /// withheld (the produced CV is an inner node of a larger tree — the sparse-opening case). + /// The production schedule comes from the fp8 `BlakeProgram` compiler; this mirror + /// only feeds the table's tests. + fn compile_plane_tree( + instrs: &mut Vec, + plane: Fp16RawPlaneId, + raw_len: usize, + ctl_key_base: u64, + subtree: bool, + bind: Option, + ) -> usize { + let chunks = padded_chunk_len(raw_len) / BLAKE3_CHUNK_LEN; + assert!(chunks >= 1, "empty plane {plane:?}"); + let mut cvs: Vec = Vec::with_capacity(chunks); + for c in 0..chunks { + for b in 0..BLOCKS_PER_CHUNK { + let mut flags = B3F_KEYED_HASH as u32; + if b == 0 { + flags |= B3F_CHUNK_START as u32; + } + let is_tree_root = chunks == 1 && b + 1 == BLOCKS_PER_CHUNK && !subtree; + if b + 1 == BLOCKS_PER_CHUNK { + flags |= B3F_CHUNK_END as u32; + if is_tree_root { + flags |= B3F_ROOT as u32; + } + } + let offset = c * BLAKE3_CHUNK_LEN + b * BLAKE3_MSG_LEN; + let ctl_base = match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues => ctl_key_base + offset as u64, + Fp16RawPlaneId::AScales | Fp16RawPlaneId::BScales => ctl_key_base + (offset / 2) as u64, + Fp16RawPlaneId::Routing | Fp16RawPlaneId::Offsets => 0, + }; + instrs.push(Fp16RawBlake3Instruction { + cv: if b == 0 { + Fp16RawCvSource::KeyA + } else { + Fp16RawCvSource::Chain(instrs.len() - 1) + }, + msg: Fp16RawMessageSource::PlaneBytes { plane, offset, ctl_base }, + counter: c as u64, + block_len: BLAKE3_MSG_LEN as u32, + flags, + bind: if is_tree_root { bind } else { None }, + egress: None, + }); + } + cvs.push(instrs.len() - 1); + } + while cvs.len() > 1 { + let is_root_layer = cvs.len() == 2 && !subtree; + let mut next_layer = Vec::with_capacity(cvs.len().div_ceil(2)); + for pair in cvs.chunks(2) { + if let [left, right] = *pair { + let mut flags = (B3F_KEYED_HASH | B3F_PARENT) as u32; + if is_root_layer { + flags |= B3F_ROOT as u32; + } + instrs.push(Fp16RawBlake3Instruction { + cv: Fp16RawCvSource::KeyA, + msg: Fp16RawMessageSource::Parent { + left: Fp16RawCvRef::Instruction(left), + right: Fp16RawCvRef::Instruction(right), + }, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags, + bind: if is_root_layer { bind } else { None }, + egress: None, + }); + next_layer.push(instrs.len() - 1); + } else { + next_layer.push(pair[0]); // Odd tail: promoted unchanged. + } + } + cvs = next_layer; + } + cvs[0] + } + + /// The complete-forest schedule of one job whose planes are fully opened: four plane trees, + /// the routing tree, the two commit folds, the lottery. + fn compile_forest(h: usize, w: usize, k: usize, routing_blocks: usize) -> Fp16RawBlake3Program { + let mut instrs = Vec::new(); + let a_values = compile_plane_tree(&mut instrs, Fp16RawPlaneId::AValues, h * k, 0, false, None); + let a_scales = compile_plane_tree(&mut instrs, Fp16RawPlaneId::AScales, h * k / 4, 0, false, None); + let b_values = compile_plane_tree(&mut instrs, Fp16RawPlaneId::BValues, w * k, (h * k) as u64, false, None); + let b_scales = compile_plane_tree(&mut instrs, Fp16RawPlaneId::BScales, w * k / 4, (h * k / 8) as u64, false, None); + if routing_blocks > 0 { + compile_plane_tree( + &mut instrs, + Fp16RawPlaneId::Routing, + routing_blocks * BLAKE3_MSG_LEN, + 0, + false, + Some(Fp16RawPublicBinding::HashRouting), + ); + // A single expert owning the whole opened stream (`e = 1`, `w = 0`), the offsets + // list [`O_0`] = the stream length; `m` past the 26-bit pin cap so oversized + // *neighbor* words stay legal. + compile_plane_tree( + &mut instrs, + Fp16RawPlaneId::Offsets, + std::mem::size_of::(), + 0, + false, + Some(Fp16RawPublicBinding::HashOffsets), + ); + } + append_commit_fold(&mut instrs, a_values, a_scales, Fp16RawPublicBinding::HashA, Fp16RawCvSource::KeyA); + append_commit_fold(&mut instrs, b_values, b_scales, Fp16RawPublicBinding::HashB, Fp16RawCvSource::KeyB); + instrs.push(Fp16RawBlake3Instruction::lottery()); + Fp16RawBlake3Program { + instructions: instrs, + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: (0..routing_blocks).map(|b| (b * 16, test_routing_word(b * 16))).collect(), + moe: (routing_blocks > 0).then(|| MoeSchedule { + w: 0, + experts: 1, + o_w_prev: 0, + o_w: 16 * routing_blocks as u32, + o_last: 16 * routing_blocks as u32, + m: 1 << 27, + }), + msg_pins: Vec::new(), + height_bits: None, + } + } + + /// Owned test inputs (the `Fp16RawBlake3TraceInputs` borrows). + struct TestData { + a_values: Vec, + a_scales: Vec, + b_values: Vec, + b_scales: Vec, + routing_words: Vec, + offsets_words: Vec, + aux_msgs: Vec<[u8; 64]>, + aux_cvs: Vec<[u8; 32]>, + lottery_words: [u32; 16], + key_a: [u32; 8], + key_b: [u32; 8], + jackpot_key: [u32; 8], + } + + impl TestData { + fn new(h: usize, w: usize, k: usize, routing_blocks: usize) -> Self { + let bytes = + |len: usize, salt: u64| -> Vec { (0..len).map(|i| ((i as u64).wrapping_mul(salt) >> 5) as u8).collect() }; + Self { + a_values: bytes(h * k, 0x9E3779B97F4A7C15), + a_scales: bytes(h * k / 4, 0xC2B2AE3D27D4EB4F), + b_values: bytes(w * k, 0xD1B54A32D192ED03), + b_scales: bytes(w * k / 4, 0xA0761D6478BD642F), + routing_words: (0..routing_blocks * 16).map(test_routing_word).collect(), + offsets_words: if routing_blocks > 0 { + vec![16 * routing_blocks as u32] + } else { + Default::default() + }, + aux_msgs: Vec::new(), + aux_cvs: Vec::new(), + lottery_words: core::array::from_fn(|i| (i as u32).wrapping_mul(0x85EBCA77) ^ 0x1234), + key_a: core::array::from_fn(|i| 0x1000_0001u32.wrapping_mul(i as u32 + 1)), + key_b: core::array::from_fn(|i| 0x4000_0005u32.wrapping_mul(i as u32 + 1)), + jackpot_key: core::array::from_fn(|i| 0x3000_0007u32.wrapping_mul(i as u32 + 1)), + } + } + + fn inputs(&self) -> Fp16RawBlake3TraceInputs<'_> { + Fp16RawBlake3TraceInputs { + a_values: &self.a_values, + a_scales: &self.a_scales, + b_values: &self.b_values, + b_scales: &self.b_scales, + routing_words: &self.routing_words, + offsets_words: &self.offsets_words, + aux_msgs: &self.aux_msgs, + aux_cvs: &self.aux_cvs, + lottery_words: self.lottery_words, + key_a: self.key_a, + key_b: self.key_b, + jackpot_key: self.jackpot_key, + a_hash_id: HashId::Blake3Chunk1024, + b_hash_id: HashId::Blake3Chunk1024, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + } + } + } + + fn words_to_bytes(words: &[u32; 8]) -> [u8; 32] { + core::array::from_fn(|i| words[i / 4].to_le_bytes()[i % 4]) + } + + fn field_words_to_bytes(words: &[F; 8]) -> [u8; 32] { + let w: [u32; 8] = core::array::from_fn(|i| words[i].to_canonical_u64() as u32); + words_to_bytes(&w) + } + + fn pi_bytes(pis: &[F; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS], base: usize) -> [u8; 32] { + let w: [F; 8] = core::array::from_fn(|i| pis[base + i]); + field_words_to_bytes(&w) + } + + /// All plane trees single-chunk; 89 compressions -> 712 live rows -> 1024. + fn small_geometry() -> (usize, usize, usize, usize) { + (2, 2, 64, 2) + } + + /// A-values/B-values 3 chunks each (odd promote + parent cascade), routing 2 chunks; + /// exercises chunk chaining across chunks, in-table parents, and multi-chunk roots. + fn multi_chunk_geometry() -> (usize, usize, usize, usize) { + (2, 2, 1536, 20) + } + + fn generate( + h: usize, + w: usize, + k: usize, + routing_blocks: usize, + ) -> ( + Fp16RawBlake3Program, + TestData, + Vec<[F; NUM_FP16_RAW_BLAKE3_COLUMNS]>, + [F; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS], + ) { + let program = compile_forest(h, w, k, routing_blocks); + let data = TestData::new(h, w, k, routing_blocks); + let (rows, pis) = program.generate_trace::(&data.inputs()); + (program, data, rows, pis) + } + + /// Runs every constraint over every row pair, *including* the last -> first wrap + /// (`z_last` vanishes only on the last row, exactly as in the real vanishing polynomial). + fn constraints_violated(stark: &S, rows: &[[F; NUM_FP16_RAW_BLAKE3_COLUMNS]], pis: &[F; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS]) -> bool { + let n = rows.len(); + for i in 0..n { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], pis); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + if consumer.accumulators().into_iter().any(|acc| acc != F::ZERO) { + return true; + } + } + false + } + + // ---------------------------------------------------------------- FP16 fork: output egress + + /// The FP16 fork's output-egress channel exports a compression's `CV_OUT` as 16 little-endian + /// 16-bit limbs on the finalization row, under the program-chosen `CTL_KEY_BASE`. This builds a + /// single keyed compression with egress set and asserts (a) the honest trace (egress flag + + /// limbs + constraint) satisfies the whole forked AIR, (b) the egress limbs recompose to + /// `cv_out`, which is bit-exact against a reference keyed BLAKE3, and (c) the egress CTL channel + /// reads exactly those limbs on the flagged row, keyed by the chosen base. + #[test] + fn egress_limbs_recompose_to_cv_out_bit_exact() { + use super::super::columns::FP16_RAW_BLAKE3_COL_MAP as CM; + use super::super::ctl::ctl_cv_egress_looking_blake3; + + const EGRESS_BASE: u64 = 4096; + // One keyed lottery compression (JACKPOT_KEY) with output egress requested. + let mut instr = Fp16RawBlake3Instruction::lottery(); + instr.egress = Some(EGRESS_BASE); + let program = Fp16RawBlake3Program { + instructions: vec![instr], + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: vec![], + moe: None, + msg_pins: Vec::new(), + height_bits: None, + }; + + let jackpot_key: [u32; 8] = core::array::from_fn(|i| 0x3000_0007u32.wrapping_mul(i as u32 + 1)); + let lottery_words: [u32; 16] = core::array::from_fn(|i| (i as u32).wrapping_mul(0x9E3779B1) ^ 0xFACE); + let data = Fp16RawBlake3TraceInputs { + a_values: &[], + a_scales: &[], + b_values: &[], + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: &[], + aux_cvs: &[], + lottery_words, + key_a: [0; 8], + key_b: [0; 8], + jackpot_key, + a_hash_id: HashId::Blake3Chunk1024, + b_hash_id: HashId::Blake3Chunk1024, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + }; + let (rows, pis) = program.generate_trace::(&data); + + // Reference: the keyed BLAKE3 of the 64-byte lottery message under JACKPOT_KEY. + let msg_bytes: Vec = lottery_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let ref_digest = blake3_digest(&msg_bytes, Some(words_to_bytes(&jackpot_key))); + // The bound public jackpot hash must already equal that digest (sanity on the compression). + assert_eq!(pi_bytes(&pis, PI_HASH_JACKPOT), ref_digest, "HASH_JACKPOT != reference keyed blake3"); + + // The egress flag fires on exactly one row (the finalization row), and nowhere else. + let flagged: Vec = (0..rows.len()).filter(|&r| rows[r][CM.is_egress_cv] == F::ONE).collect(); + assert_eq!(flagged.len(), 1, "IS_EGRESS_CV must fire on exactly the one flagged finalization row"); + let fin = flagged[0]; + let fin_row: &Fp16RawBlake3ColumnsView = rows[fin].borrow(); + assert_eq!(fin_row.is_last_round, F::ONE, "egress row must be a finalization row"); + assert_eq!(fin_row.ctl_key_base, F::from_canonical_u64(EGRESS_BASE), "egress key must ride CTL_KEY_BASE"); + + // (b) The 16 limbs recompose to cv_out, and cv_out is bit-exact vs the reference digest. + let mut recomposed = [0u32; 8]; + for w in 0..8 { + let lo = fin_row.cv_egress_limbs[2 * w].to_canonical_u64(); + let hi = fin_row.cv_egress_limbs[2 * w + 1].to_canonical_u64(); + assert!(lo < (1 << 16) && hi < (1 << 16), "egress limbs must be 16-bit (RC16 domain)"); + let word = (lo + (hi << 16)) as u32; + assert_eq!( + word, + fin_row.cv_out[w].to_canonical_u64() as u32, + "egress limbs must recompose to cv_out[{w}]" + ); + recomposed[w] = word; + } + assert_eq!(words_to_bytes(&recomposed), ref_digest, "recomposed egress CV != reference keyed blake3"); + + // Off-egress rows leave the limbs at their zero (in-domain) witness. + for r in 0..rows.len() { + if r == fin { + continue; + } + for j in 0..16 { + assert_eq!(rows[r][CM.cv_egress_limbs[j]], F::ZERO, "non-egress row {r} limb {j} must be zero"); + } + } + + // The honest trace (egress flag, limbs, constraint, RC16 inventory) satisfies the whole AIR. + assert!(!constraints_violated(&S::new(program), &rows, &pis), "forked AIR violated with egress on"); + + // (c) The egress CTL channel reads cv_egress_limbs[j] at key CTL_KEY_BASE + j. + assert_eq!(ctl_cv_egress_looking_blake3::(3).len(), 16); + } + + /// A tampered egress limb must break the forked AIR's egress constraint (soundness of the + /// limb -> cv_out pin). Flipping a limb off its honest value breaks recomposition under + /// IS_EGRESS_CV. + #[test] + fn tampered_egress_limb_breaks_constraints() { + const EGRESS_BASE: u64 = 64; + let mut instr = Fp16RawBlake3Instruction::lottery(); + instr.egress = Some(EGRESS_BASE); + let program = Fp16RawBlake3Program { + instructions: vec![instr], + num_aux_msgs: 0, + num_aux_cvs: 0, + routing_pins: vec![], + moe: None, + msg_pins: Vec::new(), + height_bits: None, + }; + let jackpot_key: [u32; 8] = core::array::from_fn(|i| 0x1234_5678u32.wrapping_add(i as u32)); + let lottery_words: [u32; 16] = core::array::from_fn(|i| (i as u32).wrapping_mul(7) ^ 0x55); + let data = Fp16RawBlake3TraceInputs { + a_values: &[], + a_scales: &[], + b_values: &[], + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: &[], + aux_cvs: &[], + lottery_words, + key_a: [0; 8], + key_b: [0; 8], + jackpot_key, + a_hash_id: HashId::Blake3Chunk1024, + b_hash_id: HashId::Blake3Chunk1024, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + }; + let (mut rows, pis) = program.generate_trace::(&data); + let stark = S::new(program); + assert!(!constraints_violated(&stark, &rows, &pis), "honest egress trace should pass"); + + let fin = (0..rows.len()) + .find(|&r| rows[r][FP16_RAW_BLAKE3_COL_MAP.is_egress_cv] == F::ONE) + .expect("an egress row"); + rows[fin][FP16_RAW_BLAKE3_COL_MAP.cv_egress_limbs[0]] += F::ONE; + assert!( + constraints_violated(&stark, &rows, &pis), + "a tampered egress limb must break the egress pin" + ); + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, rows, pis) = generate(h, w, k, r); + assert_eq!(rows.len(), 1024); + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + #[test] + fn honest_multi_chunk_trace_satisfies_all_constraints() { + let (h, w, k, r) = multi_chunk_geometry(); + let (program, _, rows, pis) = generate(h, w, k, r); + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + #[test] + fn roots_are_bit_exact_vs_pearl_blake3() { + for (h, w, k, r) in [small_geometry(), multi_chunk_geometry()] { + let (_, data, _, pis) = generate(h, w, k, r); + let key = words_to_bytes(&data.key_a); + let key_b = words_to_bytes(&data.key_b); + + // HASH_A / HASH_B vs the native fold (`operand_digest_fp10`): the plane trees + // are all keyed with `key_a`, but each side's fold keys under its own opening key. + let root = |bytes: &[u8]| MerkleTree::new(&pad_to_chunk_boundary(bytes), key).root(); + let fold_a = |values: &[u8], scales: &[u8]| operand_digest_fp10(&root(values), &root(scales), &key); + let fold_b = |values: &[u8], scales: &[u8]| operand_digest_fp10(&root(values), &root(scales), &key_b); + assert_eq!(pi_bytes(&pis, PI_HASH_A), fold_a(&data.a_values, &data.a_scales)); + assert_eq!(pi_bytes(&pis, PI_HASH_B), fold_b(&data.b_values, &data.b_scales)); + + // Routing tree root -> HASH_ROUTING, offsets tree root -> HASH_OFFSETS. + let routing_bytes: Vec = data.routing_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let expected_routing = MerkleTree::new(&pad_to_chunk_boundary(&routing_bytes), key).root(); + assert_eq!(pi_bytes(&pis, PI_HASH_ROUTING), expected_routing); + let offsets_bytes: Vec = data.offsets_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let expected_offsets = MerkleTree::new(&pad_to_chunk_boundary(&offsets_bytes), key).root(); + assert_eq!(pi_bytes(&pis, PI_HASH_OFFSETS), expected_offsets); + + // Lottery -> HASH_JACKPOT: keyed blake3 of the 16 folded words under JACKPOT_KEY. + let fold_bytes: Vec = data.lottery_words.iter().flat_map(|w| w.to_le_bytes()).collect(); + let expected_jackpot = blake3_digest(&fold_bytes, Some(words_to_bytes(&data.jackpot_key))); + assert_eq!(pi_bytes(&pis, PI_HASH_JACKPOT), expected_jackpot); + } + } + + /// The word `TestData::new` puts at routing stream position `i`: strictly increasing + /// (the whole stream is the winner slice under `compile_forest`'s schedule, so the order + /// chains apply) with gaps of 8, so a neighbor word can move without breaking the order; + /// < 2^26 (the pin cap) and nonzero at position 0 (the pinned-value tamper tests need the + /// packed prep column to move when a pin is cleared). + fn test_routing_word(i: usize) -> u32 { + (i as u32 + 1) * 8 + } + + /// The deployed selective-pinning semantics on a mixed schedule: pins on a strict + /// subset of the routing words — a second-slot-only row, a fully pinned row, and a pin + /// in the second block — with every other word (including all chunk-padding blocks) a + /// free witness neighbor. Selectors, limbs and the packed word must follow the pins + /// exactly, the neighbor words must be unconstrained (one is deliberately >= 2^26), the + /// constraints must accept, and `known_values` must reproduce the known columns bit for + /// bit — the class (a) recompute the batch verifier pins. + #[test] + fn selective_pinning_matches_deployed_semantics() { + let (h, w, k, routing_blocks) = small_geometry(); + let mut program = compile_forest(h, w, k, routing_blocks); + // Words 1 (second slot of row 0), 4 and 5 (both slots of row 2), 17 (second slot of + // block 1's row 0). Everything else — word 0 included — is a neighbor. + let pinned: [usize; 4] = [1, 4, 5, 17]; + program.routing_pins = pinned.iter().map(|&i| (i, test_routing_word(i))).collect(); + + let mut data = TestData::new(h, w, k, routing_blocks); + // A neighbor word above the 26-bit pin cap: only *pinned* values are capped; an + // unsampled slice entry is free witness under the hash chain and the order chain + // (strictly increasing below `m = 2^27`), so the slice's last word can exceed 2^26. + data.routing_words[31] = 0x0400_0001; + let (rows, pis) = program.generate_trace::(&data.inputs()); + + // The routing instructions of the fixture forest: one full chunk (16 blocks), the + // first two live. Walk their 8 message rows each and check the pin surface. + let routing_row0: usize = ROWS_PER_COMPRESSION + * program + .instructions + .iter() + .position(|i| { + matches!( + i.msg, + Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Routing, + .. + } + ) + }) + .unwrap(); + for block in 0..BLOCKS_PER_CHUNK { + for j in 0..ROWS_PER_COMPRESSION { + let row: &Fp16RawBlake3ColumnsView = rows[routing_row0 + ROWS_PER_COMPRESSION * block + j].borrow(); + let (w0, w1) = (16 * block + 2 * j, 16 * block + 2 * j + 1); + let pin = |i: usize| pinned.contains(&i); + assert_eq!( + row.is_first_outer, + F::from_bool(pin(w0)), + "block {block} row {j}: first selector" + ); + assert_eq!( + row.is_second_outer, + F::from_bool(pin(w1)), + "block {block} row {j}: second selector" + ); + let expect = |i: usize| if pin(i) { test_routing_word(i) as u64 } else { 0 }; + assert_eq!( + row.moe_outer_indices_packed, + F::from_canonical_u64(expect(w0) + (expect(w1) << 26)), + "block {block} row {j}: packed word carries pinned values only" + ); + let limbs = |v: [F; 2]| v[0].to_canonical_u64() + (v[1].to_canonical_u64() << 13); + assert_eq!(limbs(row.outer_index_first), expect(w0), "block {block} row {j}: first limbs"); + assert_eq!( + limbs(row.outer_index_second), + expect(w1), + "block {block} row {j}: second limbs" + ); + } + } + + assert!(!constraints_violated(&S::new(program.clone()), &rows, &pis)); + + // The verifier-side recompute agrees with the trace on every known column. + let known = program.known_values::(&data.inputs().known_inputs()); + assert_eq!(known.len(), NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS); + for (c, col) in known.iter().enumerate() { + for (r, expected) in col.values.iter().enumerate() { + let row: &Fp16RawBlake3ColumnsView = rows[r].borrow(); + let got = [ + row.row_flags_packed, + row.ctl_key_base, + row.is_int8_message, + row.is_scale_message, + row.cv_route_key_or_tweak, + row.moe_outer_indices_packed, + row.word_pin_first, + row.word_pin_second, + ][c]; + assert_eq!(got, *expected, "known column {c} row {r} diverges from the trace"); + } + } + } + + /// A forged limb on a pinned slot breaks the unconditional packed decomposition + /// (constraint 6): `MOE_OUTER_INDICES_PACKED` is class (a), so the limbs cannot move. + #[test] + fn tampered_pinned_limb_breaks_packed_decomposition() { + let (h, w, k, routing_blocks) = small_geometry(); + let program = compile_forest(h, w, k, routing_blocks); + let routing_row0: usize = ROWS_PER_COMPRESSION + * program + .instructions + .iter() + .position(|i| { + matches!( + i.msg, + Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Routing, + .. + } + ) + }) + .unwrap(); + let data = TestData::new(h, w, k, routing_blocks); + let (mut rows, pis) = program.generate_trace::(&data.inputs()); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[routing_row0].borrow_mut(); + assert_eq!(row.is_first_outer, F::ONE, "the fixture pins the block's first word"); + row.outer_index_first[0] += F::ONE; + } + assert!( + constraints_violated(&S::new(program), &rows, &pis), + "a forged pinned limb must break the packed decomposition" + ); + } + + /// A forged message word on a pinned slot breaks the selector-gated word pin: the limbs + /// carry the public outer index, the ingested word must equal it. + #[test] + fn tampered_pinned_message_word_breaks_word_pin() { + let (h, w, k, routing_blocks) = small_geometry(); + let program = compile_forest(h, w, k, routing_blocks); + let routing_row0: usize = ROWS_PER_COMPRESSION + * program + .instructions + .iter() + .position(|i| { + matches!( + i.msg, + Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Routing, + .. + } + ) + }) + .unwrap(); + let data = TestData::new(h, w, k, routing_blocks); + let (mut rows, pis) = program.generate_trace::(&data.inputs()); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[routing_row0].borrow_mut(); + assert_eq!(row.is_first_outer, F::ONE); + // Move the ingested word *and* its buffer copy consistently: only the gated + // equality against the pinned limbs is left to object. + row.uint8_data[0] += F::ONE; + row.blake3_msg_buffer[14] += F::ONE; + } + assert!( + constraints_violated(&S::new(program), &rows, &pis), + "a forged pinned message word must break the gated word pin" + ); + } + + /// A forged fetched root CV on the commit-fold row breaks the CV window: the fold's + /// message words *are* the tree-root CVs, so a prover cannot fold a different values + /// root into `HASH_A`. + #[test] + fn tampered_fold_root_cv_breaks_commit_fold() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let fold_row0 = ROWS_PER_COMPRESSION + * program + .instructions + .iter() + .position(|i| i.bind == Some(Fp16RawPublicBinding::HashA)) + .unwrap(); + { + // Row 3 fetches the values root through the CV window: move the fetched CV (and + // its mux copy) consistently — the sliding-buffer equality is left to object. + let row: &mut Fp16RawBlake3ColumnsView = rows[fold_row0 + 3].borrow_mut(); + assert_eq!(row.is_cv_in, F::ONE); + row.cv_in[0] += F::ONE; + row.blake3_cv[0] += F::ONE; + } + assert!( + constraints_violated(&S::new(program), &rows, &pis), + "a forged fold input must break the CV window" + ); + } + + /// The slice bound's idle-limb reuse, second-word case (even `o_w`: the slice-last entry + /// is its row's second word, so the bound decomposition lives in the *next* row's inter + /// slot — idle there, the next pair starts past the slice). That slot feeds no other + /// gate, so tampering it isolates the bound equality. + #[test] + fn tampered_bound_limbs_break_the_slice_bound() { + let (h, w, k, routing_blocks) = small_geometry(); + let program = compile_forest(h, w, k, routing_blocks); + let data = TestData::new(h, w, k, routing_blocks); + let (mut rows, pis) = program.generate_trace::(&data.inputs()); + let r = (0..rows.len()) + .find(|&r| { + let row: &Fp16RawBlake3ColumnsView = rows[r].borrow(); + row.is_bound_second == F::ONE + }) + .expect("the fixture slice ends on a second word"); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[r + 1].borrow_mut(); + row.chain_inter_limbs[0] += F::ONE; + } + assert!( + constraints_violated(&S::new(program), &rows, &pis), + "a forged bound decomposition must break the slice bound" + ); + } + + /// As above, first-word case (odd `o_w`: the slice-last entry is its row's first word, + /// so the bound rides the row's own idle intra slot). + #[test] + fn bound_first_rides_the_rows_idle_intra_limbs() { + let (h, w, k, routing_blocks) = small_geometry(); + let mut program = compile_forest(h, w, k, routing_blocks); + let o_w = 16 * routing_blocks as u32 - 1; + let s = program.moe.as_mut().unwrap(); + s.o_w = o_w; + s.o_last = o_w; + let mut data = TestData::new(h, w, k, routing_blocks); + data.offsets_words = vec![o_w]; + let (mut rows, pis) = program.generate_trace::(&data.inputs()); + let r = (0..rows.len()) + .find(|&r| { + let row: &Fp16RawBlake3ColumnsView = rows[r].borrow(); + row.is_bound_first == F::ONE + }) + .expect("an odd o_w puts the slice's last entry on a first word"); + let stark = S::new(program); + assert!( + !constraints_violated(&stark, &rows, &pis), + "the tweaked fixture must stay honest" + ); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[r].borrow_mut(); + row.chain_intra_limbs[0] += F::ONE; + } + assert!( + constraints_violated(&stark, &rows, &pis), + "a forged bound decomposition must break the slice bound" + ); + } + + /// Clearing a pin's selector (with `ROW_FLAGS_PACKED` repacked so the unpack stays + /// self-consistent) leaves the AIR satisfied — the selectors are **class (a) known + /// columns**, so the divergence is caught by the batch verifier's known-column check, + /// exactly like the deployed chip's preprocessed columns. + #[test] + fn cleared_outer_selector_is_caught_by_the_known_column_recompute() { + let (h, w, k, routing_blocks) = small_geometry(); + let program = compile_forest(h, w, k, routing_blocks); + let routing_row0: usize = ROWS_PER_COMPRESSION + * program + .instructions + .iter() + .position(|i| { + matches!( + i.msg, + Fp16RawMessageSource::PlaneBytes { + plane: Fp16RawPlaneId::Routing, + .. + } + ) + }) + .unwrap(); + let data = TestData::new(h, w, k, routing_blocks); + let (mut rows, pis) = program.generate_trace::(&data.inputs()); + { + // Freeing the word also requires zeroing the pinned limbs (the packed word is + // class (a) too and must keep decomposing); zero limbs match packed = 0 only if + // the packed column is also moved — which the known-column check pins. Here we + // only clear the selector and zero the limbs+packed consistently. + let row: &mut Fp16RawBlake3ColumnsView = rows[routing_row0].borrow_mut(); + assert_eq!(row.is_first_outer, F::ONE); + row.is_first_outer = F::ZERO; + row.row_flags_packed = pack_control(row); + row.outer_index_first = [F::ZERO; 2]; + row.moe_outer_indices_packed = F::ZERO; + } + assert!( + !constraints_violated(&S::new(program.clone()), &rows, &pis), + "the AIR alone accepts a self-consistent selector clear" + ); + // ... but the class (a) recompute does not: ROW_FLAGS_PACKED and the packed word both + // diverge from the verifier's own values on that row. + let known = program.known_values::(&data.inputs().known_inputs()); + let row: &Fp16RawBlake3ColumnsView = rows[routing_row0].borrow(); + assert_ne!( + known[0].values[routing_row0], row.row_flags_packed, + "ROW_FLAGS_PACKED must diverge" + ); + assert_ne!( + known[5].values[routing_row0], row.moe_outer_indices_packed, + "MOE_OUTER_INDICES_PACKED must diverge" + ); + } + + /// A forged *neighbor* word (unsampled entry of a hotspot block) is a legitimate free + /// witness for the AIR — but it changes the routing tree, so the bound `HASH_ROUTING` + /// public input moves and the statement's expected-public-input pinning rejects it. + #[test] + fn forged_neighbor_word_moves_hash_routing() { + let (h, w, k, routing_blocks) = small_geometry(); + let program = compile_forest(h, w, k, routing_blocks); + let mut data = TestData::new(h, w, k, routing_blocks); + let (_, honest_pis) = program.generate_trace::(&data.inputs()); + + data.routing_words[3] += 1; // Unpinned (pins sit at 0 and 16); the gap keeps the order. + let (forged_rows, forged_pis) = program.generate_trace::(&data.inputs()); + assert!( + !constraints_violated(&S::new(program), &forged_rows, &forged_pis), + "a neighbor word is free witness — the AIR must accept its own trace" + ); + let pi_range = PI_HASH_ROUTING..PI_HASH_ROUTING + 8; + assert_ne!( + &forged_pis[pi_range.clone()], + &honest_pis[pi_range], + "the routing root must move with the neighbor word — the public-input pinning rejects the forgery" + ); + } + + #[test] + #[should_panic(expected = "Blake3 program must contain exactly one lottery compression")] + fn validation_requires_a_lottery_compression() { + let (h, w, k, _) = small_geometry(); + let mut program = compile_forest(h, w, k, 0); + assert_eq!(program.instructions.pop().unwrap().bind, Some(Fp16RawPublicBinding::HashJackpot)); + program.validate(); + } + + /// The sparse-opening membership mechanism (deployed auxiliary CVs): a 4-chunk "full + /// matrix" values tree of which only chunks 0/1 (the sampled strip) are hashed in-table; + /// the unopened right subtree enters as one auxiliary sibling CV. The root folds through + /// the A-side commit wrappers, so `HASH_A` must equal the native fold of the *full* + /// matrix's Merkle root — membership of the strip. + fn sparse_opening_setup() -> (Fp16RawBlake3Program, TestData, Vec) { + let full: Vec = (0..4 * BLAKE3_CHUNK_LEN) + .map(|i| ((i as u64).wrapping_mul(0xA24BAED4963EE407) >> 7) as u8) + .collect(); + let opened = full[..2 * BLAKE3_CHUNK_LEN].to_vec(); + + let mut instrs = Vec::new(); + // Chunks 0 and 1 in-table (the a_values "strip" plane), then parent(c0, c1), then the + // root parent against the auxiliary CV of the unopened parent(c2, c3). + let c0c1 = compile_plane_tree(&mut instrs, Fp16RawPlaneId::AValues, opened.len(), 0, true, None); + instrs.push(Fp16RawBlake3Instruction { + cv: Fp16RawCvSource::KeyA, + msg: Fp16RawMessageSource::Parent { + left: Fp16RawCvRef::Instruction(c0c1), + right: Fp16RawCvRef::Auxiliary(0), + }, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags: (B3F_KEYED_HASH | B3F_PARENT | B3F_ROOT) as u32, + bind: None, + egress: None, + }); + let a_values = instrs.len() - 1; + let a_scales = compile_plane_tree(&mut instrs, Fp16RawPlaneId::AScales, 32, 0, false, None); + append_commit_fold(&mut instrs, a_values, a_scales, Fp16RawPublicBinding::HashA, Fp16RawCvSource::KeyA); + instrs.push(Fp16RawBlake3Instruction::lottery()); + let program = Fp16RawBlake3Program { + instructions: instrs, + num_aux_msgs: 0, + num_aux_cvs: 1, + routing_pins: vec![], + moe: None, + msg_pins: Vec::new(), + height_bits: None, + }; + + // Minimal other planes (only a_values carries the membership statement). + let mut data = TestData::new(2, 2, 64, 0); + data.a_values = opened; + data.a_scales = vec![0; 32]; + data.b_values = vec![0; 128]; + data.b_scales = vec![0; 32]; + // The witness sibling: parent CV of the unopened chunks 2 and 3. + let hasher = Blake3Hasher::with_key(words_to_bytes(&data.key_a)); + let c2 = hasher.chunk_cv(&full[2 * BLAKE3_CHUNK_LEN..3 * BLAKE3_CHUNK_LEN], 2); + let c3 = hasher.chunk_cv(&full[3 * BLAKE3_CHUNK_LEN..], 3); + data.aux_cvs = vec![hasher.parent_cv(&c2, &c3)]; + (program, data, full) + } + + #[test] + fn sparse_opening_root_proves_membership_in_full_tree() { + let (program, data, full) = sparse_opening_setup(); + // Only the strip's tree instructions exist: far fewer than the full tree's 64 blocks. + assert_eq!(program.instructions.len(), 2 * 16 + 1 + 1 + 16 + 1 + 1); + let (rows, pis) = program.generate_trace::(&data.inputs()); + + let key = words_to_bytes(&data.key_a); + let expected_hash_a = operand_digest_fp10( + &MerkleTree::new(&full, key).root(), + &MerkleTree::new(&pad_to_chunk_boundary(&data.a_scales), key).root(), + &key, + ); + assert_eq!( + pi_bytes(&pis, PI_HASH_A), + expected_hash_a, + "in-table fold != full-matrix fold" + ); + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + #[test] + fn tampered_aux_cv_breaks_root_binding() { + let (program, mut data, _) = sparse_opening_setup(); + let (_, honest_pis) = program.generate_trace::(&data.inputs()); + // A forged sibling produces a consistent trace whose fold no longer matches the + // public one — the IS_BIND_HASH_A binding must catch it. + data.aux_cvs[0][0] ^= 1; + let (forged_rows, _) = program.generate_trace::(&data.inputs()); + assert!(constraints_violated(&S::new(program), &forged_rows, &honest_pis)); + } + + /// The schedule has exactly `num_aux_cvs` sibling slots, so a padded witness cannot + /// even reach constraint evaluation — there is no separate ZK membership error. + #[test] + #[should_panic(expected = "aux CVs must match the compiled schedule")] + fn extra_aux_cv_cannot_pad_the_witness() { + let (program, mut data, _) = sparse_opening_setup(); + data.aux_cvs.push([0x11; 32]); + let _ = program.generate_trace::(&data.inputs()); + } + + #[test] + #[should_panic(expected = "aux CVs must match the compiled schedule")] + fn missing_aux_cv_is_rejected() { + let (program, mut data, _) = sparse_opening_setup(); + data.aux_cvs.pop(); + let _ = program.generate_trace::(&data.inputs()); + } + + #[test] + fn tampered_state_word_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let stark = S::new(program); + // A state word mid-compression (row 2 of compression 0, STATE1's packed half). + let row: &mut Fp16RawBlake3ColumnsView = rows[2].borrow_mut(); + row.round[1].row1[0] += F::ONE; + assert!( + constraints_violated(&stark, &rows, &pis), + "corrupt state word must break add3" + ); + } + + #[test] + fn tampered_message_byte_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let stark = S::new(program); + // A message byte on a values-plane byte row (compression 0, row 0). + { + let row: &mut Fp16RawBlake3ColumnsView = rows[0].borrow_mut(); + assert_eq!(row.is_int8_message, F::ONE); + row.uint8_data[3] += F::ONE; + } + assert!( + constraints_violated(&stark, &rows, &pis), + "corrupt byte must break the tail load" + ); + } + + #[test] + fn tampered_cv_mux_selector_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + // Clear IS_USE_JACKPOT_KEY on the lottery's row 0 *and* repack ROW_FLAGS_PACKED so only the + // mux itself can catch it: the muxed CV becomes 0 while the committed CV still carries + // JACKPOT_KEY. + let lottery = program + .instructions + .iter() + .position(|i| i.cv == Fp16RawCvSource::JackpotKey) + .unwrap(); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[ROWS_PER_COMPRESSION * lottery].borrow_mut(); + assert_eq!(row.is_use_jackpot_key, F::ONE); + row.is_use_jackpot_key = F::ZERO; + row.row_flags_packed = pack_control(row); + } + let stark = S::new(program); + assert!( + constraints_violated(&stark, &rows, &pis), + "corrupt CV selector must break the mux" + ); + } + + #[test] + fn tampered_rotation_bit_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let stark = S::new(program); + // Flip one bit of a rotated/xored state word (STATE1's row2 bits feed the first + // half-round's xor recomposition and the next add3). + { + let row: &mut Fp16RawBlake3ColumnsView = rows[1].borrow_mut(); + let bit = &mut row.round[1].row2[0][5]; + *bit = F::ONE - *bit; + } + assert!( + constraints_violated(&stark, &rows, &pis), + "flipped rotation bit must break the xor" + ); + } + + #[test] + fn tampered_public_binding_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let lottery = program + .instructions + .iter() + .position(|i| i.bind == Some(Fp16RawPublicBinding::HashJackpot)) + .unwrap(); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[ROWS_PER_COMPRESSION * lottery + 7].borrow_mut(); + assert_eq!(row.is_bind_jackpot_hash, F::ONE); + row.cv_out[0] += F::ONE; + } + let stark = S::new(program); + assert!( + constraints_violated(&stark, &rows, &pis), + "corrupt lottery output must break the HASH_JACKPOT binding" + ); + } + + #[test] + fn tampered_row_counter_breaks_constraints() { + let (h, w, k, r) = small_geometry(); + let (program, _, mut rows, pis) = generate(h, w, k, r); + let stark = S::new(program); + { + let row: &mut Fp16RawBlake3ColumnsView = rows[5].borrow_mut(); + row.trace_row_index += F::ONE; + } + assert!( + constraints_violated(&stark, &rows, &pis), + "corrupt row counter must break the increment" + ); + } + + #[test] + fn degree_is_at_most_three() { + let (h, w, k, r) = small_geometry(); + test_stark_low_degree::(S::new(compile_forest(h, w, k, r))).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + let (h, w, k, r) = small_geometry(); + test_stark_circuit_constraints::(S::new(compile_forest(h, w, k, r))).unwrap(); + } + + // No standalone prove/verify smoke tests: this table is a CTL party (`requires_ctls`), so + // a proof without the cross-table argument is not a supported object — the proof shape + // promises CTL openings the single-table prover has no data for. The end-to-end proving + // path (this table included, sparse openings and all) is covered by + // `fp8::driver::tests::batch_proof_roundtrips_and_rejects_tampering` and + // `api::fp8::zk::tests::api_roundtrip_and_tamper_rejection`; the sparse-opening geometry + // keeps constraint-level coverage above (`sparse_opening_root_proves_membership_in_full_tree`, + // `tampered_aux_cv_breaks_root_binding`). + + /// End-to-end against the deployed pipeline: build a prequantized proof, run the real + /// verifier (`PlainProof::parse_proof`), compile the real `BlakeProgram` from public data, + /// translate it with [`Fp16RawBlake3Program::from_blake_program`], and generate the trace from the + /// verifier's own witness (opened strips + auxiliary blocks/sibling CVs). The bound root + /// public inputs must equal the four committed Merkle roots (the full `m`-row trees, of + /// which only `h`/`w` strips are opened) and every constraint must hold. + #[test] + fn adapter_consumes_deployed_blake_program() { + use crate::api::fp8::plain_proof::PlainProofV4; + use crate::api::fp8::public_params::{CommonParams, Device, HashId, JobParams, OperandParams, Quant}; + use crate::api::layout::{AxisPattern, DimType}; + use crate::api::primitives::{IncompleteBlockHeader, Sides}; + use crate::ffi::plain_proof::MatrixMerkleProof; + // k = 2048, 4×64 tile, 16 Blake lanes. m > h and n > w so every + // plane tree still mixes opened blocks, auxiliary blocks (unopened rows sharing an + // opened chunk) and auxiliary CVs (whole unopened subtrees). + let (m, n, k) = (8usize, 128usize, 2048usize); + let n_blocks = k / BLOCK_SIZE; + let rows_pattern = AxisPattern::new(&[(4, DimType::Blake)]).unwrap(); + let cols_pattern = AxisPattern::new(&[(4, DimType::Blake), (16, DimType::Fold)]).unwrap(); + let a_rows: Vec = rows_pattern.tile_offsets().iter().map(|&o| o as usize).collect(); + let b_rows: Vec = cols_pattern.tile_offsets().iter().map(|&o| o as usize).collect(); + let header = IncompleteBlockHeader::new_for_test(0x207FFFFF); + let (key_a, key_b) = crate::circuit::fp8::consistency::fixture_tree_keys(&header); + let key_a_words = core::array::from_fn(|i| u32::from_le_bytes(key_a[4 * i..4 * i + 4].try_into().unwrap())); + let key_b_words = core::array::from_fn(|i| u32::from_le_bytes(key_b[4 * i..4 * i + 4].try_into().unwrap())); + + let value_tree = |rows: usize, seed: usize| -> Vec> { + (0..rows) + .map(|i| (0..k).map(|j| ((seed + i * k + j) % 251) as u8).collect()) + .collect() + }; + let scale_tree = |rows: usize, seed: usize| -> Vec> { + (0..rows) + .map(|i| { + (0..n_blocks) + .flat_map(|b| (0x3f80u16 + ((seed + i + b) % 16) as u16).to_le_bytes()) + .collect() + }) + .collect() + }; + + let keyed_proof = |rows_bytes: &[Vec], row_indices: &[usize], key: [u8; 32]| -> MatrixMerkleProof { + let flat: Vec = rows_bytes.iter().flatten().copied().collect(); + let tree = MerkleTree::new(&pad_to_chunk_boundary(&flat), key); + let leaves = MerkleTree::compute_leaf_indices_from_rows( + row_indices, + (rows_bytes.len(), rows_bytes[0].len()), + BLAKE3_CHUNK_LEN, + ) + .unwrap(); + MatrixMerkleProof { + proof: tree.get_multileaf_proof(&leaves), + row_indices: row_indices.to_vec(), + } + }; + let proof = PlainProofV4 { + job: JobParams { + // σ̂ and σ_Δ coincide in this fixture (the ancestor is the proposed header). + ancestor_header: header, + common: CommonParams { + k: k as u32, + r: 32, + quant: Quant::Fp8E4M3Prequant, + device: Device::B200, + }, + operands: Sides { + a: OperandParams { + num_rows: m as u32, + hash_id: HashId::Blake3Chunk1024, + pattern: rows_pattern, + }, + b: OperandParams { + num_rows: n as u32, + hash_id: HashId::Blake3Chunk1024, + pattern: cols_pattern, + }, + }, + moe: None, + }, + values: Sides { + a: keyed_proof(&value_tree(m, 0), &a_rows, key_a), + b: keyed_proof(&value_tree(n, 7), &b_rows, key_b), + }, + scales: Sides { + a: keyed_proof(&scale_tree(m, 1), &a_rows, key_a), + b: keyed_proof(&scale_tree(n, 5), &b_rows, key_b), + }, + moe_witness: None, + }; + + // The real verifier: membership-checks everything and extracts the witness. + let (private, public) = proof.parse_proof(&header).expect("fixture must parse"); + let (compiled, _, _) = public.compile(&header).expect("fixture must compile"); + let program = Fp16RawBlake3Program::from_blake_program(&compiled.blake_proof, k, vec![], None); + + // The verifier's witness, adapted: concatenated opened strips per plane, the + // auxiliary material verbatim, arbitrary lottery/POW inputs. + let data = TestData { + a_values: private.operands.a.values.as_bytes().to_vec(), + a_scales: private.operands.a.scales.as_bytes().to_vec(), + b_values: private.operands.b.values.as_bytes().to_vec(), + b_scales: private.operands.b.scales.as_bytes().to_vec(), + routing_words: vec![], + offsets_words: vec![], + aux_msgs: private.external_msgs.clone(), + aux_cvs: private.external_cvs.clone(), + lottery_words: core::array::from_fn(|i| (i as u32).wrapping_mul(0x85EBCA77) ^ 0x1234), + key_a: key_a_words, + key_b: key_b_words, + jackpot_key: core::array::from_fn(|i| 0x3000_0007u32.wrapping_mul(i as u32 + 1)), + }; + let (rows, pis) = program.generate_trace::(&data.inputs()); + + // The bound digests fold the committed full-tree roots — membership of the strips — + // and equal the statement's `hash_a`/`hash_b` (what `parse_proof` computes). + assert_eq!(pi_bytes(&pis, PI_HASH_A), public.hash_a()); + assert_eq!(pi_bytes(&pis, PI_HASH_B), public.hash_b()); + + // The CTL surface covers exactly the opened strips: h*k/8 A-values message rows (8 + // int8 elements each), h*k/32 A-scales rows (4 scales each, 2 bytes per scale). + let (h, w) = (a_rows.len(), b_rows.len()); + let count = |get: fn(&Fp16RawBlake3ColumnsView) -> F| { + rows.iter() + .filter(|r| { + let v: &Fp16RawBlake3ColumnsView = (*r).borrow(); + get(v) == F::ONE + }) + .count() + }; + assert_eq!(count(|v| v.is_int8_message), (h + w) * k / 8); + assert_eq!(count(|v| v.is_scale_message), (h + w) * 2 * n_blocks / 8); + + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + } + + /// The `k % 32` envelope end-to-end at the Blake3 layer, over the REAL wire pipeline. + /// With `k = 2080` (`k % 64 = 32`, and `k ≥ 2048`) the int8 rows are 2080 bytes and the + /// scales rows 520, so committed rows no longer tile into whole 64-byte blocks and the + /// deployed compiler must emit straddling blocks — cross-strip `MatrixLeaf`s where both + /// neighbor rows are opened, `SplitLeaf`s where only one side is (the other side being an + /// unopened row, or the plane's chunk padding). `parse_proof` reruns `evaluate_blake` + /// against the committed Merkle roots, so the chip-level split evaluation is exercised + /// before the trace is built. Checks: the trace binds the committed roots, the CTL + /// surface still covers exactly the opened elements/scales once each, `known_values` + /// reproduces the known columns bit for bit, and every constraint holds. Returns the + /// straddle-kind counts of the compiled schedule so callers can pin their geometry's mix. + fn k_mod_32_adapter_fixture( + m: usize, + n: usize, + k: usize, + a_rows: &[usize], + a_dims: &[(u32, DimType)], + b_rows: &[usize], + b_dims: &[(u32, DimType)], + ) -> (usize, usize, usize) { + use crate::api::fp8::plain_proof::PlainProofV4; + use crate::api::fp8::public_params::{CommonParams, Device, HashId, JobParams, OperandParams, Quant}; + use crate::api::primitives::{IncompleteBlockHeader, Sides}; + use crate::ffi::plain_proof::MatrixMerkleProof; + + assert_eq!(k % 32, 0); + assert_ne!(k % 64, 0, "the fixture exists to exercise straddling rows"); + let n_blocks = k / BLOCK_SIZE; + let rows_pattern = AxisPattern::new(a_dims).unwrap(); + let cols_pattern = AxisPattern::new(b_dims).unwrap(); + let header = IncompleteBlockHeader::new_for_test(0x207FFFFF); + let (key_a, key_b) = crate::circuit::fp8::consistency::fixture_tree_keys(&header); + let key_a_words = core::array::from_fn(|i| u32::from_le_bytes(key_a[4 * i..4 * i + 4].try_into().unwrap())); + let key_b_words = core::array::from_fn(|i| u32::from_le_bytes(key_b[4 * i..4 * i + 4].try_into().unwrap())); + + let value_tree = |rows: usize, seed: usize| -> Vec> { + (0..rows) + .map(|i| (0..k).map(|j| ((seed + i * k + j) % 251) as u8).collect()) + .collect() + }; + let scale_tree = |rows: usize, seed: usize| -> Vec> { + (0..rows) + .map(|i| { + (0..n_blocks) + .flat_map(|b| (0x3f80u16 + ((seed + i + b) % 16) as u16).to_le_bytes()) + .collect() + }) + .collect() + }; + let keyed_proof = |rows_bytes: &[Vec], row_indices: &[usize], key: [u8; 32]| -> MatrixMerkleProof { + let flat: Vec = rows_bytes.iter().flatten().copied().collect(); + let tree = MerkleTree::new(&pad_to_chunk_boundary(&flat), key); + let leaves = MerkleTree::compute_leaf_indices_from_rows( + row_indices, + (rows_bytes.len(), rows_bytes[0].len()), + BLAKE3_CHUNK_LEN, + ) + .unwrap(); + MatrixMerkleProof { + proof: tree.get_multileaf_proof(&leaves), + row_indices: row_indices.to_vec(), + } + }; + let proof = PlainProofV4 { + job: JobParams { + // σ̂ and σ_Δ coincide in this fixture (the ancestor is the proposed header). + ancestor_header: header, + common: CommonParams { + k: k as u32, + r: 32, + quant: Quant::Fp8E4M3Prequant, + device: Device::B200, + }, + operands: Sides { + a: OperandParams { + num_rows: m as u32, + hash_id: HashId::Blake3Chunk1024, + pattern: rows_pattern, + }, + b: OperandParams { + num_rows: n as u32, + hash_id: HashId::Blake3Chunk1024, + pattern: cols_pattern, + }, + }, + moe: None, + }, + values: Sides { + a: keyed_proof(&value_tree(m, 0), a_rows, key_a), + b: keyed_proof(&value_tree(n, 7), b_rows, key_b), + }, + scales: Sides { + a: keyed_proof(&scale_tree(m, 1), a_rows, key_a), + b: keyed_proof(&scale_tree(n, 5), b_rows, key_b), + }, + moe_witness: None, + }; + + // The real verifier: the wire layer now admits k % 32 == 0, membership-checks the + // trees, and reruns the (split-aware) compiled program natively against the roots. + let (private, public) = proof.parse_proof(&header).expect("k % 32 fixture must parse"); + let (compiled, _, _) = public.compile(&header).expect("fixture must compile"); + let program = Fp16RawBlake3Program::from_blake_program(&compiled.blake_proof, k, vec![], None); + + // Tally the straddle kinds the schedule produced (returned for per-geometry pins). + let (mut cross_strip, mut split_opened_first, mut split_unopened_first) = (0usize, 0usize, 0usize); + for instr in &program.instructions { + match instr.msg { + Fp16RawMessageSource::PlaneBytes { plane, offset, .. } + if plane != Fp16RawPlaneId::Routing && { + let row_bytes = match plane { + Fp16RawPlaneId::AValues | Fp16RawPlaneId::BValues => k, + _ => k / 4, + }; + offset / row_bytes != (offset + BLAKE3_MSG_LEN - 1) / row_bytes + } => + { + cross_strip += 1; + } + Fp16RawMessageSource::PlaneBytesSplit { skip: 0, .. } => split_opened_first += 1, + Fp16RawMessageSource::PlaneBytesSplit { .. } => split_unopened_first += 1, + _ => {} + } + } + + let data = TestData { + a_values: private.operands.a.values.as_bytes().to_vec(), + a_scales: private.operands.a.scales.as_bytes().to_vec(), + b_values: private.operands.b.values.as_bytes().to_vec(), + b_scales: private.operands.b.scales.as_bytes().to_vec(), + routing_words: vec![], + offsets_words: vec![], + aux_msgs: private.external_msgs.clone(), + aux_cvs: private.external_cvs.clone(), + lottery_words: core::array::from_fn(|i| (i as u32).wrapping_mul(0x85EBCA77) ^ 0x1234), + key_a: key_a_words, + key_b: key_b_words, + jackpot_key: core::array::from_fn(|i| 0x3000_0007u32.wrapping_mul(i as u32 + 1)), + }; + let (rows, pis) = program.generate_trace::(&data.inputs()); + + // Committed-root binding through the straddling schedule: the bound digests fold + // the committed roots and equal the statement's `hash_a`/`hash_b`. + assert_eq!(pi_bytes(&pis, PI_HASH_A), public.hash_a()); + assert_eq!(pi_bytes(&pis, PI_HASH_B), public.hash_b()); + + // The CTL surface covers exactly the opened strips, split dwords included: every + // element / scale crosses exactly once, none of the unopened-neighbor bytes do. + let (h, w) = (a_rows.len(), b_rows.len()); + let count = |get: fn(&Fp16RawBlake3ColumnsView) -> F| { + rows.iter() + .filter(|r| { + let v: &Fp16RawBlake3ColumnsView = (*r).borrow(); + get(v) == F::ONE + }) + .count() + }; + assert_eq!(count(|v| v.is_int8_message), (h + w) * k / 8); + assert_eq!(count(|v| v.is_scale_message), (h + w) * 2 * n_blocks / 8); + // ... at pairwise-distinct keys: with per-key uniqueness, the counts above pin the + // exposed key sets to exactly [0, h*k) + [h*k, (h+w)*k) (values) and the block range + // (scales), matching InputQuant's demand multiset. + let mut value_keys: Vec = Vec::new(); + let mut scale_keys: Vec = Vec::new(); + for r in rows.iter() { + let v: &Fp16RawBlake3ColumnsView = r.borrow(); + if v.is_int8_message == F::ONE { + value_keys.push(v.ctl_key_base.to_canonical_u64()); + } + if v.is_scale_message == F::ONE { + scale_keys.push(v.ctl_key_base.to_canonical_u64()); + } + } + value_keys.sort_unstable(); + scale_keys.sort_unstable(); + assert!(value_keys.iter().enumerate().all(|(i, &b)| b == 8 * i as u64)); + assert!(scale_keys.iter().enumerate().all(|(i, &b)| b == 4 * i as u64)); + + // The class (a) recompute is bit-exact with the trace, split rows included. + let known = program.known_values::(&data.inputs().known_inputs()); + assert_eq!(known.len(), NUM_FP16_RAW_BLAKE3_KNOWN_COLUMNS); + for (c, column) in known.iter().enumerate() { + for (r, row) in rows.iter().enumerate() { + assert_eq!(column.values[r], row[c], "known column {c} differs from trace at row {r}"); + } + } + + assert!(!constraints_violated(&S::new(program), &rows, &pis)); + (cross_strip, split_opened_first, split_unopened_first) + } + + /// `k = 2080`, 8×32 tile: A opens the contiguous band `{0..7}` (cross-strip + /// blocks at even|odd row boundaries) and B the isolated odd rows `{1,3,…,63}` (fold + /// `{0,2,4,6}` (+) blake `{0,8,…,56}`, based at 1) of `n = 64`. Odd B rows start + /// mid-block against unopened even neighbors (`skip > 0` splits); the 520-byte scales + /// rows add opened-first splits (`skip = 0`). + #[test] + fn adapter_handles_row_straddling_blocks_at_k_mod_32() { + let a_rows: Vec = (0..8).collect(); + let b_rows: Vec = (0..32).map(|i| 1 + 2 * i).collect(); + let (cross, opened_first, unopened_first) = k_mod_32_adapter_fixture( + 8, + 64, + 2080, + &a_rows, + &[(4, DimType::Fold), (2, DimType::Blake)], + &b_rows, + &[(2, DimType::Null), (4, DimType::Fold), (8, DimType::Blake)], + ); + assert!(cross > 0, "adjacent opened rows must yield cross-strip blocks"); + assert!(opened_first > 0, "opened-tail blocks must yield skip = 0 splits"); + assert!(unopened_first > 0, "opened-head blocks must yield skip > 0 splits"); + } + + /// `m = 17` (odd) with every A row opened: the raw A plane ends mid-block + /// (`17 * 2080 ≡ 32 (mod 64)`), so row 16's tail block straddles into the chunk padding — + /// an opened-first split whose auxiliary half carries the padding zeros. B keeps the + /// isolated-odd 32-col tile so values-plane splits against unopened neighbors still appear. + #[test] + fn adapter_handles_straddle_into_chunk_padding() { + let a_rows: Vec = (0..17).collect(); + let b_rows: Vec = (0..32).map(|i| 1 + 2 * i).collect(); + let (_, opened_first, unopened_first) = k_mod_32_adapter_fixture( + 17, + 64, + 2080, + &a_rows, + &[(17, DimType::Fold)], + &b_rows, + &[(2, DimType::Null), (2, DimType::Fold), (16, DimType::Blake)], + ); + assert!(opened_first > 0, "the raw-tail block must split into the chunk padding"); + assert!(unopened_first > 0); + } + + /// The scheme boundary: an Int7 job's `BlakeProgram` — with no scales sections — must be + /// rejected by the adapter. Int7 is being disabled protocol-wide; nothing Int7-shaped + /// may acquire an fp8 schedule. + #[test] + #[should_panic(expected = "not a prequant four-plane program")] + fn adapter_rejects_legacy_int7_programs() { + let h = 16; + let w = 16; + let k = 2048; + let blake_proof = chip_program::BlakeProgram { + num_a_rows: h, + num_b_cols: w, + strip_length: k, + num_routing_strips: 0, + num_offsets_strips: 0, + num_auxiliary_msgs: 0, + num_auxiliary_cvs: 0, + instructions: vec![], + }; + let _ = Fp16RawBlake3Program::from_blake_program(&blake_proof, k, vec![], None); + } +} diff --git a/zk-pow/src/circuit/fp16/consistency.rs b/zk-pow/src/circuit/fp16/consistency.rs new file mode 100644 index 000000000..85a7ca99b --- /dev/null +++ b/zk-pow/src/circuit/fp16/consistency.rs @@ -0,0 +1,279 @@ +//! One FP16 tile, six traces, every CTL channel balanced — and an end-to-end batched-FRI proof. +//! +//! This is the FP16 analogue of `crate::circuit::fp8::consistency`. It builds an honest, +//! policy-accepting tile from the GPU reference vectors, generates the matmul and policy traces +//! and the four committed-LUT traces, and exercises two drivers: +//! +//! - [`one_fp16_job_balances_every_ctl_channel`]: every AIR's constraints on its own trace, every +//! committed-LUT instance served ([`LutChecker`]), and all five CTL channels balanced over the +//! full six-table batch (`check_ctls`) — the four LUT channels and the `matmul -> policy` +//! census import; +//! - [`batched_fp16_proof_roundtrips_and_rejects_tampering`]: the real +//! [`Fp16System`] batched proof — it generates, verifies, and rejects a tampered trace cell, a +//! forged per-step census value, and a forged decode column. + +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::util::timing::TimingTree; +use starky::constraint_consumer::ConstraintConsumer; +use starky::cross_table_lookup::debug_utils::check_ctls; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::ctl::{ + BLAKE3_A100_TABLE, MATMUL_A100_TABLE, NUM_FP16_TABLES, POLICY_A100_TABLE, XOR_FOLD_A100_TABLE, + all_cross_table_lookups, +}; +use super::driver::{Fp16System, default_lane_layout, fp16_noised_operands}; +use super::matmul_a100_stark::columns::MATMUL_A100_COL_MAP; +use super::matmul_a100_stark::stark::MatmulStarkA100; +use super::policy_stark::columns::POLICY_A100_COL_MAP; +use super::policy_stark::stark::PolicyStarkA100; +use super::xor_fold_stark::columns::XOR_FOLD_COL_MAP; +use crate::api::fp16::accumulate::{GROUP as ACC_GROUP, a100_dot}; +use crate::api::fp16::policy::replay_and_evaluate; +use crate::api::fp8::transcript::{compute_jackpot_ticket, jackpot_key}; +use crate::api::fp8::utils::xor_fold_extract; +use crate::api::layout::lane_assignment; +use crate::api::primitives::Hash256; +use crate::circuit::fp8::blake3_stark::columns::PI_HASH_JACKPOT; + +type F = GoldilocksField; +type C = PoseidonGoldilocksConfig; +const D: usize = 2; +type S = MatmulStarkA100; +type P = PolicyStarkA100; + +const VECTORS: &str = include_str!("../../api/fp16/testdata/a100_dot_vectors.txt"); + +/// A small accepting `1 x 1 x k` tile from the GPU reference vectors: operands that clear the +/// policy gate (nonnegative slacks, in-domain RANGE16 limbs) and whose matmul output is normal. +/// `min_k` lets callers pick a tile tall enough to cover the FRI Merkle cap. +fn accepting_tile(min_k: usize) -> (usize, Vec, Vec) { + let mut best: Option<(usize, Vec, Vec)> = None; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % ACC_GROUP != 0 || k < min_k { + continue; + } + // Prefer the smallest qualifying k (fastest FRI). + if best.as_ref().is_some_and(|(bk, _, _)| k >= *bk) { + continue; + } + let a0: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b0: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + // The batch's matmul/policy are over the NOISED operands, so the gate must clear on the + // noised 4x4 tile (the tile shape the capstone test proves). + let (a, b) = (a0.repeat(4), b0.repeat(4)); + let Ok((noised_a, noised_b)) = fp16_noised_operands(4, 4, k, &a, &b, KEY_A, KEY_B, OP_HASH_ID, OP_HASH_ID) else { continue }; + if replay_and_evaluate(&noised_a, &noised_b, 4, 4, k).1.accept { + best = Some((k, a0, b0)); + } + } + best.unwrap_or_else(|| panic!("reference vectors must contain a cell whose noised 4x4 tile accepts with k >= {min_k}")) +} + +/// Replicates one accepting cell `(a, b)` into an `h x w` tile: `a` on every A row, `b` on every +/// B column. Every cell then replays the same accepting dot product, so the whole tile clears the +/// policy gate (both ratios are averages of identical cells). Returns `(a_full, b_full)`. +fn replicate(a: &[u16], b: &[u16], h: usize, w: usize) -> (Vec, Vec) { + (a.repeat(h), b.repeat(w)) +} + +/// Runs every constraint of `$stark` over every row pair of its own trace with starky's +/// `z_last`/`L_first`/`L_last` semantics (transitions excluded on the last -> first wrap). +macro_rules! assert_constraints { + ($stark:expr, $rows:expr, $name:literal) => {{ + let stark = $stark; + let n = $rows.len(); + for i in 0..n { + let frame = StarkFrame::from_values(&$rows[i], &$rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + assert!( + consumer.accumulators().into_iter().all(|acc| acc == F::ZERO), + "{} constraints violated at row {i}", + $name + ); + } + }}; +} + +/// A fixed noise seed for the jackpot key derivation in these tests. +const SEED_A: Hash256 = [0x5a; 32]; +/// Operand-tree opening keys and leaf size for these tests (passed in; the seed-chain derivation is +/// a later increment). `Blake3Chunk512` keeps the Blake3 table's height a power of two the config +/// handles natively. +const KEY_A: Hash256 = [0x11; 32]; +const KEY_B: Hash256 = [0x22; 32]; +const OP_HASH_ID: crate::api::fp8::public_params::HashId = crate::api::fp8::public_params::HashId::Blake3Chunk512; + +/// The 32-byte jackpot digest the plaintext extractor produces for the `h x w` tile whose cell +/// `(r, c)` is the A100 dot of the NOISED operand rows `(noised_a[r], noised_b[c])` — the same noised +/// operands the batch's matmul multiplies: fold the tile under the committed lane layout, then +/// `compute_jackpot_ticket`. The committed ZK `HASH_JACKPOT` must equal this bit-for-bit. +fn plaintext_jackpot(noised_a: &[u16], noised_b: &[u16], h: usize, w: usize, k: usize) -> Hash256 { + let mut tile = vec![0f32; h * w]; + for r in 0..h { + for c in 0..w { + tile[r * w + c] = a100_dot(&noised_a[r * k..r * k + k], &noised_b[c * k..c * k + k], 0.0, None); + } + } + let (row_axis, col_axis) = default_lane_layout(h, w); + let lanes = lane_assignment(&row_axis, &col_axis); + let msg = xor_fold_extract(&tile, &lanes); + compute_jackpot_ticket(&SEED_A, &msg).jackpot +} + +/// 32-byte digest -> 8 LE `u32` field words, the Blake3 public-input form of `HASH_JACKPOT`. +fn hash_to_words(h: &Hash256) -> Vec { + (0..8) + .map(|i| F::from_canonical_u32(u32::from_le_bytes(h[4 * i..4 * i + 4].try_into().unwrap()))) + .collect() +} + +/// The channel-balance driver: every AIR satisfied on its own trace, every committed-LUT instance +/// served, and all CTL channels balanced over the full nine-table batch. +#[test] +fn one_fp16_job_balances_every_ctl_channel() { + // A 4x4 tile replicated from one accepting cell: 16 output cells, one per lottery lane. + let (k, a0, b0) = accepting_tile(16); + let (a, b) = replicate(&a0, &b0, 4, 4); + let matmul = S::new(4, 4, k); + let policy = P::new(4, 4, k); + + // Every AIR satisfied on its own trace — over the NOISED operands the batch's matmul/policy + // multiply (the quant chain's `out`), so the policy gate clears exactly as in the batch. + let (noised_a, noised_b) = + fp16_noised_operands(4, 4, k, &a, &b, KEY_A, KEY_B, OP_HASH_ID, OP_HASH_ID).expect("in-envelope noised operands"); + assert_constraints!(&matmul, &matmul.generate_trace(&noised_a, &noised_b, None), "MatmulA100"); + assert_constraints!(&policy, &policy.generate_trace(&noised_a, &noised_b), "PolicyA100"); + + // The driver assembles all nine traces (committed-LUT serving re-checked inside). + let system = Fp16System::::new(4, 4, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let (traces, blake3_pis) = system + .generate_batch_traces(&a, &b, KEY_A, KEY_B, jk) + .expect("every honest instance must be served"); + assert_eq!(traces.len(), NUM_FP16_TABLES); + + // Every CTL channel balances: the five LUT channels, the census-import channel, the matmul -> + // XorFold cell-results and XorFold -> Blake3 lottery-words channels, the two internal quant-chain + // channels, and the two operand-provenance channels (operand bytes [6c], operand codes [6d]). + let mut all_pis: Vec> = vec![Vec::new(); NUM_FP16_TABLES]; + all_pis[BLAKE3_A100_TABLE] = blake3_pis; + check_ctls(&traces.to_vec(), &all_pis, &all_cross_table_lookups::(4, 4, k), &Default::default()); +} + +/// The capstone: a real batched-FRI proof of an honest tile generates and verifies, `HASH_JACKPOT` +/// equals the plaintext jackpot, and tampering (a trace cell, a policy census, a decode column) is +/// rejected by the batch verifier. +#[test] +fn batched_fp16_proof_roundtrips_and_rejects_tampering() { + // A 4x4 tile (replicated accepting cell): 16 output cells feeding the 16 lottery lanes; the + // 2^16 committed LUTs dominate the proof cost regardless. + let (k, a0, b0) = accepting_tile(16); + let (a, b) = replicate(&a0, &b0, 4, 4); + let (h, w) = (4usize, 4usize); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- Honest proof: generates and verifies. ---- + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system + .verify::(&proof, &blake3_pis, &lut_cap) + .expect("honest FP16 proof must verify"); + + // HASH_JACKPOT is bit-exact with the plaintext extractor -> jackpot transcript over the NOISED + // operands the matmul multiplies (the quant chain's `out`). + let (noised_a, noised_b) = system.noised_operands(&a, &b, KEY_A, KEY_B); + let expected = plaintext_jackpot(&noised_a, &noised_b, h, w, k); + assert_eq!( + &blake3_pis[PI_HASH_JACKPOT..PI_HASH_JACKPOT + 8], + hash_to_words(&expected).as_slice(), + "committed HASH_JACKPOT must equal the plaintext jackpot" + ); + + // ---- Tampering: mutate one honest trace cell (keeping the honest LUT multiplicities), prove, + // and assert the batch verifier rejects. ---- + let m = &MATMUL_A100_COL_MAP; + let p = &POLICY_A100_COL_MAP; + let xf = &XOR_FOLD_COL_MAP; + + let (honest, _) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + let mat_live = (0..system.num_rows() - 1) + .find(|&r| { + honest[MATMUL_A100_TABLE][m.is_padding].values[r] == F::ZERO + && honest[MATMUL_A100_TABLE][m.group_sum_is_zero].values[r] == F::ZERO + && honest[MATMUL_A100_TABLE][m.is_cell_final].values[r] == F::ZERO + }) + .expect("a live mid-cell matmul row"); + let pol_live = (0..system.num_rows()) + .find(|&r| honest[POLICY_A100_TABLE][p.is_padding].values[r] == F::ZERO) + .expect("a live policy row"); + // A live (non-padding) XorFold row carries a folded cell word. + let xf_rows = honest[XOR_FOLD_A100_TABLE][xf.is_pad].values.len(); + let xf_live = (0..xf_rows) + .find(|&r| honest[XOR_FOLD_A100_TABLE][xf.is_pad].values[r] == F::ZERO) + .expect("a live XorFold row"); + + let prove_tampered = |col_table: usize, col: usize, row: usize| { + let (mut traces, blake3_pis) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + traces[col_table][col].values[row] += F::ONE; + let mut timing = TimingTree::default(); + // The prover may succeed (it does not re-check constraints), but verification must fail. + match system.prove_batch_traces::(traces, &blake3_pis, &preprocessed, &mut timing) { + Ok(bad) => system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + Err(_) => true, // the prover itself refused the malformed trace + } + }; + + // (a) a trace cell: the accumulated group-sum magnitude (MA5 arithmetic). + assert!( + prove_tampered(MATMUL_A100_TABLE, m.group_sum_abs, mat_live), + "a tampered matmul trace cell must be rejected" + ); + // (b) a census value: the policy's per-step breakpoint (census-import channel + PP gate). + assert!( + prove_tampered(POLICY_A100_TABLE, p.group_breakpoint, pol_live), + "a forged policy census value must be rejected" + ); + // (c) a decode column the LUTs are responsible for: a lane significand (FP16DECODE channel). + assert!( + prove_tampered(MATMUL_A100_TABLE, m.sig_a[1], mat_live), + "a forged decode column must be rejected by the FP16DECODE CTL" + ); + // (d) the matmul output tile a cell feeds into the lottery: tampering a XorFold cell-result limb + // unbalances the matmul -> XorFold cell-results channel. (The full output -> jackpot chain, + // including a tampered lottery word, is exercised by the driver end-to-end test.) + assert!( + prove_tampered(XOR_FOLD_A100_TABLE, xf.cell_result_f32_lo, xf_live), + "a tampered folded cell word must be rejected by the cell-results CTL" + ); + + // (e) a mismatched statement: verifying the honest proof against a different geometry must fail + // on the degree-profile / known-column binding. + let other = Fp16System::::new(h, w, k * 2, OP_HASH_ID, OP_HASH_ID); + let other_prep = other.preprocessed_data::(&mut TimingTree::default()); + assert!( + other.verify::(&proof, &blake3_pis, &other_prep.cap()).is_err(), + "a proof must not verify against a different statement" + ); +} diff --git a/zk-pow/src/circuit/fp16/ctl.rs b/zk-pow/src/circuit/fp16/ctl.rs new file mode 100644 index 000000000..29de39393 --- /dev/null +++ b/zk-pow/src/circuit/fp16/ctl.rs @@ -0,0 +1,787 @@ +//! Cross-table lookups of the FP16 / A100 multi-STARK batch. +//! +//! The FP16 batch is wire-separate from the FP8 system (it does not extend the FP8 `Table`/`Device` +//! enums). It has eight main tables — the A100 matmul AIR (0), the rho/breakpoint policy AIR (1), the +//! XorFold lottery mixer (2), the Blake3 jackpot commitment (3), the three quantization-chain +//! AIRs: the per-row scale derivation (4), the fused noisy-quant G1/G3 roundings (5), and the +//! single-rounding G2 FMA (6), and the noise matmul AIR (`N = E@F^T`, 7) — plus the five committed +//! LUTs their auxiliary columns are served by. +//! Each LUT is its own AIR of the batch; its channel's looking side collects every instance of all +//! main tables' inventories and its looked side is the LUT's slots filtered by their per-proof +//! multiplicity columns. This is what makes each main STARK's own verification enforce its +//! decode/shift/width/byte-range auxiliary columns. +//! +//! On top of the LUT channels there are seven main-table channels: the matmul -> policy census +//! import, the matmul -> XorFold **cell results** (binding the proven output tile to the folded +//! lottery lanes), the XorFold -> Blake3 **lottery words** (binding the 16 lane outputs to the +//! jackpot message, hence to the `HASH_JACKPOT` public input), the two internal quant-chain +//! channels (the row-scale -> noisy-quant **scales** import and the G1/G3 <-> G2 **FMA pairing**), +//! and the two operand-provenance channels (increments 6c/6d) that close audit Finding 3: the +//! Blake3 -> noisy-quant **operand bytes** (committed byte pair `== raw`, keyed by byte offset) and +//! the matmul -> noisy-quant **operand codes** (matmul code `== noised out`, keyed by element index +//! with the `w`/`h` reuse multiplicity). The first three bind the matmul output tile to +//! `HASH_JACKPOT`; the next two prove the noised-operand arithmetic `noised = Q(alpha*raw + beta*N)` +//! end to end in-batch; the last two bind that one operand set end to end — committed bytes (Blake3) +//! `== raw` (quant) `--Q-->` `out` (quant) `== matmul operand codes` — so the matmul provably +//! multiplies the noised quantization of the committed operands. The noise `N` is now bound too +//! (increment 6e-1): a second matmul instance (table 7) proves `N = E@F^T` in-batch and the +//! noise-word channel binds its cell results to the noise noisy-quant consumes (keyed by element +//! index). The noise derivation itself is now bound too (increment 6e-3, CLOSED): the forked BLAKE3 +//! AIR (`blake3_fp16_stark`) egresses each noise line's keyed-XOF bytes and the noise-BLAKE3 egress +//! CTL binds them to the seeds derived from the committed operand roots, so `E`/`F` are no longer +//! free witness and the noise is not grindable. +//! +//! The committed LUTs reuse the FP8 [`LutStark`](crate::circuit::fp8::luts::LutStark) machinery: +//! `RANGE16`, `WIDTH32` and `BYTES2` are the very FP8 tables (`BYTES2` serves the Blake3 AIR's +//! message-byte range checks); `FP16DECODE` and `FP16POW2` are new [`LutTable`] variants (serving +//! FP16's `2^16`-key operand decode and its wider alignment power-of-two) that no FP8 device commits, +//! so the FP8 consensus layout is untouched. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{CrossTableLookup, TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::blake3_commit::{ctl_lottery_words_looking_blake3, ctl_operand_bytes_looking_blake3}; +use super::blake3_fp16_stark::ctl::{blake3_lut_lookups as noise_blake3_lut_lookups, ctl_cv_egress_looking_blake3}; +use super::matmul_a100_stark::columns::MATMUL_A100_COL_MAP; +use super::matmul_a100_stark::ctl::{ + ctl_cell_results_looked_matmul, ctl_cell_results_looked_matmul_offset, ctl_operand_codes_looking_matmul, + ctl_operand_codes_looking_matmul_offset, matmul_a100_lut_lookups, +}; +use super::noise_stark::ctl::{ctl_noise_egress_pair_looked, ctl_noise_operands_looked, noise_lut_lookups}; +use super::noisy_quant_fma_stark::ctl::{ctl_fma_pairing_looking, fma_lut_lookups}; +use super::noisy_quant_stark::columns::NOISY_QUANT_COL_MAP; +use super::noisy_quant_stark::ctl::{ + ctl_fma_hook_looking, ctl_noise_word_looked_noisy_quant, ctl_operand_bytes_looked_noisy_quant, + ctl_operand_codes_looked_noisy_quant, noisy_quant_lut_lookups, +}; +use super::policy_stark::columns::POLICY_A100_COL_MAP; +use super::policy_stark::ctl::policy_a100_lut_lookups; +use super::row_scale_stark::columns::ROW_SCALE_COL_MAP; +use super::row_scale_stark::ctl::row_scale_lut_lookups; +use super::xor_fold_stark::ctl::{ + ctl_cell_results_looking_xor_fold, ctl_lottery_words_looked_xor_fold, xor_fold_lut_lookups, +}; +use crate::circuit::fp8::blake3_stark::ctl::blake3_lut_lookups; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::columns::num_slots; +use crate::circuit::fp8::luts::ctl::LutLookup; +use crate::circuit::fp8::luts::ctl_looked_lut_slot; + +/// The A100 matmul AIR is table 0 of the FP16 batch. +pub const MATMUL_A100_TABLE: usize = 0; + +/// The FP16 rho/breakpoint policy AIR is table 1 of the FP16 batch. +pub const POLICY_A100_TABLE: usize = 1; + +/// The FP16 XorFold lottery-mixer AIR is table 2 of the FP16 batch. +pub const XOR_FOLD_A100_TABLE: usize = 2; + +/// The FP16 Blake3 jackpot-commitment AIR is table 3 of the FP16 batch. +pub const BLAKE3_A100_TABLE: usize = 3; + +/// The FP16 per-row scale-derivation AIR is table 4 of the FP16 batch (quant chain, increment 6b). +pub const ROW_SCALE_A100_TABLE: usize = 4; + +/// The FP16 fused noisy-quantization AIR (G1 + G3) is table 5 of the FP16 batch (increment 6b). +pub const NOISY_QUANT_A100_TABLE: usize = 5; + +/// The FP16 single-rounding FMA AIR (G2) is table 6 of the FP16 batch (increment 6b). +pub const NOISY_QUANT_FMA_A100_TABLE: usize = 6; + +/// The A-side FP16 noise matmul AIR (`N_A = E_A @ F_A^T`, output `h x k`, inner `r`) is table 7 of +/// the FP16 batch (increment 6e-2). A [`super::matmul_a100_stark::MatmulStarkA100`] instance whose +/// proven cell results are the A-side noise matrix noisy-quant's G1 rounding consumes; the noise-word +/// CTL binds them to noisy-quant's `(NOISE_LO, NOISE_HI)`. Its `E_A`/`F_A` operands are bound to +/// NoiseStark's proven normalized lines by the E/F-operand channel (6e-2), so they are the real, +/// distinct seed-derived lines (seed-keyed-XOF binding is 6e-3). +pub const NOISE_MATMUL_A_A100_TABLE: usize = 7; + +/// The B-side FP16 noise matmul AIR (`N_B = E_B @ F_B^T`, output `w x k`, inner `r`) is table 8 of the +/// FP16 batch (increment 6e-2). Restoring the plaintext's DISTINCT `F_A`/`F_B` (6e-1 used one shared +/// `F`): B keys `F_B` off `Side::B`, so `N_B` matches `sample_noise` bit-for-bit. Its cell results +/// bind to noisy-quant's B-side noise words (cell-id offset `h*k`), its `E_B`/`F_B` operands to +/// NoiseStark (index offset `(h+k)*r`). +pub const NOISE_MATMUL_B_A100_TABLE: usize = 8; + +/// The FP16 noise-line normalization AIR (NoiseStark) is table 9 of the FP16 batch (increment 6e-2). +/// It proves `normalize_line` for every noise line of the tile (`E_A`, `F_A`, `E_B`, `F_B`) and binds +/// its normalized FP16 output to the two noise matmuls' `E`/`F` operands. In increment 6e-3c its raw +/// XOF bytes are no longer free witness: the egress-pair CTL binds them to the noise-BLAKE3 table. +pub const NOISE_STARK_A100_TABLE: usize = 9; + +/// The FP16 noise-BLAKE3 derivation AIR (forked engine) is table 10 of the FP16 batch (increment +/// 6e-3c). It recomputes every noise line's keyed-BLAKE3-XOF bytes in-circuit from the noise seeds +/// (its `KEY_A`/`KEY_B` public inputs): two subkey compressions then `h+w+2k` per-line compressions, +/// each keyed by the line's subkey and egressing its `cv_out`. The egress-pair CTL binds those +/// `cv_out` limbs to NoiseStark's XOF-byte inputs, so the noise is no longer grindable through those +/// bytes. Every message block is pinned to its public constant via the engine's message-word pins. +pub const NOISE_BLAKE3_A100_TABLE: usize = 10; + +/// Number of FP16 main (non-LUT) tables: the A100 matmul AIR, the policy AIR, the XorFold lottery +/// mixer, the Blake3 jackpot commitment, the three quantization-chain AIRs (row-scale, G1/G3 +/// noisy-quant, G2 FMA), the two noise matmul AIRs (`N_A`/`N_B`), the NoiseStark line AIR, and the +/// noise-BLAKE3 derivation AIR (6e-3c). +pub const NUM_FP16_MAIN_TABLES: usize = 11; + +/// The committed LUTs of the FP16 batch, in descending committed height (the batch order; FRI +/// folds by height internally). `FP16DECODE`/`RANGE16`/`BYTES2` are `2^16` tall, `FP16POW2` is +/// `256`, `WIDTH32` is `32`. `BYTES2` serves the Blake3 AIR's message-byte range checks (the +/// `blake3_lut_lookups` BYTES2 instances); it is the FP8 byte-pair table, committed by no FP8 device +/// change here. +pub const FP16_LUT_TABLES: [LutTable; NUM_FP16_LUT_TABLES] = [ + LutTable::Fp16Decode, + LutTable::Range16, + LutTable::Bytes2, + LutTable::Fp16Pow2, + LutTable::Width32, +]; + +/// Number of committed LUT tables in the FP16 batch. +pub const NUM_FP16_LUT_TABLES: usize = 5; + +/// Total tables of the FP16 batch: the eight main tables, then the five LUTs. +pub const NUM_FP16_TABLES: usize = NUM_FP16_MAIN_TABLES + NUM_FP16_LUT_TABLES; + +/// Number of CTL channels: one per committed LUT, plus the nine main-table channels (matmul -> +/// policy census import, matmul -> XorFold cell results, XorFold -> Blake3 lottery words, the two +/// internal quant-chain channels (row-scale -> noisy-quant scales, G1/G3 <-> G2 FMA pairing), the +/// two operand-provenance channels (Blake3 -> noisy-quant operand bytes [6c], matmul -> noisy-quant +/// operand codes [6d]), the noise-word channel (both noise matmuls -> noisy-quant `N` [6e-1/6e-2]), +/// and the E/F-operand channel (both noise matmuls' `E`/`F` -> NoiseStark normalized lines [6e-2])). +pub const NUM_FP16_CTL_CHANNELS: usize = NUM_FP16_LUT_TABLES + 10; + +/// Batch table index of the `i`-th committed LUT (LUTs follow the main tables). +pub const fn fp16_lut_table_idx(i: usize) -> usize { + NUM_FP16_MAIN_TABLES + i +} + +/// The matmul -> policy census-import cross-table lookup (gap 3 linkage). The matmul AIR exports, +/// per live group step, the tuple `(operand_index_base_a, operand_index_base_b, group_breakpoint, +/// sum products_truncated_flag)`; the policy AIR imports the same tuple on its matching row. The +/// `(base_a, base_b)` pair is unique per live row (base_a fixes `(r, j)`, base_b fixes `(c, j)`), +/// so the multiset equality forces the policy's per-step census to equal the matmul's +/// bit-exactly — the policy can no longer score a census different from the one the matmul proved. +/// Both sides are filtered to live rows (`1 - is_padding`). +pub fn census_import_ctl() -> CrossTableLookup { + let m = &MATMUL_A100_COL_MAP; + let p = &POLICY_A100_COL_MAP; + let one = F::ONE; + let neg = -F::ONE; + + // Matmul (looking): keys (base_a, base_b); values (group_breakpoint, sum of the 8 lane + // products-truncated flags). The sum is a plain linear combination of the flag columns. + let matmul_pt_sum = Column::linear_combination(m.products_truncated_flag.iter().map(|&c| (c, one))); + let looking = TableWithColumns::new( + TableIdx::from(MATMUL_A100_TABLE), + vec![ + Column::single(m.operand_index_base_a), + Column::single(m.operand_index_base_b), + Column::single(m.group_breakpoint), + matmul_pt_sum, + ], + Filter::from_column(Column::linear_combination_with_constant([(m.is_padding, neg)], one)), + ); + + // Policy (looked): the same tuple on the same grid. + let looked = TableWithColumns::new( + TableIdx::from(POLICY_A100_TABLE), + vec![ + Column::single(p.operand_index_base_a), + Column::single(p.operand_index_base_b), + Column::single(p.group_breakpoint), + Column::single(p.products_truncated), + ], + Filter::from_column(Column::linear_combination_with_constant([(p.is_padding, neg)], one)), + ); + + CrossTableLookup::new(vec![looking], vec![looked]) +} + +/// The internal quant-chain scales channel, keyed by operand-row index (the FP8 `InputQuant` +/// `element_index`/offset pattern): the row-scale AIR exports, per live row, the tuple +/// `(OPERAND_ROW_INDEX, alpha, beta)`; the noisy-quant AIR imports the same tuple on every live +/// element. Both sides are filtered to live rows (`1 - IS_PAD`). For each operand row `i`, the +/// row-scale table replicates `(i, alpha_i, beta_i)` on each of its `k` live block rows and the +/// noisy-quant table consumes `(i, alpha_i, beta_i)` on each of its `k` live elements, so the +/// multiset balance forces every element to consume *its own* operand row's proven `(alpha, beta)`. +/// The shared index space (`A` rows `0..h`, `B` rows `h..h+w`) covers BOTH operands in one channel. +pub fn scales_import_ctl() -> CrossTableLookup { + let rs = &ROW_SCALE_COL_MAP; + let nq = &NOISY_QUANT_COL_MAP; + let one = F::ONE; + let neg = -F::ONE; + // noisy-quant (looking): `(operand_row_index, alpha, beta)` per live element. + let looking = TableWithColumns::new( + TableIdx::from(NOISY_QUANT_A100_TABLE), + Column::singles([nq.operand_row_index, nq.alpha, nq.beta]).collect(), + Filter::from_column(Column::linear_combination_with_constant([(nq.is_pad, neg)], one)), + ); + // row-scale (looked): `(operand_row_index, alpha_code, beta_code)` per live row. + let looked = TableWithColumns::new( + TableIdx::from(ROW_SCALE_A100_TABLE), + Column::singles([rs.operand_row_index, rs.alpha_code, rs.beta_code]).collect(), + Filter::from_column(Column::linear_combination_with_constant([(rs.is_pad, neg)], one)), + ); + CrossTableLookup::new(vec![looking], vec![looked]) +} + +/// Every committed-LUT instance the FP16 batch consumes, tagged with the batch table index of its +/// consumer: the matmul AIR's full inventory at [`MATMUL_A100_TABLE`], the policy AIR's RANGE16 +/// inventory at [`POLICY_A100_TABLE`], the XorFold AIR's RC16 inventory at [`XOR_FOLD_A100_TABLE`], +/// the Blake3 AIR's BYTES2/RC16 inventory at [`BLAKE3_A100_TABLE`], and the three quantization-chain +/// AIRs' FP16DECODE/RANGE16/FP16POW2/WIDTH32 inventories (all shared FP16-batch LUTs). +fn lut_inventories() -> [(usize, Vec>); NUM_FP16_MAIN_TABLES] { + [ + (MATMUL_A100_TABLE, matmul_a100_lut_lookups::()), + (POLICY_A100_TABLE, policy_a100_lut_lookups::()), + (XOR_FOLD_A100_TABLE, xor_fold_lut_lookups::()), + (BLAKE3_A100_TABLE, blake3_lut_lookups::()), + (ROW_SCALE_A100_TABLE, row_scale_lut_lookups::()), + (NOISY_QUANT_A100_TABLE, noisy_quant_lut_lookups::()), + (NOISY_QUANT_FMA_A100_TABLE, fma_lut_lookups::()), + // The two noise matmuls reuse the exact A100 matmul inventory (same decode/shift/width/range + // auxiliary columns), so their decode/alignment columns are served by the same committed LUTs. + (NOISE_MATMUL_A_A100_TABLE, matmul_a100_lut_lookups::()), + (NOISE_MATMUL_B_A100_TABLE, matmul_a100_lut_lookups::()), + // NoiseStark's per-line normalization inventory (RC16/PAIR128/POW2D) — shared FP16-batch LUTs. + (NOISE_STARK_A100_TABLE, noise_lut_lookups::()), + // The noise-BLAKE3 derivation table reuses the forked engine's BYTES2/RC16 inventory (the same + // message-byte and egress-limb range checks), served by the shared FP16-batch LUTs (6e-3c). + (NOISE_BLAKE3_A100_TABLE, noise_blake3_lut_lookups::()), + ] +} + +/// All FP16 cross-table lookups: one channel per committed LUT, then the eight main-table channels +/// (census import, cell results, lottery words, scales import, FMA pairing, operand bytes [6c], +/// operand codes [6d], noise word [6e-1]). Each LUT channel's looking side collects every +/// instance of that table across *all* main tables' inventories (so the shared RANGE16 table +/// serves the matmul's result limbs, the policy's gate-slack / per-step-count limbs, and the +/// XorFold mixer limbs in one channel, and BYTES2 serves the Blake3 message bytes), and its looked +/// side is the LUT's slots at [`fp16_lut_table_idx`]. Every LUT must have at least one consumer (a +/// consumerless table is a wiring bug). +pub fn all_cross_table_lookups(h: usize, w: usize, k: usize) -> Vec> { + // `w` enters only through the noise-word B offset `h*k` and the E/F B offset `(h+k)*r`, both of + // which are expressed via `h`/`k`; it is kept in the signature for geometric symmetry. + let _ = w; + let r = super::driver::FP16_QUANT_R; + let inventories = lut_inventories::(); + let mut ctls: Vec> = FP16_LUT_TABLES + .iter() + .enumerate() + .map(|(i, &table)| { + let looking: Vec> = inventories + .iter() + .flat_map(|(table_idx, lookups)| { + let table_idx = *table_idx; + lookups.iter().filter(|l| l.table == table).map(move |l| { + TableWithColumns::new( + TableIdx::from(table_idx), + l.keys.iter().chain(&l.values).cloned().collect(), + l.filter.clone(), + ) + }) + }) + .collect(); + assert!(!looking.is_empty(), "{table:?} has no looking instances"); + let looked = (0..num_slots(table)) + .map(|slot| ctl_looked_lut_slot(TableIdx::from(fp16_lut_table_idx(i)), table, slot)) + .collect(); + CrossTableLookup::new(looking, looked) + }) + .collect(); + // The three main-table channels: the matmul -> policy census import, the matmul -> XorFold cell + // results (binding the proven output tile to the folded lottery lanes), and the XorFold -> + // Blake3 lottery words (binding the 16 lane outputs to the jackpot message, hence HASH_JACKPOT). + ctls.push(census_import_ctl::()); + ctls.push(CrossTableLookup::new( + vec![ctl_cell_results_looking_xor_fold::(XOR_FOLD_A100_TABLE)], + vec![ctl_cell_results_looked_matmul::(MATMUL_A100_TABLE)], + )); + ctls.push(CrossTableLookup::new( + ctl_lottery_words_looking_blake3::(BLAKE3_A100_TABLE), + vec![ctl_lottery_words_looked_xor_fold::(XOR_FOLD_A100_TABLE)], + )); + // The two internal quant-chain channels (increment 6b): the row-scale -> noisy-quant scales + // import, and the G1/G3 noisy-quant <-> G2 FMA pairing. The pairing's shared tuple + // `(alpha, raw, t_sign, t_mant, t_exp, noised_lo, noised_hi)` binds G1's proven `t` (fed to G2) + // and G3's cast input `noised` (proven by G2) to the single-rounding FMA. Both sides are filtered + // to live rows. + ctls.push(scales_import_ctl::()); + ctls.push(CrossTableLookup::new( + vec![ctl_fma_hook_looking::(NOISY_QUANT_A100_TABLE)], + vec![ctl_fma_pairing_looking::(NOISY_QUANT_FMA_A100_TABLE)], + )); + // The two operand-provenance channels (increments 6c/6d) that close audit Finding 3: the matmul + // provably multiplies the NOISED quantization of the COMMITTED operands. + // 6c — operand-bytes: Blake3's committed operand byte pairs (-> HASH_A/HASH_B) equal the quant + // chain's `raw` inputs, keyed by byte offset `2*e`. So `raw` is no longer free witness: it is the + // committed operand the noised codes derive from. + ctls.push(CrossTableLookup::new( + ctl_operand_bytes_looking_blake3::(BLAKE3_A100_TABLE), + vec![ctl_operand_bytes_looked_noisy_quant::(NOISY_QUANT_A100_TABLE)], + )); + // 6d — noised->matmul: the matmul's operand codes equal the noisy-quant `out` column, keyed by the + // shared element index, with the w/h reuse multiplicity on the looked side. So the matmul's + // operands are no longer free: they are the proven noised quantization of the committed `raw`, and + // cells of a row/column provably reuse the same operand element. + ctls.push(CrossTableLookup::new( + ctl_operand_codes_looking_matmul::(MATMUL_A100_TABLE), + vec![ctl_operand_codes_looked_noisy_quant::(NOISY_QUANT_A100_TABLE)], + )); + // 6e-1/6e-2 — noise-word: the two noise matmuls' proven cell results (`N_A = E_A@F_A^T`, `h x k`; + // `N_B = E_B@F_B^T`, `w x k`; both `CELL_ID = i*k + j`) equal the noisy-quant `(NOISE_LO, + // NOISE_HI)` the G1 rounding consumes, keyed by the shared global element index. A-side cells map + // directly (`[0, h*k)`); B-side cells are shifted by `h*k` into `[h*k, (h+w)*k)`. So the `beta*N` + // noise is provably `E@F` with distinct `F_A`/`F_B`. + ctls.push(CrossTableLookup::new( + vec![ + ctl_cell_results_looked_matmul::(NOISE_MATMUL_A_A100_TABLE), + ctl_cell_results_looked_matmul_offset::(NOISE_MATMUL_B_A100_TABLE, h * k), + ], + vec![ctl_noise_word_looked_noisy_quant::(NOISY_QUANT_A100_TABLE)], + )); + // 6e-2 — E/F-operand: the two noise matmuls' `E`/`F` operand codes equal NoiseStark's proven + // normalized line entries, keyed by the global entry index `line*r + entry`. NoiseStark lays its + // lines in the order `[E_A, F_A, E_B, F_B]`: matmul A's own `[0, (h+k)*r)` operand index space + // matches the leading `E_A`,`F_A` blocks directly (offset 0); matmul B's `[0, (w+k)*r)` space is + // shifted by `(h+k)*r` onto the trailing `E_B`,`F_B` blocks. NoiseStark's looked side carries the + // per-element reuse multiplicity (`k` for `E`, `h`/`w` for `F`), so each proven entry balances the + // matmul operands' per-cell reuse. This binds `E`/`F` to the seed-derived normalized lines. + let mut ef_looking = ctl_operand_codes_looking_matmul_offset::(NOISE_MATMUL_A_A100_TABLE, 0); + ef_looking.extend(ctl_operand_codes_looking_matmul_offset::(NOISE_MATMUL_B_A100_TABLE, (h + k) * r)); + ctls.push(CrossTableLookup::new( + ef_looking, + vec![ctl_noise_operands_looked::(NOISE_STARK_A100_TABLE)], + )); + // 6e-3c — noise-XOF egress: the noise-BLAKE3 table recomputes every line's keyed-BLAKE3-XOF bytes + // in-circuit from the seeds (its pinned `KEY_A`/`KEY_B` public inputs) and egresses each line + // compression's `cv_out` as 16 little-endian 16-bit limbs on keys `line*16 .. line*16 + 16`. + // NoiseStark's egress-pair looked side recomposes its own two consecutive XOF bytes into the same + // limbs on the same keys, so the multiset balance forces NoiseStark's normalized line's raw XOF + // bytes to equal the seed-derived, material-pinned keyed-XOF — the noise's last free witness is + // closed, so it is no longer grindable through those bytes. + ctls.push(CrossTableLookup::new( + ctl_cv_egress_looking_blake3::(NOISE_BLAKE3_A100_TABLE), + vec![ctl_noise_egress_pair_looked::(NOISE_STARK_A100_TABLE)], + )); + ctls +} + +/// The per-main-table committed-LUT inventories, for the prover's multiplicity accounting +/// (mirrors [`lut_inventories`] but keyed for the driver's [`crate::circuit::fp8::luts::LutChecker`]). +pub fn fp16_lut_inventories() -> [(usize, Vec>); NUM_FP16_MAIN_TABLES] { + lut_inventories::() +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::polynomial::PolynomialValues; + use plonky2::field::types::Field; + use starky::cross_table_lookup::debug_utils::check_ctls; + + use super::*; + use crate::api::fp16::accumulate::GROUP as ACC_GROUP; + use crate::api::fp16::policy::{evaluate, replay_and_evaluate}; + use crate::api::fp8::transcript::jackpot_key; + use crate::circuit::fp8::luts::{LutChecker, lut_trace}; + use crate::circuit::fp16::driver::Fp16System; + use crate::circuit::fp16::matmul_a100_stark::columns::{MATMUL_A100_COL_MAP, NUM_MATMUL_A100_COLUMNS}; + use crate::circuit::fp16::matmul_a100_stark::stark::MatmulStarkA100; + use crate::circuit::fp16::policy_stark::columns::{NUM_POLICY_A100_COLUMNS, POLICY_A100_COL_MAP}; + use crate::circuit::fp16::policy_stark::stark::PolicyStarkA100; + + /// The full honest nine-table batch for a 4x4 tile (16 output cells, one per lottery lane), + /// replicated from one accepting cell: the traces (canonical order) plus the per-table public + /// inputs (only Blake3's are nonempty). Built via the driver so the output -> jackpot chain is + /// wired exactly as a real proof. + fn full_batch() -> (Vec>>, Vec>, usize) { + use crate::api::fp8::public_params::HashId; + let (k, a0, b0) = accepting_tile(); + let (a, b) = (a0.repeat(4), b0.repeat(4)); + // Operand-tree keys / leaf size are passed in for now (seed-chain derivation is a later + // increment); the CTL balance is independent of these choices. + let system = Fp16System::::new(4, 4, k, HashId::Blake3Chunk512, HashId::Blake3Chunk512); + let (traces, blake3_pis) = system + .generate_batch_traces(&a, &b, [0x11; 32], [0x22; 32], jackpot_key(&[0x5a; 32])) + .expect("every honest instance must be served"); + let mut all_pis: Vec> = vec![Vec::new(); NUM_FP16_TABLES]; + all_pis[BLAKE3_A100_TABLE] = blake3_pis; + (traces.to_vec(), all_pis, k) + } + + type F = GoldilocksField; + const D: usize = 2; + type S = MatmulStarkA100; + type P = PolicyStarkA100; + + const VECTORS: &str = include_str!("../../api/fp16/testdata/a100_dot_vectors.txt"); + + /// An accepting `1 x 1 x k` tile from the GPU reference vectors: operands that clear the + /// policy gate (so the policy slacks are nonnegative and its RANGE16 limbs are in-domain) and + /// whose matmul output is normal (no subnormal branch). + fn accepting_tile() -> (usize, Vec, Vec) { + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % ACC_GROUP != 0 { + continue; + } + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + if replay_and_evaluate(&a, &b, 1, 1, k).1.accept { + return (k, a, b); + } + } + panic!("reference vectors must contain an accepting 1x1 tile"); + } + + fn mat_columns(rows: &[[F; NUM_MATMUL_A100_COLUMNS]]) -> Vec> { + (0..NUM_MATMUL_A100_COLUMNS) + .map(|c| PolynomialValues::new(rows.iter().map(|r| r[c]).collect())) + .collect() + } + + fn policy_columns(rows: &[[F; NUM_POLICY_A100_COLUMNS]]) -> Vec> { + (0..NUM_POLICY_A100_COLUMNS) + .map(|c| PolynomialValues::new(rows.iter().map(|r| r[c]).collect())) + .collect() + } + + /// Assembles the full FP16 batch trace set from (possibly tampered) matmul rows and a policy + /// trace generated from the same operands: `[matmul, policy, Fp16Decode, Range16, Fp16Pow2, + /// Width32]`. Runs `LutChecker` over both main tables' inventories; `Err` if any instance is + /// not served by its committed table. + fn build_batch( + mat_rows: &[[F; NUM_MATMUL_A100_COLUMNS]], + pol_rows: &[[F; NUM_POLICY_A100_COLUMNS]], + ) -> Result>>, String> { + let mat_cols = mat_columns(mat_rows); + let pol_cols = policy_columns(pol_rows); + let mut checker = LutChecker::::new(&FP16_LUT_TABLES); + checker.check_trace(&matmul_a100_lut_lookups::(), &mat_cols, &[], "MatmulA100")?; + checker.check_trace(&policy_a100_lut_lookups::(), &pol_cols, &[], "PolicyA100")?; + let mut traces = vec![mat_cols, pol_cols]; + for table in FP16_LUT_TABLES { + traces.push(lut_trace::(table, checker.multiplicities.table_columns(table))); + } + Ok(traces) + } + + #[test] + fn fp16_ctls_assemble() { + let ctls = all_cross_table_lookups::(4, 4, 16); + assert_eq!( + ctls.len(), + NUM_FP16_CTL_CHANNELS, + "one channel per LUT, plus census import, cell results, lottery words, scales, FMA pairing, \ + operand bytes (6c), operand codes (6d), noise word (6e-1/6e-2), and E/F operands (6e-2)" + ); + assert_eq!( + NUM_FP16_TABLES, 16, + "matmul, policy, xor_fold, blake3, row_scale, noisy_quant, noisy_quant_fma, noise_matmul_a, \ + noise_matmul_b, noise_stark, noise_blake3, five LUTs" + ); + } + + #[test] + fn lut_tables_descend_in_height() { + use crate::circuit::fp8::luts::lut_height; + let heights: Vec = FP16_LUT_TABLES.iter().map(|&t| lut_height(t)).collect(); + assert!(heights.windows(2).all(|w| w[0] >= w[1]), "committed LUTs must descend: {heights:?}"); + } + + /// The headline of gaps 1 and 3: every decode/shift/width auxiliary column of the matmul AIR + /// and every RANGE16 fact of the policy AIR is served by a committed table (`LutChecker`), and + /// every CTL channel balances — the four LUT channels *and* the matmul -> policy census-import + /// channel (`check_ctls`). So the batch's own verification enforces those columns and binds the + /// policy census to the matmul's. + #[test] + fn honest_batch_serves_and_balances_every_channel() { + let (traces, all_pis, k) = full_batch(); + check_ctls(&traces, &all_pis, &all_cross_table_lookups::(4, 4, k), &Default::default()); + } + + /// Negative: forging an auxiliary column the LUTs are responsible for must be caught by the + /// committed tables (a value mismatch or an out-of-domain key). + #[test] + fn forged_auxiliary_columns_are_rejected_by_the_luts() { + let (k, a, b) = accepting_tile(); + let mat = S::new(1, 1, k).generate_trace(&a, &b, None); + let pol = P::new(1, 1, k).generate_trace(&a, &b); + let m = &MATMUL_A100_COL_MAP; + build_batch(&mat, &pol).expect("baseline honest trace must serve"); + + let live = (0..mat.len()) + .find(|&r| { + mat[r][m.is_padding] == F::ZERO + && mat[r][m.group_nonempty] == F::ONE + && mat[r][m.group_sum_is_zero] == F::ZERO + }) + .expect("fixture has a live non-cancelling row"); + + let forge = |col: usize, delta: F| -> Result<(), String> { + let mut t = mat.clone(); + t[live][col] += delta; + build_batch(&t, &pol).map(|_| ()) + }; + + assert!(forge(m.sig_a[1], F::ONE).is_err(), "forged sig_a must be rejected by FP16DECODE"); + assert!(forge(m.eps_b[1], F::ONE).is_err(), "forged eps_b must be rejected by FP16DECODE"); + assert!(forge(m.lane_shift_power[1], F::ONE).is_err(), "forged lane_shift_power must be rejected by FP16POW2"); + assert!( + forge(m.product_biased_exp[1], F::from_canonical_u64(1000)).is_err(), + "a product exponent above the window max must leave the FP16POW2 key domain" + ); + assert!(forge(m.truncation_power, F::ONE).is_err(), "forged truncation_power must be rejected by WIDTH32"); + // MA12: a floor-witness hi limb pushed to >= 2^10 (a field-fraction alias of the floor + // quotient) leaves the `2^6`-scaled RANGE16 domain — the limb-range soundness fix. + assert!( + forge(m.aligned_mag_hi[1], F::from_canonical_u64(1024)).is_err(), + "an out-of-range floor-witness hi limb must be rejected by RANGE16" + ); + + // The multiset balance itself breaks: honest LUT multiplicities against a tampered matmul + // value is a CTL imbalance that `check_ctls` panics on. (Full nine-table batch so every + // channel — LUTs, census, cell-results, lottery-words — is present.) + let (honest, all_pis, k) = full_batch(); + let mut tampered = honest.clone(); + let live = (0..tampered[MATMUL_A100_TABLE][m.is_padding].values.len()) + .find(|&r| { + tampered[MATMUL_A100_TABLE][m.is_padding].values[r] == F::ZERO + && tampered[MATMUL_A100_TABLE][m.group_sum_is_zero].values[r] == F::ZERO + }) + .expect("a live non-cancelling row"); + tampered[MATMUL_A100_TABLE][m.sig_a[1]].values[live] += F::ONE; + let ctls = all_cross_table_lookups::(4, 4, k); + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a tampered matmul value against honest LUT multiplicities must unbalance a CTL channel"); + } + + /// Regression guard for the NORM_SIG normalized-range pin (the dropped B200 MB7 check). + /// + /// The MA7 width identity `GROUP_SUM_ABS * LIFTING_POWER = NORM_SIG * TRUNCATION_POWER + + /// TRUNC_REM` only pins `GROUP_SUM_WIDTH` to the true bit-width when `NORM_SIG` is forced into + /// `[2^23, 2^24)`. The looser MA12 split alone (`NORM_SIG_HI < 2^10`) lets a prover pick a false + /// width, choose `TRUNC_REM != 0`, and so forge `RZ_DROPPED` (MA11) → `GROUP_BREAKPOINT` → the + /// jackpot census (`f_bp` / `rho`). A `NORM_SIG_HI` outside `[128, 256)` but still inside the + /// looser `2^6*hi < 2^16` domain is exactly the shape of such a forge; the committed RANGE16 + /// normalized-range instance must reject it. + #[test] + fn forged_norm_sig_width_is_rejected_by_the_normalized_range() { + let (k, a, b) = accepting_tile(); + let mat = S::new(1, 1, k).generate_trace(&a, &b, None); + let pol = P::new(1, 1, k).generate_trace(&a, &b); + let m = &MATMUL_A100_COL_MAP; + // Baseline: the honest (normalized) trace is served, so the new pin does not reject it. + build_batch(&mat, &pol).expect("baseline honest trace must serve"); + + let live = (0..mat.len()) + .find(|&r| mat[r][m.is_padding] == F::ZERO && mat[r][m.group_sum_is_zero] == F::ZERO) + .expect("fixture has a live nonzero-sum row"); + + // Each forged hi is below 128 (hi = 0) or at/above 256, i.e. outside the normalized band + // `[128, 256)` — yet all stay inside the looser MA12 `2^6*hi < 2^16` (hi < 2^10) split that + // the pre-fix inventory relied on, so only the new normalized-range check can catch them. + for forged_hi in [0u64, 256, 512] { + assert!((1u64 << 6) * forged_hi < (1 << 16), "forged hi stays inside the MA12 2^6-split domain"); + let mut t = mat.clone(); + t[live][m.norm_sig_hi] = F::from_canonical_u64(forged_hi); + assert!( + build_batch(&t, &pol).is_err(), + "norm_sig_hi={forged_hi} is outside [128,256) and must be rejected by the normalized-range RANGE16" + ); + } + } + + /// The census-import channel binds the policy census to the matmul's: forging a policy + /// per-step census value away from the matmul's (keeping the matmul honest) unbalances the + /// `matmul -> policy` channel. + #[test] + fn forged_policy_census_breaks_the_import_channel() { + let p = &POLICY_A100_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let live = (0..honest[POLICY_A100_TABLE][p.is_padding].values.len()) + .find(|&r| honest[POLICY_A100_TABLE][p.is_padding].values[r] == F::ZERO) + .unwrap(); + + let ctls = all_cross_table_lookups::(4, 4, k); + for col in [p.group_breakpoint, p.products_truncated] { + let mut tampered = honest.clone(); + tampered[POLICY_A100_TABLE][col].values[live] += F::ONE; + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged policy census value must unbalance the census-import channel"); + } + } + + /// 6d — the noised->matmul operand-codes channel binds the matmul's operand codes to the quant + /// chain's noised `out`. Forging the noisy-quant `OUT` column at a live element (keeping the + /// matmul honest) unbalances the operand-codes channel — and ONLY that channel, since `OUT` is + /// wired nowhere else (no LUT, no other CTL), so the panic is attributable to it. + #[test] + fn forged_noised_out_breaks_the_operand_codes_channel() { + let nq = &NOISY_QUANT_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let live = (0..honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values.len()) + .find(|&r| honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values[r] == F::ZERO) + .expect("a live noisy-quant element"); + let mut tampered = honest.clone(); + tampered[NOISY_QUANT_A100_TABLE][nq.out].values[live] += F::ONE; + let ctls = all_cross_table_lookups::(4, 4, k); + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged noised OUT must unbalance the noised->matmul operand-codes channel"); + } + + /// 6e-1 — the noise-word channel binds the `N = E@F^T` noise matmul's proven cell results to the + /// noise noisy-quant consumes. Forging the noisy-quant `NOISE_LO` at a live element, and (keeping + /// the matmul honest) forging the noise matmul's `CELL_RESULT_F32_LO` at a finished cell, each + /// unbalance the noise-word channel — `NOISE_LO`/`NOISE_HI` and the noise matmul's + /// `CELL_RESULT_F32_*` are wired into no other CTL channel, so the panic is attributable to it. + #[test] + fn forged_noise_word_breaks_the_noise_channel() { + use crate::circuit::fp16::matmul_a100_stark::columns::MATMUL_A100_COL_MAP; + let nq = &NOISY_QUANT_COL_MAP; + let m = &MATMUL_A100_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let ctls = all_cross_table_lookups::(4, 4, k); + + // (a) the consuming side: a forged noise word noisy-quant claims to consume. + let nq_live = (0..honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values.len()) + .find(|&r| honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values[r] == F::ZERO) + .expect("a live noisy-quant element"); + // (b) the producing side: a forged cell result of the noise matmul at a finished live cell. + let noise_final = (0..honest[NOISE_MATMUL_A_A100_TABLE][m.is_cell_final].values.len()) + .find(|&r| { + honest[NOISE_MATMUL_A_A100_TABLE][m.is_cell_final].values[r] == F::ONE + && honest[NOISE_MATMUL_A_A100_TABLE][m.is_padding].values[r] == F::ZERO + }) + .expect("a finished live noise-matmul cell"); + + for (table, col, row) in [ + (NOISY_QUANT_A100_TABLE, nq.noise_lo, nq_live), + (NOISE_MATMUL_A_A100_TABLE, m.cell_result_f32_lo, noise_final), + ] { + let mut tampered = honest.clone(); + tampered[table][col].values[row] += F::ONE; + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged noise word must unbalance the noise-word (6e-1) channel"); + } + } + + /// 6c — the operand-bytes channel binds Blake3's committed operand bytes to the quant chain's + /// `raw`. Forging the committed `UINT8_DATA` at a live operand-values row unbalances the + /// operand-bytes channel (its committed byte pair no longer equals the quant `raw`), so a prover + /// cannot commit one operand and quantize a different one. + #[test] + fn forged_committed_byte_breaks_the_operand_bytes_channel() { + use crate::circuit::fp8::blake3_stark::columns::BLAKE3_COL_MAP; + let bm = &BLAKE3_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let live = (0..honest[BLAKE3_A100_TABLE][bm.is_int8_message].values.len()) + .find(|&r| honest[BLAKE3_A100_TABLE][bm.is_int8_message].values[r] == F::ONE) + .expect("a live operand-values row"); + let mut tampered = honest.clone(); + tampered[BLAKE3_A100_TABLE][bm.uint8_data[0]].values[live] += F::ONE; + let ctls = all_cross_table_lookups::(4, 4, k); + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged committed operand byte must unbalance the operand-bytes channel"); + } + + /// 6e-2 — the E/F-operand channel binds the two noise matmuls' `E`/`F` operand codes to + /// NoiseStark's proven normalized line entries. Forging a NoiseStark line entry (`ENTRY_FP16`) at a + /// live row unbalances the E/F channel: the proven normalized line no longer matches the matmul + /// operand it is bound to. `ENTRY_FP16` is wired into no other CTL channel, so the panic is + /// attributable to the E/F binding. + #[test] + fn forged_noise_line_breaks_the_ef_channel() { + use crate::circuit::fp16::noise_stark::columns::NOISE_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let ns = &NOISE_COL_MAP; + let live = (0..honest[NOISE_STARK_A100_TABLE][ns.is_pad].values.len()) + .find(|&r| honest[NOISE_STARK_A100_TABLE][ns.is_pad].values[r] == F::ZERO) + .expect("a live noise line entry"); + let mut tampered = honest.clone(); + tampered[NOISE_STARK_A100_TABLE][ns.entry_fp16].values[live] += F::ONE; + let ctls = all_cross_table_lookups::(4, 4, k); + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged NoiseStark line entry must unbalance the E/F-operand channel"); + } + + /// 6e-3c — the noise-XOF egress channel binds NoiseStark's raw XOF bytes to the noise-BLAKE3 + /// table's in-circuit, seed-derived keyed-XOF `cv_out` limbs. Grinding the noise is fail-closed: + /// * forging NoiseStark's recomposed limb (`BYTE_PAIR`) at a live egress-pair row unbalances the + /// egress channel (its XOF bytes no longer match the seed-derived keyed-XOF); + /// * forging the noise-BLAKE3 table's egressed limb (`CV_EGRESS_LIMBS`) at a line finalization row + /// unbalances the SAME channel from the producing side. + /// `BYTE_PAIR` / `CV_EGRESS_LIMBS` are wired into no other CTL channel, so each panic is + /// attributable to the egress binding — the noise is no longer grindable through those bytes. + #[test] + fn forged_noise_xof_breaks_the_egress_channel() { + use crate::circuit::fp16::blake3_fp16_stark::columns::FP16_RAW_BLAKE3_COL_MAP as BM; + use crate::circuit::fp16::noise_stark::columns::NOISE_COL_MAP; + let (honest, all_pis, k) = full_batch(); + let ctls = all_cross_table_lookups::(4, 4, k); + let ns = &NOISE_COL_MAP; + + // (a) the consuming side: forge NoiseStark's recomposed limb at a live egress-pair row. + let pair_row = (0..honest[NOISE_STARK_A100_TABLE][ns.is_egress_pair].values.len()) + .find(|&r| honest[NOISE_STARK_A100_TABLE][ns.is_egress_pair].values[r] == F::ONE) + .expect("a live egress-pair row"); + // (b) the producing side: forge a noise-BLAKE3 egress limb at a line finalization (egress) row. + let egress_row = (0..honest[NOISE_BLAKE3_A100_TABLE][BM.is_egress_cv].values.len()) + .find(|&r| honest[NOISE_BLAKE3_A100_TABLE][BM.is_egress_cv].values[r] == F::ONE) + .expect("a noise-BLAKE3 egress row"); + + for (table, col, row) in [ + (NOISE_STARK_A100_TABLE, ns.byte_pair, pair_row), + (NOISE_BLAKE3_A100_TABLE, BM.cv_egress_limbs[0], egress_row), + ] { + let mut tampered = honest.clone(); + tampered[table][col].values[row] += F::ONE; + let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + check_ctls(&tampered, &all_pis, &ctls, &Default::default()); + })) + .is_err(); + assert!(panicked, "a forged noise XOF limb must unbalance the egress (6e-3c) channel"); + } + } + + /// `evaluate` is the oracle the policy trace is built to match; this keeps the import test's + /// tile genuinely accepting even if the reference set changes. + #[test] + fn accepting_tile_is_accepted_by_the_oracle() { + let (k, a, b) = accepting_tile(); + assert!(evaluate(&[replay_census(&a, &b)], k).accept); + } + + fn replay_census(a: &[u16], b: &[u16]) -> Vec { + use crate::api::fp16::accumulate::a100_dot; + let mut steps = Vec::new(); + a100_dot(a, b, 0.0, Some(&mut steps)); + steps + } +} + diff --git a/zk-pow/src/circuit/fp16/driver.rs b/zk-pow/src/circuit/fp16/driver.rs new file mode 100644 index 000000000..57aa8dfab --- /dev/null +++ b/zk-pow/src/circuit/fp16/driver.rs @@ -0,0 +1,2302 @@ +//! The FP16 / A100 batch driver: one batched-FRI proof for the whole thirteen-table system. +//! +//! [`Fp16System`] mirrors [`crate::circuit::fp8::driver::Fp8System`] at FP16's (much smaller) +//! scale. It batches the two main AIRs — the A100 `HMMA` matmul +//! ([`crate::circuit::fp16::matmul_a100_stark`]) and the rho/breakpoint policy gate +//! ([`crate::circuit::fp16::policy_stark`]) — together with the four committed LUTs their +//! auxiliary columns are served by (`FP16DECODE`, `RANGE16`, `FP16POW2`, `WIDTH32`), under one +//! [`starky::batch_prover::batch_prove`] / [`starky::batch_verifier::batch_verify`] argument with +//! the full [`CrossTableLookup`] set of [`super::ctl`]: +//! +//! * the four LUT channels, so the matmul's decode/shift/width columns and the policy's +//! gate-slack / per-step-count range checks are enforced by the batch's own verification +//! (the CTL multiset balance), not by blind trust; +//! * the `matmul -> policy` census-import channel, so the policy scores the matmul's +//! tightly-pinned per-step census rather than regenerating it; +//! * the two internal **quant-chain** channels (increment 6b): `row-scale -> noisy-quant` (the derived +//! per-row `(alpha, beta)` the noisy-quant consumes) and the G1/G3 `noisy-quant <-> G2 FMA` pairing +//! (binding G1's proven `t` and G3's cast input `noised` to the single-rounding FMA). Together with +//! the three quant AIRs and the shared LUTs, these prove the noised operand +//! `noised = Q(alpha*raw + beta*N)` end-to-end inside the batch. `raw` is bound to the commitment +//! (6c) and the noise matrix `N = E@F^T` to the noise matmul (6e-1, below); `E`/`F` stay free +//! witness (seed-binding is 6e-2/6e-3). +//! +//! The batch order is canonical: matmul (0), policy (1), xor_fold (2), blake3 (3), the three +//! quantization-chain AIRs — row-scale (4), noisy-quant G1/G3 (5), G2 FMA (6) — the noise matmul (7), +//! then the five LUTs (8..12) in descending committed height. The main tables' heights come from the AIR geometry `(h, w, k)` — the +//! verifier never takes the batch layout from the proof. The LUTs' precommitted columns are +//! committed once at setup ([`Fp16System::preprocessed_data`]); proofs copy the setup +//! commitment and FRI opens it alongside the trace oracles. +//! +//! **Scope.** This is the native batched prove/verify path: an honest tile's proof generates and +//! verifies, and tampering (a trace cell, a census value, a decode column, a gate slack) is +//! rejected. The recursive FRI wrapper to a constant-size proof (the FP8 `wrapper.rs` analogue) +//! is the documented follow-on. +//! +//! **Operand provenance (increments 6c + 6d — DONE).** The matmul provably multiplies the NOISED +//! quantization of the COMMITTED operands, closing audit Finding 3. Two keyed CTLs bind one operand +//! set through Blake3 + quant + matmul: +//! +//! * **Operand-bytes (6c).** The Blake3 operand trees' committed byte pairs (-> `HASH_A`/`HASH_B`) +//! equal the quant chain's `raw` inputs, keyed by byte offset `2*e` (A elements `0..h*k`, B +//! elements past them, one shared disjoint key space). So `raw` is no longer free witness: it is +//! the committed operand (`HASH_A`/`HASH_B` bit-exact with `commit_operand(..).root()`). +//! * **Operand-codes (6d).** The matmul's `operand_codes_a/b` equal the noisy-quant `out` column, +//! keyed by the shared element index `operand_index_base_{a,b} + lane`, with the `w`/`h` reuse +//! multiplicity on the looked side. This single channel binds BOTH provenance (matmul code == +//! noised `out`) AND cross-cell sharing (cells `(r, c1)`/`(r, c2)` reuse the same `A[r, :]` element +//! because they look up the same key; a column reuses `B[:, c]`). `operand_index_base_a/b` are +//! class (a) known columns, so the keys are fixed and only the codes are witness. +//! +//! So `generate_batch_traces` flows ONE operand set: committed bytes (Blake3) == `raw` (quant) +//! --`Q(.)`--> `out` (quant) == matmul operand codes. The three quant AIRs + the two internal +//! channels prove `noised = Q(alpha*raw + beta*N)` over EVERY operand row of BOTH operands. +//! +//! **Noise `N` provenance (increments 6e-1 … 6e-3d — DONE).** `N = E@F^T` is proven in-batch (two +//! [`MatmulStarkA100`] instances, tables 7/8, bound to the noise noisy-quant consumes by the +//! noise-word CTL); `E`/`F` are the proven normalized lines of NoiseStark (E/F-operand CTL); the raw +//! keyed-XOF bytes NoiseStark normalizes are recomputed in-circuit by the forked noise-BLAKE3 engine +//! (table 10) from the seeds and bound via the egress-pair CTL (6e-3c); and the SEEDS are derived from +//! the committed operand roots — `seedA`/`seedB = noise_seeds(keys, {HASH_A, HASH_B}, p)` +//! ([`fp16_root_derived_seeds`], exactly [`crate::api::fp16::noise::noise_seeds`]) — fed as the +//! noise-BLAKE3 `KEY_A`/`KEY_B` public inputs, which [`Fp16System::verify`] pins to the seeds +//! recomputed from the pinned `HASH_A`/`HASH_B` + keys + `p` (6e-3d). So the whole noise chain +//! (`E`/`F` -> `N` -> `beta*N` -> `noised` -> tile -> jackpot) is a pure function of the COMMITTED +//! operands, bit-exact with the plaintext's root-derived noise, and fully anti-grind. +//! +//! **Header-pinned verify gateway ([`Fp16System::verify_with_headers`] — DONE).** The opening keys +//! (`keyA`/`keyB`) and the `p_a`/`p_b` encodings that feed the noise seeds + the operand-tree +//! commitment keys are no longer taken from the circuit boundary in the sound entry: the gateway +//! derives `keyA = key_a(proposed)`, `keyB = key_b(ancestor)` ([`commitment_keys`]) and +//! `p_a`/`p_b` ([`Fp16JobParams::encode_p_a`]/`encode_p_b`) from the block headers + public job +//! params, bit-exact with the plaintext certificate, then pins the proof's operand-tree +//! `KEY_A`/`KEY_B`, the lottery-compression `JACKPOT_KEY` (= `jackpot_key(seed_a)` over the +//! header/root-derived `seed_a`, so the jackpot key cannot be ground), and the noise-BLAKE3 +//! `KEY_A`/`KEY_B` (= `noise_seeds` of the header-derived keys/`p` over the proof's `HASH_A`/ +//! `HASH_B`) to those header-derived values, DERIVES `statement_digest` from the proven +//! `HASH_JACKPOT` (not caller-supplied), and applies the native difficulty check +//! ([`check_jackpot_difficulty`]). So the ZK verify is pinned to the actual header exactly like the +//! plaintext cert path. The committed roots `HASH_A`/`HASH_B` still come from the proof (as they do +//! in the plaintext cert, whose root is proof-carried); the ONLY remaining boundary is inherent — the +//! consensus layer supplies the header + `nbits`, and must window-authenticate `job.ancestor_header` +//! (the plaintext FFI's SHA256d hash-walk) before calling the gateway, which assumes that +//! authentication exactly as the plaintext `verify_fp16_plain_proof` assumes its caller's. The +//! caller-supplied-expectation [`Fp16System::verify`] is retained for the non-consensus test paths. +//! +//! **Header binding CLOSED (the ZK proof is now a header-bound consensus certificate).** The output +//! tile is bound end-to-end: the matmul -> XorFold cell-results CTL feeds each proven +//! `cell_result_f32_*` into the lottery mixer, the XorFold -> Blake3 lottery-words CTL carries the 16 +//! lane outputs into the jackpot compression, the Blake3 AIR binds that compression to the +//! `HASH_JACKPOT` public input, and the header gateways +//! ([`Fp16System::verify_with_headers`] for the batch proof and +//! [`crate::circuit::fp16::wrapper::verify_wrapped_proof_with_headers`] for the wrapped/published +//! proof) pin `HASH_JACKPOT` to the consensus header by pinning the jackpot key to +//! `jackpot_key(seed_a)` and deriving `statement_digest` from the proven `HASH_JACKPOT`. A verified +//! proof therefore attests "this policy-passing tile folds, under the header-derived jackpot key for +//! this block, to a `HASH_JACKPOT` meeting difficulty." (The census totals remain non-public, which +//! is sound: the policy AIR gates them in-circuit.) +//! +//! The ZK proof is thus a sound stand-alone consensus certificate; the only REMAINING work to make +//! it the wired consensus path is deployment integration (the FFI entry, the Go/wire routing, and +//! the miner switching from plaintext-cert assembly to proof generation), tracked as follow-on +//! steps. Until that lands the wired consensus path remains the plaintext certificate +//! ([`crate::api::fp16::verify`]). The full binding design (the Blake3 commitment, the seed-derived +//! noise + noisy-quant stages, the XorFold ticket, and the header-bound public inputs) is in +//! `docs/fp16_scheme/zk_binding_design.md`. + +use anyhow::{Result, anyhow, ensure}; +use plonky2::field::extension::Extendable; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::fri::FriConfig; +use plonky2::fri::reduction_strategies::FriReductionStrategy; +use plonky2::hash::hash_types::{HashOut, RichField}; +use plonky2::hash::merkle_tree::MerkleCap; +use plonky2::plonk::config::GenericConfig; +use plonky2::util::log2_strict; +use plonky2::util::timing::TimingTree; +use primitive_types::U256; +use starky::batch_proof::BatchStarkProofWithPublicInputs; +use starky::batch_prover::{BatchStarkPreprocessedData, BatchStarkPreprocessedVerifierData, batch_prove}; +use starky::batch_stark::BatchStark; +use starky::batch_universal::UniversalVerifierEnvelope; +use starky::batch_verifier::{BatchKnownColumns, batch_verify}; +use starky::config::StarkConfig; +use starky::cross_table_lookup::CrossTableLookup; + +use crate::api::layout::{AxisPattern, DimType, lane_assignment}; +use crate::api::primitives::Hash256; +use crate::api::proof_utils::check_jackpot_difficulty; +use crate::api::fp8::transcript::{hash_labelled, jackpot_key}; +use crate::v2::api::proof_utils::u32_field_array_to_hash; + +use core::borrow::Borrow; + +use super::blake3_commit::{bytes32_to_words, fp16_blake3_program}; +use crate::api::fp16::commitment::{commit_operand, rows_to_bytes}; +use super::ctl::{ + BLAKE3_A100_TABLE, FP16_LUT_TABLES, MATMUL_A100_TABLE, NOISE_BLAKE3_A100_TABLE, + NOISE_MATMUL_A_A100_TABLE, NOISE_MATMUL_B_A100_TABLE, NOISE_STARK_A100_TABLE, + NOISY_QUANT_A100_TABLE, NOISY_QUANT_FMA_A100_TABLE, NUM_FP16_LUT_TABLES, NUM_FP16_MAIN_TABLES, + NUM_FP16_TABLES, ROW_SCALE_A100_TABLE, XOR_FOLD_A100_TABLE, all_cross_table_lookups, + fp16_lut_inventories, fp16_lut_table_idx, +}; +use super::blake3_fp16_stark::columns::NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS; +use super::blake3_fp16_stark::stark::{Fp16RawBlake3KnownInputs, Fp16RawBlake3Stark, Fp16RawBlake3TraceInputs}; +use super::noise_blake3::{ + noise_blake3_aux_msgs, noise_blake3_height_bits, noise_blake3_program, noise_blake3_public_inputs, + noise_seed_key_words, NOISE_BLAKE3_JACKPOT_KEY, NOISE_BLAKE3_LOTTERY_WORDS, +}; +use super::matmul_a100_stark::columns::{MatmulA100ColumnsView, NUM_MATMUL_A100_PUBLIC_INPUTS}; +use super::matmul_a100_stark::stark::MatmulStarkA100; +use super::noise_stark::stark::{NoiseProgram, NoiseStark}; +use super::noisy_quant_fma_stark::columns::FMA_COL_MAP; +use super::noisy_quant_fma_stark::stark::{FmaProgram, NoisyQuantFmaStark}; +use super::noisy_quant_stark::columns::NOISY_QUANT_COL_MAP; +use super::noisy_quant_stark::stark::{NoisyQuantProgram, NoisyQuantStark}; +use super::policy_stark::columns::NUM_POLICY_A100_PUBLIC_INPUTS; +use super::policy_stark::stark::PolicyStarkA100; +use super::row_scale_stark::stark::{RowScaleProgram, RowScaleStark}; +use crate::api::fp16::noise::{NoiseFactor, Side, commitment_keys, noise_seeds, sample_line_xof_bytes}; +use crate::api::fp16::plain_proof::Fp16JobParams; +use crate::api::primitives::{IncompleteBlockHeader, Sides}; +use super::xor_fold_stark::columns::XorFoldColumnsView; +use super::xor_fold_stark::stark::{XorFoldProgram, XorFoldStark}; +use crate::api::fp16::accumulate::a100_matmul; +use crate::api::fp16::quantization::{noisy_quantize, row_norms}; +use crate::api::fp8::dtype::bf16_to_f32; +use crate::circuit::fp8::blake3_stark::columns::{ + NUM_BLAKE3_PUBLIC_INPUTS, PI_HASH_A, PI_HASH_B, PI_HASH_JACKPOT, PI_JACKPOT_KEY, PI_KEY_A, PI_KEY_B, +}; +use crate::circuit::fp8::blake3_stark::stark::{Blake3KnownInputs, Blake3Stark, Blake3TraceInputs}; +use crate::api::fp8::public_params::HashId; +use crate::circuit::fp8::luts::stark::boxed_lut_stark; +use crate::circuit::fp8::luts::{LutChecker, lut_precommitted_values, lut_trace, num_precommitted_columns}; + +// ================================================================================================== +// Consensus proof shape (mirrors the FP8 consensus parameters) +// ================================================================================================== + +/// Targeted (conjectured) security level in bits. +pub const STARK_SECURITY_BITS: usize = 120; +/// Logup/CTL challenge repetitions. +pub const STARK_NUM_CHALLENGES: usize = 3; +/// FRI rate `2^-1`. +pub const STARK_RATE_BITS: usize = 1; +/// Merkle cap height of every oracle and FRI commit layer. +pub const STARK_CAP_HEIGHT: usize = 4; +/// FRI grinding bits. +pub const STARK_POW_BITS: u32 = 18; +/// FRI query rounds meeting the security target at this rate. +pub const STARK_QUERY_ROUNDS: usize = (STARK_SECURITY_BITS - STARK_POW_BITS as usize).div_ceil(STARK_RATE_BITS); + +/// The consensus FRI fold ladder (degree bits, strictly descending) for the FP16 batch. Every +/// reachable table height is a member and every gap is at most 3 bits, so the ladder doubles as +/// the universal-verifier fold schedule: it includes the four committed-LUT heights (`FP16DECODE` +/// / `RANGE16` at `2^16`, `FP16POW2` at `2^8`, `WIDTH32` at `2^5`) and the main-table range +/// [`FP16_MAIN_TABLE_DEGREE_RANGE`]. Baking it (rather than the job's distinct heights) into +/// [`fp16_stark_config`] makes the config a consensus constant for every on-ladder job, so the +/// Fiat-Shamir transcript the recursive wrapper replays in-circuit is identical across tile +/// sizes — the prerequisite for one compiled universal wrapper to verify every envelope-legal +/// job (the FP8 `wrapper.rs` design). +pub const FP16_REACHABLE_DEGREE_BITS: [usize; 7] = [16, 13, 10, 8, 6, 5, 4]; + +/// Batch indices of the grouped tables — the four committed LUTs (`NUM_FP16_MAIN_TABLES..`). Their +/// heights are consensus constants, so each role (trace / auxiliary / quotient) commits all of them +/// in one shared multi-height Merkle tree. Grouping is required by the universal recursive verifier +/// (its shared-tree Merkle walks are profile-independent only for grouped fixed-height tables), and +/// it also shrinks the native proof's cap count. +pub const FP16_GROUPED_TABLES: [usize; NUM_FP16_LUT_TABLES] = { + let mut tables = [0; NUM_FP16_LUT_TABLES]; + let mut i = 0; + while i < NUM_FP16_LUT_TABLES { + tables[i] = NUM_FP16_MAIN_TABLES + i; + i += 1; + } + tables +}; + +/// Inclusive degree-bits range `[lo, hi]` of the two main tables (matmul, policy — they share the +/// row grid) over the wrapper's consensus envelope. Both bounds lie on +/// [`FP16_REACHABLE_DEGREE_BITS`]. The floor is `4` so every table's LDE (`height + RATE`) strictly +/// exceeds the Merkle `cap_height` (4): a table whose LDE equals the cap has a degenerate (cap == +/// leaves, zero-sibling) Merkle tree that the universal verifier's envelope-max padding does not +/// model. Jobs outside this range still prove natively (the config adds their heights as extra +/// boundaries); only the recursive wrapper is gated to the envelope. +pub const FP16_MAIN_TABLE_DEGREE_RANGE: (usize, usize) = (4, 6); + +/// Inclusive degree-bits range of each per-side noise matmul table (`N_A`/`N_B = E@F^T`, increment +/// 6e-2). A side's `m x k` output (inner dimension [`FP16_QUANT_R`]) has live height +/// `m*k*(FP16_QUANT_R/GROUP)`, snapped up to a [`FP16_REACHABLE_DEGREE_BITS`] member; over the +/// wrapper's legal tiles this lands on `2^8..2^10`. Both bounds lie on the ladder. +pub const FP16_NOISE_MATMUL_DEGREE_RANGE: (usize, usize) = (8, 10); + +/// Inclusive degree-bits range of the NoiseStark table (increment 6e-2). It proves every noise line +/// (`E_A`,`F_A`,`E_B`,`F_B` = `h+w+2k` lines) at rank [`FP16_QUANT_R`], live height +/// `(h+w+2k)*FP16_QUANT_R` snapped to the ladder; over the wrapper's legal tiles (`k >= 16`) this +/// lands on `2^13`. +pub const FP16_NOISE_STARK_DEGREE_RANGE: (usize, usize) = (13, 13); + +/// Inclusive degree-bits range of the noise-BLAKE3 derivation table (increment 6e-3c). It runs two +/// subkey compressions, `h + w + 2k` per-line compressions and the mandatory lottery (`8` rows each), +/// its live height `8*(h+w+2k+3)` snapped up to a [`FP16_REACHABLE_DEGREE_BITS`] member via +/// [`crate::circuit::fp16::noise_blake3::noise_blake3_height_bits`]. Over the wrapper's legal tiles +/// (`k >= 16`) this lands on `2^10..2^13`; both bounds lie on the ladder. +pub const FP16_NOISE_BLAKE3_DEGREE_RANGE: (usize, usize) = (10, 13); + +/// The consensus universal-verifier envelope: the seven tile/quant main tables each range over +/// [`FP16_MAIN_TABLE_DEGREE_RANGE`], the two per-side noise matmuls over +/// [`FP16_NOISE_MATMUL_DEGREE_RANGE`], and NoiseStark over [`FP16_NOISE_STARK_DEGREE_RANGE`]; the +/// five LUT tables are fixed at their consensus heights; the fold ladder is +/// [`FP16_REACHABLE_DEGREE_BITS`]. The FP16 LUTs are committed per table (not grouped), so +/// `grouped_tables` is empty. One stage-1 wrapper circuit built on this envelope verifies every +/// envelope-legal job (the job's degree profile becomes a public input). +pub fn fp16_universal_envelope() -> UniversalVerifierEnvelope { + let (lo, hi) = FP16_MAIN_TABLE_DEGREE_RANGE; + // Main tables 0..=6 (tile + quant chain) share the tile row grid; tables 7/8 are the per-side + // noise matmuls, table 9 is NoiseStark, table 10 is the noise-BLAKE3 derivation. + let mut degree_ranges: Vec<(usize, usize)> = vec![(lo, hi); NUM_FP16_MAIN_TABLES - 4]; + degree_ranges.push(FP16_NOISE_MATMUL_DEGREE_RANGE); + degree_ranges.push(FP16_NOISE_MATMUL_DEGREE_RANGE); + degree_ranges.push(FP16_NOISE_STARK_DEGREE_RANGE); + degree_ranges.push(FP16_NOISE_BLAKE3_DEGREE_RANGE); + for &table in &FP16_LUT_TABLES { + let bits = log2_strict(crate::circuit::fp8::luts::lut_height(table)); + degree_ranges.push((bits, bits)); + } + UniversalVerifierEnvelope { + degree_ranges, + ladder: FP16_REACHABLE_DEGREE_BITS.to_vec(), + grouped_tables: FP16_GROUPED_TABLES.to_vec(), + } +} + +/// Domain-separation label for the FP16 statement digest. The FP16 scheme reuses the FP8 transcript +/// domain (its jackpot/key subkeys are already the `pearl/v4/FP8/` labels), so this stays under that +/// prefix — distinct from the FP8 block digest's own `pearl/v4/FP8/zk-public`. +/// [`derive_statement_digest`] hashes the proven lottery digest under it. +const LABEL_FP16_ZK_PUBLIC: &[u8] = b"pearl/v4/FP8/fp16-zk-public"; + +/// The proven lottery digest `J` reassembled from the Blake3 table's `HASH_JACKPOT` public-input +/// limbs (8 little-endian `u32` words, the STARK witness key encoding). The FP16 analogue of the +/// FP8 driver's `hash_jackpot`. +pub(crate) fn hash_jackpot(blake3_pis: &[F]) -> Hash256 { + let limbs: &[F; 8] = blake3_pis[PI_HASH_JACKPOT..PI_HASH_JACKPOT + 8] + .try_into() + .expect("HASH_JACKPOT occupies 8 Blake3 public-input limbs"); + u32_field_array_to_hash(limbs) +} + +/// Derives the Fiat-Shamir statement digest from the PROVEN lottery digest `J` — the FP16 analogue +/// of the FP8 driver's `derive_statement_digest` callback (`H_"zk-public"(…)`). This ties the salt +/// the known-column binding absorbs to the batch's own `HASH_JACKPOT`, so a verified proof attests +/// "this policy-passing tile folds to this jackpot under this derived statement," not an opaque +/// caller-chosen salt. Binding `J` to the consensus block header (the full +/// `H_"zk-public"(σ̂ || public_data)` FP8 does) remains the documented follow-on; this increment +/// binds the output chain `tile -> HASH_JACKPOT -> statement_digest`. +pub(crate) fn derive_statement_digest(hash_jackpot: Hash256) -> Hash256 { + hash_labelled(&hash_jackpot, LABEL_FP16_ZK_PUBLIC, None) +} + +/// Reduces a 32-byte statement digest into four Goldilocks elements (little-endian integer mod +/// `p^4`) — the Fiat-Shamir salt the known-column binding absorbs, and the wrapper's pinned +/// `known-column digest` public inputs. +pub(crate) fn statement_digest_to_hash_out(digest: Hash256) -> HashOut { + let p = U256::from(F::ORDER); + let mut value = U256::from_little_endian(&digest); + let mut elements = [F::ZERO; 4]; + for element in &mut elements { + *element = F::from_canonical_u64((value % p).as_u64()); + value /= p; + } + HashOut { elements } +} + +/// The FP16 batch [`StarkConfig`] for a job whose tables have the given `degree_bits` (any order, +/// duplicates allowed). The FRI reduction schedule is a [`FriReductionStrategy::Ladder`] whose +/// boundaries are [`FP16_REACHABLE_DEGREE_BITS`] unioned with the job's own heights (descending, +/// deduped), so every table's height is a fold boundary (batch FRI injects each instance at its +/// LDE size) and gaps are auto-split into steps of at most 3 bits. For an on-ladder job the union +/// equals the consensus ladder, so the config — hence the absorbed Fiat-Shamir transcript — is a +/// consensus constant (the universal-wrapper prerequisite). +pub fn fp16_stark_config(degree_bits: &[usize]) -> StarkConfig { + let min = degree_bits.iter().copied().min().expect("at least one table"); + assert!( + min + STARK_RATE_BITS >= STARK_CAP_HEIGHT, + "the smallest table's LDE must cover the Merkle cap" + ); + let mut boundaries: Vec = FP16_REACHABLE_DEGREE_BITS.iter().chain(degree_bits).copied().collect(); + boundaries.sort_unstable_by_key(|&bits| core::cmp::Reverse(bits)); + boundaries.dedup(); + StarkConfig::new( + STARK_SECURITY_BITS, + STARK_NUM_CHALLENGES, + FriConfig { + rate_bits: STARK_RATE_BITS, + cap_height: STARK_CAP_HEIGHT, + proof_of_work_bits: STARK_POW_BITS, + reduction_strategy: FriReductionStrategy::Ladder(boundaries), + num_query_rounds: STARK_QUERY_ROUNDS, + }, + ) +} + +// ================================================================================================== +// Quantization chain geometry (increment 6b) +// ================================================================================================== + +/// The fixed noise rank the quant chain uses (`dr`/`dos` are then compile-time bf16 constants). +pub const FP16_QUANT_R: usize = 32; + +/// The smallest on-ladder ([`FP16_REACHABLE_DEGREE_BITS`]) trace height `>= live`. The quant chain's +/// three tables are padded to this common height so every legal tile keeps them on the consensus +/// FRI fold ladder (the universal-wrapper prerequisite), covering the real `(h + w) * k` operand +/// elements with trailing padding. +pub fn fp16_quant_num_rows(live: usize) -> usize { + FP16_REACHABLE_DEGREE_BITS + .iter() + .map(|&b| 1usize << b) + .filter(|&h| h >= live) + .min() + .expect("the live element count exceeds the ladder's top height") +} + +/// The per-side noise-seed public-parameter encodings (`p_A` / `p_B`) for an `h x w` tile with inner +/// `k`, built bit-exact with [`crate::api::fp16::plain_proof::Fp16JobParams::encode_p_a`] / +/// `encode_p_b` so the driver derives the noise seeds through the exact same `api::fp16::noise` +/// recipe as the plaintext certificate. +/// +/// The driver's simplified job model commits the whole operand as the tile (so `num_rows = h` / `w` +/// and the pattern is a single dense tile dim) under a fixed placeholder ancestor header. In +/// production the consensus layer supplies the real header-derived params (ancestor, pattern, …) — +/// the same test-vs-header boundary the opening keys ([`Fp16System::prove`]'s `key_a`/`key_b`) sit +/// on. The content only matters in that both the circuit and the plaintext comparison fold the same +/// `p` into [`noise_seeds`]. +pub(crate) fn fp16_noise_seed_params( + h: usize, + w: usize, + k: usize, + a_hash_id: HashId, + b_hash_id: HashId, +) -> Sides> { + use crate::api::fp16::params::Fp16Device; + use crate::api::fp16::plain_proof::{Fp16JobParams, Fp16OperandParams}; + use crate::api::layout::{AxisPattern, DimType}; + let pattern = |n: usize| AxisPattern::new(&[(n as u32, DimType::Blake)]).expect("dense tile pattern"); + let job = Fp16JobParams { + ancestor_header: IncompleteBlockHeader::zero(), + device: Fp16Device::A100, + k: k as u32, + r: FP16_QUANT_R as u32, + operands: Sides { + a: Fp16OperandParams { num_rows: h as u32, hash_id: a_hash_id, pattern: pattern(h) }, + b: Fp16OperandParams { num_rows: w as u32, hash_id: b_hash_id, pattern: pattern(w) }, + }, + }; + Sides { a: job.encode_p_a(), b: job.encode_p_b() } +} + +/// The root-derived per-side noise seeds `noise_seeds({key_a, key_b}, {root_a, root_b}, {p_a, p_b})` +/// for an `h x w` tile over the committed operands `a_codes`/`b_codes` — the exact +/// [`crate::api::fp16::noise::noise_seeds`] the plaintext certificate derives. `root_X = +/// commit_operand(..).root()` (bit-exact with the batch's `HASH_A`/`HASH_B`), so the seeds — and +/// hence every derived XOF byte, every noise line, `N`, the noised operands, the tile and the +/// jackpot — are a pure function of the COMMITTED operands: the noise is operand-dependent and fully +/// anti-grind. Pipeline order: operands -> commit -> roots -> `noise_seeds` -> noise. +pub(crate) fn fp16_root_derived_seeds( + h: usize, + w: usize, + k: usize, + a_hash_id: HashId, + b_hash_id: HashId, + key_a: Hash256, + key_b: Hash256, + a_codes: &[u16], + b_codes: &[u16], +) -> anyhow::Result> { + let root_a = commit_operand(a_codes, h, k, a_hash_id, key_a)?.root(); + let root_b = commit_operand(b_codes, w, k, b_hash_id, key_b)?.root(); + let p = fp16_noise_seed_params(h, w, k, a_hash_id, b_hash_id); + Ok(noise_seeds(&Sides { a: key_a, b: key_b }, &Sides { a: root_a, b: root_b }, &p)) +} + +/// The real, seed-derived FP16 noise factors for an `h x w` tile under the ROOT-DERIVED `seeds` +/// ([`fp16_root_derived_seeds`]) — DISTINCT `F_A`/`F_B` (the plaintext's distinct `F`). Returns +/// `(E_A, F_A, E_B, F_B)`, each a row-major stack of normalized FP16 lines, bit-exact with +/// [`crate::api::fp16::noise::sample_noise`] over `seeds` and global row/col indices `0..h` / `0..w`: +/// `E_A` is `h` lines, `F_A`/`F_B` are `k` lines, `E_B` is `w` lines; each line `r = FP16_QUANT_R` +/// entries. `N_A = E_A @ F_A^T`, `N_B = E_B @ F_B^T`. +pub(crate) fn fp16_tile_noise(seeds: Sides, h: usize, w: usize, k: usize) -> (Vec, Vec, Vec, Vec) { + use crate::api::fp16::noise::sample_noise; + let a_rows: Vec = (0..h as u32).collect(); + let b_cols: Vec = (0..w as u32).collect(); + let noise = sample_noise(k, FP16_QUANT_R as u16, seeds, &a_rows, &b_cols); + (noise.a.e, noise.a.f, noise.b.e, noise.b.f) +} + +/// The per-line noise-matmul reuse multiplicities (the `OPERAND_MULT` known column) in NoiseStark line +/// order `[E_A (h), F_A (k), E_B (w), F_B (k)]`: `k` for an `E` line, `h`/`w` for an `F` line. These are +/// seed-independent (pure geometry), so [`Fp16System::new`] derives the NoiseStark program from them +/// without any operand/seed. +pub(crate) fn fp16_noise_mults(h: usize, w: usize, k: usize) -> Vec { + let mut mults: Vec = Vec::with_capacity(h + w + 2 * k); + mults.extend(std::iter::repeat_n(k as u64, h)); // E_A lines + mults.extend(std::iter::repeat_n(h as u64, k)); // F_A lines + mults.extend(std::iter::repeat_n(k as u64, w)); // E_B lines + mults.extend(std::iter::repeat_n(w as u64, k)); // F_B lines + mults +} + +/// The raw keyed-BLAKE3-XOF bytes of every noise line for an `h x w` tile under the ROOT-DERIVED +/// `seeds`, concatenated in NoiseStark line order `[E_A (h), F_A (k), E_B (w), F_B (k)]`. Feeding them +/// to NoiseStark yields output bit-exact with the normalized lines [`fp16_tile_noise`] returns. (The +/// companion multiplicities are [`fp16_noise_mults`], which is seed-independent.) +pub(crate) fn fp16_tile_noise_xof(seeds: Sides, h: usize, w: usize, k: usize) -> Vec { + let r = FP16_QUANT_R as u16; + let (sa, sb) = (seeds.a, seeds.b); + let mut bytes: Vec = Vec::new(); + for row in 0..h as u32 { + bytes.extend_from_slice(&sample_line_xof_bytes(&sa, Side::A, NoiseFactor::E, row, r)); + } + for i in 0..k as u32 { + bytes.extend_from_slice(&sample_line_xof_bytes(&sb, Side::A, NoiseFactor::F, i, r)); + } + for col in 0..w as u32 { + bytes.extend_from_slice(&sample_line_xof_bytes(&sb, Side::B, NoiseFactor::E, col, r)); + } + for i in 0..k as u32 { + bytes.extend_from_slice(&sample_line_xof_bytes(&sb, Side::B, NoiseFactor::F, i, r)); + } + bytes +} + +/// One side's noise matmul geometry (increment 6e-2): a +/// [`crate::circuit::fp16::matmul_a100_stark::MatmulStarkA100`] of output `m x k` (A: `m = h`; B: +/// `m = w`) with inner dimension [`FP16_QUANT_R`], computing `N = E @ F^T`. Returns +/// `(m, k_out, k_inner, height)`, the height being the live row count `m*k*(FP16_QUANT_R/GROUP)` +/// snapped up to a [`FP16_REACHABLE_DEGREE_BITS`] member (forced via [`MatmulStarkA100::new_with_height`]). +pub(crate) fn fp16_noise_matmul_geometry(m: usize, k: usize) -> (usize, usize, usize, usize) { + use super::matmul_a100_stark::columns::GROUP; + let k_inner = FP16_QUANT_R; + let live = m * k * (k_inner / GROUP); + (m, k, k_inner, fp16_quant_num_rows(live)) +} + +/// The proven noised FP16 operands for an `h x w` tile over the committed `a_codes`/`b_codes`: +/// `noisy_quantize` over each operand row with the real ROOT-DERIVED noise (distinct `F_A`/`F_B`, +/// seeds = [`fp16_root_derived_seeds`] over the committed roots/keys/params), bit-exact with the +/// batch's quant-chain `out` column (hence with what the matmul multiplies — see +/// [`Fp16System::noised_operands`]). A free helper so test fixtures can pick an operand whose NOISED +/// tile clears the policy gate without constructing a full system; the keys/hash ids must match the +/// [`Fp16System`] the operand will be proven under so the derived noise is the same. +/// Seed-exact noised operands for a tile, through the full real pipeline +/// (root-derived seeds -> noise lines -> `noisy_quantize`). Public so offline +/// validation tooling (`docs/fp16_scheme/validation`) can reproduce consensus +/// noise bit-for-bit rather than approximating it. +pub fn fp16_noised_operands( + h: usize, + w: usize, + k: usize, + a_codes: &[u16], + b_codes: &[u16], + key_a: Hash256, + key_b: Hash256, + a_hash_id: HashId, + b_hash_id: HashId, +) -> anyhow::Result<(Vec, Vec)> { + use crate::api::fp16::quantization::{noisy_quantize, row_norms}; + let r = FP16_QUANT_R; + let seeds = fp16_root_derived_seeds(h, w, k, a_hash_id, b_hash_id, key_a, key_b, a_codes, b_codes)?; + let (e_a, f_a, e_b, f_b) = fp16_tile_noise(seeds, h, w, k); + let mut sides: Vec> = Vec::with_capacity(2); + for (codes, num_rows, e, f) in [(a_codes, h, &e_a, &f_a), (b_codes, w, &e_b, &f_b)] { + let norms: Vec<(u16, u16)> = (0..num_rows) + .map(|i| row_norms(&codes[i * k..(i + 1) * k])) + .collect::>()?; + sides.push(noisy_quantize(codes, e, f, &norms, r)?.noised_part); + } + Ok((sides.remove(0), sides.remove(0))) +} + +// ================================================================================================== +// The system +// ================================================================================================== + +/// One FP16 tile's fully derived proving/verifying context. Built from the public geometry +/// `(h, w, k)` alone; the prover supplies the private operand codes to [`Self::prove`]. +pub struct Fp16System, const D: usize> { + matmul: MatmulStarkA100, + policy: PolicyStarkA100, + /// The XorFold lottery mixer: folds the matmul output tile into the 16 lottery lanes. + xor_fold: XorFoldStark, + /// The full FP16 Blake3 commitment: operand-A tree (-> `HASH_A`, keyed `KEY_A`), operand-B tree + /// (-> `HASH_B`, keyed `KEY_B`), and the keyed compression of the 16 lottery words to + /// `HASH_JACKPOT`. + blake3: Blake3Stark, + /// The per-operand Merkle leaf sizes ([`HashId::chunk_len`]) the Blake3 operand trees commit + /// under. Geometry of the Blake3 program, so they are fixed at construction. + a_hash_id: HashId, + b_hash_id: HashId, + /// The quantization chain (increment 6b): the per-row scale derivation, the fused noisy-quant + /// (G1 pre-FMA multiply + G3 FP16 cast), and the single-rounding G2 FMA. They prove the noised + /// operand `noised = Q(alpha*raw + beta*N)` over a fixed in-envelope witness operand row; `raw` + /// and `N` are free witness (binding them is increments 6c/6e). + row_scale: RowScaleStark, + noisy_quant: NoisyQuantStark, + noisy_quant_fma: NoisyQuantFmaStark, + /// The A-side noise matmul (increment 6e-2): `N_A = E_A @ F_A^T` (`h x k`, inner [`FP16_QUANT_R`]). + /// Its cell results bind to noisy-quant's A-side `(NOISE_LO, NOISE_HI)` (noise-word CTL); its + /// `E_A`/`F_A` operands bind to NoiseStark's proven normalized lines (E/F-operand CTL). Padded to + /// an on-ladder height. + noise_matmul_a: MatmulStarkA100, + /// The B-side noise matmul (increment 6e-2): `N_B = E_B @ F_B^T` (`w x k`, inner [`FP16_QUANT_R`]), + /// with DISTINCT `F_B` (restores the plaintext's distinct `F`). Cell results bind to noisy-quant's + /// B-side noise words (offset `h*k`); `E_B`/`F_B` bind to NoiseStark (offset `(h+k)*r`). + noise_matmul_b: MatmulStarkA100, + /// The NoiseStark line AIR (increment 6e-2): proves `normalize_line` for every noise line of the + /// tile (`E_A`, `F_A`, `E_B`, `F_B`), its normalized FP16 output bound to the two noise matmuls' + /// `E`/`F` operands. The raw XOF bytes stay free witness (seed-keyed-XOF binding is 6e-3). + noise_stark: NoiseStark, + /// The noise-BLAKE3 derivation AIR (increment 6e-3d): recomputes every noise line's + /// keyed-BLAKE3-XOF bytes in-circuit from the seeds (its `KEY_A`/`KEY_B` public inputs, which are + /// the ROOT-DERIVED noise seeds), egressing each line's `cv_out`. The egress-pair CTL binds those + /// limbs to NoiseStark's XOF-byte inputs, so the noise is bound to the seeds, and the seeds are + /// bound to the committed operand roots. Padded to an on-ladder height. + noise_blake3: Fp16RawBlake3Stark, + /// The per-side noise-seed public-parameter encodings (`p_A`/`p_B`) folded into the seed chain + /// ([`fp16_noise_seed_params`]). Together with the committed roots (`HASH_A`/`HASH_B`) and the + /// opening keys — both carried in the Blake3 public inputs — they determine the root-derived noise + /// seeds `verify` pins the noise-BLAKE3 `KEY_A`/`KEY_B` to. + noise_seed_params: Sides>, + /// The five committed-LUT AIRs at their exact widths, in committed order. + luts: [Box>; NUM_FP16_LUT_TABLES], + h: usize, + w: usize, + k: usize, + /// Per-table trace degree bits in canonical batch order (matmul, policy, then the LUTs). + degree_bits: [usize; NUM_FP16_TABLES], + /// The config for this job's degree profile. + config: StarkConfig, + /// Class (a) known columns of the two main tables (the LUT positions are empty). + known: BatchKnownColumns, + /// All CTL channels (four LUT channels + census import), table indices in canonical order. + ctls: Vec>, +} + +impl, const D: usize> Fp16System { + /// Derives the full batching context for an `h x w` tile with inner dimension `k`. + /// + /// The lottery layout (which of the `h*w` output cells each of the 16 lanes folds) is derived + /// canonically from `(h, w)` via [`default_lane_layout`] — the committed extractor layout of + /// [`crate::api::layout`]. `h*w` must admit a 16-lane Blake split (see [`default_lane_layout`]). + pub fn new(h: usize, w: usize, k: usize, a_hash_id: HashId, b_hash_id: HashId) -> Self { + let matmul = MatmulStarkA100::::new(h, w, k); + let policy = PolicyStarkA100::::new(h, w, k); + let (row_axis, col_axis) = default_lane_layout(h, w); + let xor_fold = XorFoldStark::::new(XorFoldProgram { + lanes: lane_assignment(&row_axis, &col_axis), + }); + // The committed operand byte lengths: A is `h x k` FP16 (`h*k*2` LE bytes), B is `w x k` + // over the transposed operand (`w*k*2` LE bytes). These are the `commit_operand` row-byte + // lengths the two keyed Merkle trees are built over. + let a_len = h * k * 2; + let b_len = w * k * 2; + let blake3 = Blake3Stark::::new(fp16_blake3_program( + a_len, + a_hash_id.chunk_len(), + b_len, + b_hash_id.chunk_len(), + )); + + // The quantization chain (increment 6b-extended). It proves `noised = Q(alpha*raw + beta*N)` + // over EVERY operand row of BOTH operands: `h` A rows then `w` B rows, each `k` elements + // (rank `FP16_QUANT_R`). `raw` is the caller's real tile operands; `N` is still free witness + // (binding `raw`/`N` to the operand commitment / `E@F` is increments 6c/6e). The three tables + // are padded to a common on-ladder height (`fp16_quant_num_rows`) covering `(h + w) * k`. + let quant_operand_rows = h + w; + let quant_live = quant_operand_rows * k; + let quant_height = fp16_quant_num_rows(quant_live); + let row_scale = + RowScaleStark::::new(RowScaleProgram::with_rows_ab(h, w, k, FP16_QUANT_R, quant_height)); + // The operand-codes (6d) looked-side multiplicity: an A-side element (operand rows `0..h`) is + // reused in `w` output cells, a B-side element (rows `h..h+w`) in `h` cells. + let noisy_quant = NoisyQuantStark::::new(NoisyQuantProgram::with_rows(quant_live, k, quant_height, h, w, h)); + let noisy_quant_fma = NoisyQuantFmaStark::::new(FmaProgram::with_rows(quant_live, quant_height)); + // The two per-side noise matmuls `N_A = E_A @ F_A^T` (`h x k`) and `N_B = E_B @ F_B^T` + // (`w x k`), inner `FP16_QUANT_R`, each padded to an on-ladder height (6e-2, distinct `F`). + let (man, _, kin_a, noise_height_a) = fp16_noise_matmul_geometry(h, k); + let noise_matmul_a = MatmulStarkA100::::new_with_height(man, k, kin_a, noise_height_a); + let (mbn, _, kin_b, noise_height_b) = fp16_noise_matmul_geometry(w, k); + let noise_matmul_b = MatmulStarkA100::::new_with_height(mbn, k, kin_b, noise_height_b); + // NoiseStark: every noise line (`E_A`,`F_A`,`E_B`,`F_B`) at rank `FP16_QUANT_R`, with the + // per-line reuse multiplicities, padded to an on-ladder height covering `(h+w+2k)*r` entries. + let noise_mults = fp16_noise_mults(h, w, k); + let noise_live = noise_mults.len() * FP16_QUANT_R; + let noise_stark_height = fp16_quant_num_rows(noise_live); + let noise_stark = + NoiseStark::::new(NoiseProgram::with_lines(FP16_QUANT_R, noise_mults, noise_stark_height)); + + // The noise-BLAKE3 derivation table (6e-3d): recompute every line's keyed-XOF in-circuit from + // the seeds (the engine's KEY_A/KEY_B public inputs), egressing each line's cv_out for the + // egress-pair CTL. Padded to an on-ladder height. The program structure is seed-independent; + // the seeds enter as the KEY_A/KEY_B public inputs, which are now the ROOT-DERIVED noise seeds + // ([`fp16_root_derived_seeds`]) — operand-dependent, so they are computed per proof/verify + // from the committed roots rather than stored here. `noise_seed_params` carries the `p` + // half of the seed chain. + let noise_blake3_bits = noise_blake3_height_bits(h, w, k); + let noise_blake3 = + Fp16RawBlake3Stark::::new(noise_blake3_program(h, w, k, Some(noise_blake3_bits))); + let noise_seed_params = fp16_noise_seed_params(h, w, k, a_hash_id, b_hash_id); + + // Class (a) known columns: each main table's leading geometry/layout columns, bit-exact with + // its trace. The verifier recomputes these and binds the trace openings to them. + let matmul_known = matmul.known_values(); + let policy_known = policy.known_values(); + let xor_fold_known = xor_fold.program.known_values::(); + let blake3_known = blake3.program.known_values::(&Blake3KnownInputs { + a_values_len: a_len, + a_scales_len: 0, + b_values_len: b_len, + b_scales_len: 0, + }); + let row_scale_known = row_scale.program.known_values::(); + let noisy_quant_known = noisy_quant.program.known_values::(); + let fma_known = noisy_quant_fma.program.known_values::(); + let noise_matmul_a_known = noise_matmul_a.known_values(); + let noise_matmul_b_known = noise_matmul_b.known_values(); + let noise_stark_known = noise_stark.program.known_values::(); + let noise_blake3_known = noise_blake3.program.known_values::(&Fp16RawBlake3KnownInputs { + a_values_len: 0, + a_scales_len: 0, + b_values_len: 0, + b_scales_len: 0, + }); + let mut columns_per_table = vec![Vec::new(); NUM_FP16_TABLES]; + let mut values_per_table = vec![Vec::new(); NUM_FP16_TABLES]; + for (table, known) in [ + (MATMUL_A100_TABLE, matmul_known), + (super::ctl::POLICY_A100_TABLE, policy_known), + (XOR_FOLD_A100_TABLE, xor_fold_known), + (BLAKE3_A100_TABLE, blake3_known), + (ROW_SCALE_A100_TABLE, row_scale_known), + (NOISY_QUANT_A100_TABLE, noisy_quant_known), + (NOISY_QUANT_FMA_A100_TABLE, fma_known), + (NOISE_MATMUL_A_A100_TABLE, noise_matmul_a_known), + (NOISE_MATMUL_B_A100_TABLE, noise_matmul_b_known), + (NOISE_STARK_A100_TABLE, noise_stark_known), + (NOISE_BLAKE3_A100_TABLE, noise_blake3_known), + ] { + columns_per_table[table] = (0..known.len()).collect(); + values_per_table[table] = known; + } + let known = BatchKnownColumns { + digest: None, + columns_per_table, + values_per_table, + }; + + // Per-table heights -> degree bits (canonical order). Each main table's height comes from + // its own geometry; the LUTs' heights are consensus constants. + assert_eq!(matmul.num_rows(), policy.num_rows(), "matmul and policy share the row grid"); + let main_heights = [ + matmul.num_rows(), + policy.num_rows(), + xor_fold.program.num_rows(), + blake3.program.num_rows(), + row_scale.program.num_rows(), + noisy_quant.program.num_rows(), + noisy_quant_fma.program.num_rows(), + noise_matmul_a.num_rows(), + noise_matmul_b.num_rows(), + noise_stark.program.num_rows(), + noise_blake3.program.num_rows(), + ]; + let degree_bits: [usize; NUM_FP16_TABLES] = core::array::from_fn(|t| { + if t < NUM_FP16_MAIN_TABLES { + log2_strict(main_heights[t]) + } else { + log2_strict(crate::circuit::fp8::luts::lut_height(FP16_LUT_TABLES[t - NUM_FP16_MAIN_TABLES])) + } + }); + let config = fp16_stark_config(°ree_bits); + let ctls = all_cross_table_lookups::(h, w, k); + + Self { + matmul, + policy, + xor_fold, + blake3, + a_hash_id, + b_hash_id, + row_scale, + noisy_quant, + noisy_quant_fma, + noise_matmul_a, + noise_matmul_b, + noise_stark, + noise_blake3, + noise_seed_params, + luts: FP16_LUT_TABLES.map(boxed_lut_stark::), + h, + w, + k, + degree_bits, + config, + known, + ctls, + } + } + + /// The config of this job's degree profile. + pub fn config(&self) -> &StarkConfig { + &self.config + } + + /// Per-table trace degree bits in canonical batch order. + pub fn degree_bits(&self) -> &[usize; NUM_FP16_TABLES] { + &self.degree_bits + } + + /// The tile geometry (`|I_A|`, `|I_B|`, inner `k`) — used by the header-bound gateways for the + /// native `check_jackpot_difficulty` call. + pub(crate) fn tile_geometry(&self) -> (usize, usize, usize) { + (self.h, self.w, self.k) + } + + /// The (shared) row height of the two main tables. + pub fn num_rows(&self) -> usize { + self.matmul.num_rows() + } + + /// The root-derived noise seeds for this tile's committed operands: `noise_seeds({key_a, key_b}, + /// {root_a, root_b}, {p_a, p_b})` with `root_X = commit_operand(..).root()` and `p` this system's + /// [`Self::new`]-time [`fp16_noise_seed_params`]. The single source of truth for the witness noise + /// (`generate_batch_traces`) — the verify path recomputes the same seeds straight from the Blake3 + /// public inputs ([`Self::noise_seeds_from_blake3_pis`]). + pub(crate) fn root_derived_seeds(&self, a_codes: &[u16], b_codes: &[u16], key_a: Hash256, key_b: Hash256) -> Result> { + // Fold THIS system's `p` encodings (the [`Self::new`] placeholder by default, or the real + // header-derived job's encodings when [`Self::set_noise_seed_params`] has been called by the + // header gateway's honest prover) into the seed chain -- so the prover and + // [`Self::verify_with_headers`] agree on `p`. Equivalent to [`fp16_root_derived_seeds`] when + // `noise_seed_params` is the default placeholder. + let root_a = commit_operand(a_codes, self.h, self.k, self.a_hash_id, key_a)?.root(); + let root_b = commit_operand(b_codes, self.w, self.k, self.b_hash_id, key_b)?.root(); + Ok(noise_seeds( + &Sides { a: key_a, b: key_b }, + &Sides { a: root_a, b: root_b }, + &self.noise_seed_params, + )) + } + + /// Overrides the per-side noise-seed public-parameter encodings `p_A`/`p_B` (default: the + /// [`Self::new`] placeholder job's [`fp16_noise_seed_params`]). The header gateway's honest prover + /// sets these to the REAL job's [`Fp16JobParams::encode_p_a`]/`encode_p_b`, so the prover's seed + /// chain folds the header-derived public parameters that [`Self::verify_with_headers`] recomputes + /// from the job and pins to. Only affects the seed derivation ([`Self::root_derived_seeds`]) and + /// the noise-BLAKE3 `KEY_A`/`KEY_B` public-input pins; the table geometry is `p`-independent. + pub(crate) fn set_noise_seed_params(&mut self, p: Sides>) { + self.noise_seed_params = p; + } + + /// The root-derived noise seeds read straight from a Blake3 public-input vector: the opening keys + /// (`PI_KEY_A`/`PI_KEY_B`) and the committed operand roots (`PI_HASH_A`/`PI_HASH_B`) folded with + /// this system's `p` encodings through [`noise_seeds`]. Because [`Self::verify`] pins + /// `HASH_A`/`HASH_B`/`KEY_A`/`KEY_B` to the expected (header-derived) limbs and this is what fixes + /// the noise-BLAKE3 `KEY_A`/`KEY_B` public inputs, a prover cannot substitute seeds not derived + /// from the committed roots. + fn noise_seeds_from_blake3_pis(&self, blake3_pis: &[F]) -> Sides { + let read = |base: usize| -> Hash256 { + let limbs: &[F; 8] = blake3_pis[base..base + 8].try_into().expect("8 Blake3 PI limbs"); + u32_field_array_to_hash(limbs) + }; + let keys = Sides { a: read(PI_KEY_A), b: read(PI_KEY_B) }; + let roots = Sides { a: read(PI_HASH_A), b: read(PI_HASH_B) }; + noise_seeds(&keys, &roots, &self.noise_seed_params) + } + + /// The all-channel CTL set (four LUT channels + census import) in canonical table order — for + /// the recursive wrapper, which re-runs the batch verifier in-circuit. + pub(crate) fn ctls(&self) -> &[CrossTableLookup] { + &self.ctls + } + + /// The class (a) known columns in canonical table order. The column indices shape the wrapper + /// circuit; the values feed the native evaluation-at-zeta recompute. The digest slot is filled + /// by [`Self::bind_statement_digest`]. + pub(crate) fn known(&self) -> &BatchKnownColumns { + &self.known + } + + /// Binds `statement_digest` into the known-column Fiat-Shamir slot. [`Self::prove`] must be + /// preceded by this (with the digest of the statement) for the wrapper paths, whose in-circuit + /// replay pins the digest; the native [`Self::verify`] is unaffected by the slot's contents. + pub fn bind_statement_digest(&mut self, statement_digest: Hash256) { + self.known.digest = Some(statement_digest_to_hash_out(statement_digest)); + } + + /// Cross-checks a caller-supplied `statement_digest` against the one bound into this system, if + /// any: a mismatch means the system and digest came from different statements. + pub fn ensure_statement_digest_binding(&self, statement_digest: Hash256) -> Result<()> { + ensure!( + self.known + .digest + .is_none_or(|bound| bound == statement_digest_to_hash_out(statement_digest)), + "the statement_digest disagrees with the one bound into the system's known columns" + ); + Ok(()) + } + + /// The batch tables in canonical order: matmul, policy, xor_fold, blake3, then the five + /// committed LUTs. + pub(crate) fn batch_starks(&self) -> [&dyn BatchStark; NUM_FP16_TABLES] { + core::array::from_fn(|t| { + if t == MATMUL_A100_TABLE { + &self.matmul as &dyn BatchStark + } else if t == super::ctl::POLICY_A100_TABLE { + &self.policy as &dyn BatchStark + } else if t == XOR_FOLD_A100_TABLE { + &self.xor_fold as &dyn BatchStark + } else if t == BLAKE3_A100_TABLE { + &self.blake3 as &dyn BatchStark + } else if t == ROW_SCALE_A100_TABLE { + &self.row_scale as &dyn BatchStark + } else if t == NOISY_QUANT_A100_TABLE { + &self.noisy_quant as &dyn BatchStark + } else if t == NOISY_QUANT_FMA_A100_TABLE { + &self.noisy_quant_fma as &dyn BatchStark + } else if t == NOISE_MATMUL_A_A100_TABLE { + &self.noise_matmul_a as &dyn BatchStark + } else if t == NOISE_MATMUL_B_A100_TABLE { + &self.noise_matmul_b as &dyn BatchStark + } else if t == NOISE_STARK_A100_TABLE { + &self.noise_stark as &dyn BatchStark + } else if t == NOISE_BLAKE3_A100_TABLE { + &self.noise_blake3 as &dyn BatchStark + } else { + self.luts[t - NUM_FP16_MAIN_TABLES].as_ref() + } + }) + } + + /// The batch public inputs: only the Blake3 table carries any (its 64-limb hash/key slots, with + /// `HASH_JACKPOT` the lottery output); every other table is public-input-free. + pub(crate) fn batch_public_inputs(&self, blake3_pis: &[F]) -> [Vec; NUM_FP16_TABLES] { + core::array::from_fn(|t| { + if t == BLAKE3_A100_TABLE { + blake3_pis.to_vec() + } else if t == NOISE_BLAKE3_A100_TABLE { + // The noise-BLAKE3 table's KEY_A/KEY_B public inputs ARE the ROOT-DERIVED noise seeds + // (6e-3d): derive them from the operand roots + keys carried in `blake3_pis` plus this + // system's `p` encodings. In `verify` `blake3_pis` is the pinned expectation, so this + // forces the proof's seeds to be `noise_seeds` of the committed roots. + let seeds = self.noise_seeds_from_blake3_pis(blake3_pis); + noise_blake3_public_inputs::(&seeds.a, &seeds.b) + } else { + Vec::new() + } + }) + } + + /// The setup-time commitment to the four LUTs' precommitted columns, placed at their batch + /// positions (`2..6`). The flat column list is job-independent, so the Merkle cap is a + /// consensus constant. + pub fn preprocessed_data>(&self, timing: &mut TimingTree) -> BatchStarkPreprocessedData { + let mut values = vec![Vec::new(); NUM_FP16_TABLES]; + let mut columns = vec![Vec::new(); NUM_FP16_TABLES]; + for (i, &table) in FP16_LUT_TABLES.iter().enumerate() { + let pos = fp16_lut_table_idx(i); + values[pos] = lut_precommitted_values::(table) + .into_iter() + .map(PolynomialValues::new) + .collect(); + columns[pos] = (0..num_precommitted_columns(table)).collect(); + } + BatchStarkPreprocessedData::new(values, columns, &self.config, timing) + } + + /// The verifier's view of the LUT precommitment: the consensus `cap` plus the per-table + /// preprocessed column indices (pinned by the statement, not taken from the proof). + pub fn preprocessed_verifier_data>( + &self, + cap: &MerkleCap, + ) -> BatchStarkPreprocessedVerifierData { + let mut columns_per_table = vec![Vec::new(); NUM_FP16_TABLES]; + for (i, &table) in FP16_LUT_TABLES.iter().enumerate() { + columns_per_table[fp16_lut_table_idx(i)] = (0..num_precommitted_columns(table)).collect(); + } + BatchStarkPreprocessedVerifierData { + cap: cap.clone(), + columns_per_table, + } + } + + /// Proves one tile: regenerates the matmul and policy traces from the operand codes (the + /// policy's per-step census is bound to the matmul's by the census-import CTL), accumulates + /// the committed-LUT multiplicities over both inventories, assembles the LUT traces, and runs + /// the batch prover. `a_codes` is `h*k` row-major FP16, `b_codes` is `w*k` row-major over the + /// transposed B. `preprocessed` is the setup-time LUT commitment ([`Self::preprocessed_data`]). + pub fn prove>( + &mut self, + a_codes: &[u16], + b_codes: &[u16], + key_a: Hash256, + key_b: Hash256, + jackpot_key: Hash256, + preprocessed: &BatchStarkPreprocessedData, + timing: &mut TimingTree, + ) -> Result> { + let (traces, blake3_pis) = self.generate_batch_traces(a_codes, b_codes, key_a, key_b, jackpot_key)?; + // Derive the Fiat-Shamir salt from the PROVEN jackpot (the FP8 pattern — the digest is no + // longer a caller-opaque salt), and bind it into the known-column slot before the batch + // prover absorbs the known columns. [`Self::statement_digest`] recovers it for the wrapper. + let statement_digest = derive_statement_digest(hash_jackpot::(&blake3_pis)); + self.bind_statement_digest(statement_digest); + self.prove_batch_traces(traces, &blake3_pis, preprocessed, timing) + } + + /// The Fiat-Shamir statement digest [`Self::prove`] derives from a proof's own `HASH_JACKPOT` + /// limbs — [`derive_statement_digest`] of [`hash_jackpot`]. The wrapper paths + /// ([`crate::circuit::fp16::wrapper`]) pass this to [`Self::bind_statement_digest`]'s binding + /// check and to the known-column digest public input, so a verified wrapped proof is pinned to + /// the batch's own proven jackpot. + pub fn statement_digest(blake3_pis: &[F]) -> Hash256 { + derive_statement_digest(hash_jackpot::(blake3_pis)) + } + + /// Generates the three quantization-chain traces (row-scale, noisy-quant G1/G3, G2 FMA) in + /// canonical batch order, over EVERY operand row of both operands (A rows then B rows). + /// The chain is: row-scale derives `(alpha, beta)` from `raw`; G1 computes `t = RNE(beta*N)`; G2 + /// computes `noised = fma(alpha, raw, t)`; G3 casts `noised` to FP16. `N = E@F^T` is computed + /// natively (the A100 datapath) and fed as the witness noise. The internal CTLs then bind + /// row-scale's scales to noisy-quant and G1/G3's `(t, noised)` to G2 inside the batch. + fn generate_quant_traces( + &self, + seeds: Sides, + a_codes: &[u16], + b_codes: &[u16], + ) -> ([Vec>; 3], Vec, Vec) { + let k = self.k; + let r = FP16_QUANT_R; + + // Per-element witness arrays over EVERY operand row of both operands (A rows then B rows). + let mut alpha_vec: Vec = Vec::new(); + let mut beta_vec: Vec = Vec::new(); + let mut raw_vec: Vec = Vec::new(); + let mut noise_vec: Vec = Vec::new(); + + // Real, ROOT-DERIVED noise with DISTINCT F_A/F_B: N_A = E_A@F_A^T, N_B = E_B@F_B^T on the + // committed A100 FP16 datapath, bit-exact with `sample_noise(noise_seeds(roots, keys, p))` + + // `a100_matmul`. + let (e_a, f_a, e_b, f_b) = fp16_tile_noise(seeds, self.h, self.w, k); + for (codes, num_rows, e, f) in [(a_codes, self.h, &e_a, &f_a), (b_codes, self.w, &e_b, &f_b)] { + let norms: Vec<(u16, u16)> = + (0..num_rows).map(|i| row_norms(&codes[i * k..(i + 1) * k]).expect("in-envelope operand norms")).collect(); + // The scales come from the real plaintext kernel; the row-scale AIR re-proves their + // derivation, and the scales-import CTL forces noisy-quant to consume them per row. + let built = noisy_quantize(codes, e, f, &norms, r).expect("in-envelope quant operand"); + let noise = a100_matmul(e, f, None, num_rows, k, r); + for i in 0..num_rows { + for j in 0..k { + alpha_vec.push(built.alpha[i]); + beta_vec.push(built.beta[i]); + raw_vec.push(codes[i * k + j]); + noise_vec.push(noise[i * k + j]); + } + } + } + + // G1 witness `t = beta*noise` (as f32), decomposed into the G2 input fields. + let n = raw_vec.len(); + let t: Vec = (0..n).map(|e| bf16_to_f32(beta_vec[e]) * noise_vec[e]).collect(); + let t_sign: Vec = t.iter().map(|&x| u64::from(x.to_bits() >> 31)).collect(); + let t_mant: Vec = t + .iter() + .map(|&x| if (x.to_bits() >> 23) & 0xFF == 0 { 0 } else { (1u64 << 23) + u64::from(x.to_bits() & 0x7F_FFFF) }) + .collect(); + let t_exp: Vec = t.iter().map(|&x| u64::from((x.to_bits() >> 23) & 0xFF)).collect(); + + // G2: derive `noised` from the single-rounding FMA (its proven output, read back to f32). + let fma_rows = self.noisy_quant_fma.program.generate_trace::(&alpha_vec, &raw_vec, &t_sign, &t_mant, &t_exp); + let noised: Vec = (0..n) + .map(|e| { + let lo = fma_rows[e][FMA_COL_MAP.noised_lo].to_canonical_u64(); + let hi = fma_rows[e][FMA_COL_MAP.noised_hi].to_canonical_u64(); + f32::from_bits(((hi << 16) | lo) as u32) + }) + .collect(); + + // G1 + G3 (noisy-quant), fed the G2-derived `noised`. + let nq_rows = self.noisy_quant.program.generate_trace::(&alpha_vec, &raw_vec, &beta_vec, &noise_vec, &noised); + // The proven noised FP16 codes (the `out` column) over every element, A rows then B rows. + // These — not the clean inputs — are what the matmul multiplies, so the operand-codes (6d) + // channel binds the matmul's codes to this exact `out` column. + let noised_codes: Vec = + (0..n).map(|e| nq_rows[e][NOISY_QUANT_COL_MAP.out].to_canonical_u64() as u16).collect(); + let noised_a = noised_codes[..self.h * k].to_vec(); + let noised_b = noised_codes[self.h * k..].to_vec(); + // Per-row scale derivation over A rows then B rows. + let mut all_raw = a_codes.to_vec(); + all_raw.extend_from_slice(b_codes); + let rs_rows = self.row_scale.program.generate_trace::(&all_raw); + + ([column_major(&rs_rows), column_major(&nq_rows), column_major(&fma_rows)], noised_a, noised_b) + } + + /// The proven noised FP16 operands the batch's matmul/policy multiply: the noisy-quant `out` + /// column over the A rows (`h*k`) and the B rows (`w*k`), bit-exact with + /// [`crate::api::fp16::quantization::noisy_quantize`] over the committed `raw` and the ROOT-DERIVED + /// noise ([`Self::root_derived_seeds`] over the committed roots / `key_a`/`key_b` / `p`). Exposed + /// so tests can build the plaintext tile / jackpot and check the noised tile clears the policy gate + /// over the SAME operands the matmul uses. + pub(crate) fn noised_operands(&self, a_codes: &[u16], b_codes: &[u16], key_a: Hash256, key_b: Hash256) -> (Vec, Vec) { + let seeds = self.root_derived_seeds(a_codes, b_codes, key_a, key_b).expect("in-envelope operands"); + let (_, noised_a, noised_b) = self.generate_quant_traces(seeds, a_codes, b_codes); + (noised_a, noised_b) + } + + /// Generates the batch traces (canonical order) from the operand codes and jackpot key, + /// returning them together with the Blake3 table's witness-generated public inputs (the + /// `HASH_JACKPOT` slot binds the lottery output). The matmul output tile is read off the matmul's + /// finished cells, folded by XorFold into the 16 lottery lanes, and committed by the Blake3 + /// jackpot compression; the committed-LUT multiplicities are accumulated over all four main + /// tables' inventories (which also re-validates every instance is served). Exposed so tests can + /// tamper a trace cell before proving. + pub fn generate_batch_traces( + &self, + a_codes: &[u16], + b_codes: &[u16], + key_a: Hash256, + key_b: Hash256, + jackpot_key: Hash256, + ) -> Result<([Vec>; NUM_FP16_TABLES], Vec)> { + ensure!(a_codes.len() == self.h * self.k, "a_codes must be h*k FP16 codes"); + ensure!(b_codes.len() == self.w * self.k, "b_codes must be w*k FP16 codes"); + + // The committed operand byte streams: the exact `u16` LE row bytes the two Blake3 operand + // trees (-> HASH_A / HASH_B) hash, bit-identical to `commit_operand`'s `rows_to_bytes` input. + let a_bytes = rows_to_bytes(a_codes); + let b_bytes = rows_to_bytes(b_codes); + + // ---- Noise seeds (6e-3d): operands -> commit -> roots -> `noise_seeds` -> noise. The seeds + // are `noise_seeds({key_a, key_b}, {root_a, root_b}, {p_a, p_b})` over the natively-committed + // roots (bit-exact with the Blake3 trace's HASH_A/HASH_B), so every noise value below is a pure + // function of the COMMITTED operands — the noise is operand-dependent and fully anti-grind. ---- + let seeds = self.root_derived_seeds(a_codes, b_codes, key_a, key_b)?; + + // ---- Quantization chain (increments 6b/6c/6d): prove `noised = Q(alpha*raw + beta*N)` over + // the COMMITTED `raw` (the clean `a_codes`/`b_codes`), and return the proven noised FP16 codes + // (`out`) the matmul multiplies. The internal CTLs (row-scale -> noisy-quant scales, G1/G3 <-> + // G2 FMA pairing) bind the chain together; the operand-bytes (6c) and operand-codes (6d) + // channels bind `raw` to the Blake3 commitment and `out` to the matmul operands below. ---- + let ([rs_cols, nq_cols, fma_cols_], noised_a, noised_b) = self.generate_quant_traces(seeds, a_codes, b_codes); + + // ---- Noise matmuls (6e-2): prove `N_A = E_A@F_A^T` and `N_B = E_B@F_B^T` in-batch over the + // SAME real root-derived `E`/`F` (distinct `F_A`/`F_B`) the quant chain's noise came from, so + // their cell results are bit-exact with the noise noisy-quant consumed (noise-word CTL, keyed by + // the global element index). NoiseStark proves every line's `normalize_line`, its output bound + // to these matmuls' `E`/`F` operands (E/F-operand CTL). ---- + let (e_a, f_a, e_b, f_b) = fp16_tile_noise(seeds, self.h, self.w, self.k); + let noise_mat_a_cols = column_major(&self.noise_matmul_a.generate_trace(&e_a, &f_a, None)); + let noise_mat_b_cols = column_major(&self.noise_matmul_b.generate_trace(&e_b, &f_b, None)); + let noise_xof = fp16_tile_noise_xof(seeds, self.h, self.w, self.k); + let noise_stark_cols = column_major(&self.noise_stark.program.generate_trace::(&noise_xof)); + + // ---- Noise-BLAKE3 (6e-3d): recompute every line's keyed-XOF in-circuit from the ROOT-DERIVED + // seeds (fed as the engine's KEY_A/KEY_B) and egress each line's cv_out. The egress-pair CTL + // binds those limbs to NoiseStark's XOF bytes, so the noise bytes are the keyed-BLAKE3 XOF of + // the root-derived seeds — operand-dependent, closing the anti-grind gap. ---- + let (nb_seed_ka, nb_seed_kb) = noise_seed_key_words(&seeds.a, &seeds.b); + let nb_aux = noise_blake3_aux_msgs(self.h, self.w, self.k); + let (nb_rows, nb_pis) = self.noise_blake3.program.generate_trace::(&Fp16RawBlake3TraceInputs { + a_values: &[], + a_scales: &[], + b_values: &[], + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: &nb_aux, + aux_cvs: &[], + lottery_words: NOISE_BLAKE3_LOTTERY_WORDS, + key_a: nb_seed_ka, + key_b: nb_seed_kb, + jackpot_key: bytes32_to_words(&NOISE_BLAKE3_JACKPOT_KEY), + a_hash_id: HashId::Blake3Chunk1024, + b_hash_id: HashId::Blake3Chunk1024, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + }); + let noise_blake3_cols = column_major(&nb_rows); + let noise_blake3_pis = noise_blake3_public_inputs::(&seeds.a, &seeds.b); + debug_assert_eq!( + nb_pis.to_vec(), + noise_blake3_pis, + "noise-BLAKE3 witness public inputs must equal the root-derived seed pins" + ); + + // ---- Matmul: the output tile and its per-cell f32 result words, over the NOISED operands. ---- + let mat_rows = self.matmul.generate_trace(&noised_a, &noised_b, None); + let mut cell_words = vec![0u32; self.h * self.w]; + for row in &mat_rows { + let v: &MatmulA100ColumnsView = row.borrow(); + if v.is_cell_final == F::ONE && v.is_padding == F::ZERO { + let cell = v.cell_id.to_canonical_u64() as usize; + cell_words[cell] = + (v.cell_result_f32_lo.to_canonical_u64() | (v.cell_result_f32_hi.to_canonical_u64() << 16)) as u32; + } + } + let mat_cols = column_major(&mat_rows); + // The policy scores the NOISED tile (the census-import CTL binds its per-step census to the + // matmul's, so both must be over the same noised operands). + let pol_cols = column_major(&self.policy.generate_trace(&noised_a, &noised_b)); + + // ---- XorFold: fold the matmul's finished cell words into the 16 lottery lanes. ---- + let xf_rows = self.xor_fold.program.generate_trace::(&cell_words); + let mut lottery_words = [0u32; 16]; + for row in &xf_rows { + let v: &XorFoldColumnsView = row.borrow(); + if v.is_lane_final == F::ONE { + lottery_words[v.lane_id.to_canonical_u64() as usize] = (v.rotation_input_top13.to_canonical_u64() + + (v.rotation_input_bottom19_limb_0.to_canonical_u64() << 13) + + (v.rotation_input_bottom19_limb_1.to_canonical_u64() << 29)) + as u32; + } + } + let xf_cols = column_major(&xf_rows); + + // ---- Blake3: the A/B operand Merkle trees (-> HASH_A / HASH_B under KEY_A / KEY_B) and the + // keyed compression of the 16 lottery words (-> HASH_JACKPOT). The operand bytes fed here are + // the committed CLEAN `a_codes`/`b_codes` (the quant chain's `raw`), so HASH_A / HASH_B are + // bit-exact with `commit_operand(..).root()`. The operand-bytes (6c) CTL binds these committed + // bytes to the quant `raw`, and the operand-codes (6d) CTL binds the quant `out` to the + // matmul operands, so the matmul provably multiplies the noised quantization of THESE committed + // operands. ---- + let (b3_rows, b3_pis) = self.blake3.program.generate_trace::(&Blake3TraceInputs { + a_values: &a_bytes, + a_scales: &[], + b_values: &b_bytes, + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: &[], + aux_cvs: &[], + lottery_words, + key_a: bytes32_to_words(&key_a), + key_b: bytes32_to_words(&key_b), + jackpot_key: bytes32_to_words(&jackpot_key), + a_hash_id: self.a_hash_id, + b_hash_id: self.b_hash_id, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + }); + let b3_cols = column_major(&b3_rows); + let b3_pis = b3_pis.to_vec(); + // The witness noise's seeds (derived from the natively-committed roots) must equal the seeds + // the verify path derives straight from the proof's Blake3 public inputs (HASH_A/HASH_B + + // keys) — i.e. the native commit roots match the proven HASH_A/HASH_B. Guarantees the proof's + // pinned noise-BLAKE3 KEY_A/KEY_B equal the trace's. + debug_assert_eq!( + self.noise_seeds_from_blake3_pis(&b3_pis), + seeds, + "root-derived seeds must match the Blake3-PI-derived seeds" + ); + + // Committed-LUT multiplicities over all main tables' inventories; the checker also + // re-validates every instance is served (fails fast on an unbalanceable proof). + let mut checker = LutChecker::::new(&FP16_LUT_TABLES); + for (table_idx, lookups) in &fp16_lut_inventories::() { + let (trace, pis): (&Vec>, &[F]) = match *table_idx { + super::ctl::MATMUL_A100_TABLE => (&mat_cols, &[]), + super::ctl::POLICY_A100_TABLE => (&pol_cols, &[]), + XOR_FOLD_A100_TABLE => (&xf_cols, &[]), + BLAKE3_A100_TABLE => (&b3_cols, &b3_pis), + ROW_SCALE_A100_TABLE => (&rs_cols, &[]), + NOISY_QUANT_A100_TABLE => (&nq_cols, &[]), + NOISY_QUANT_FMA_A100_TABLE => (&fma_cols_, &[]), + NOISE_MATMUL_A_A100_TABLE => (&noise_mat_a_cols, &[]), + NOISE_MATMUL_B_A100_TABLE => (&noise_mat_b_cols, &[]), + NOISE_STARK_A100_TABLE => (&noise_stark_cols, &[]), + NOISE_BLAKE3_A100_TABLE => (&noise_blake3_cols, noise_blake3_pis.as_slice()), + other => unreachable!("fp16 inventory table {other}"), + }; + checker + .check_trace(lookups, trace, pis, &format!("fp16 table {table_idx}")) + .map_err(|e| anyhow!(e))?; + } + + let mut traces: Vec>> = vec![ + mat_cols, + pol_cols, + xf_cols, + b3_cols, + rs_cols, + nq_cols, + fma_cols_, + noise_mat_a_cols, + noise_mat_b_cols, + noise_stark_cols, + noise_blake3_cols, + ]; + for table in FP16_LUT_TABLES { + traces.push(lut_trace::(table, checker.multiplicities.table_columns(table))); + } + let traces: [Vec>; NUM_FP16_TABLES] = traces.try_into().map_err(|_| anyhow!("table count"))?; + Ok((traces, b3_pis)) + } + + /// Runs the batch prover over pre-assembled traces and the Blake3 public inputs (the second half + /// of [`Self::prove`]). + pub fn prove_batch_traces>( + &self, + batch_traces: [Vec>; NUM_FP16_TABLES], + blake3_pis: &[F], + preprocessed: &BatchStarkPreprocessedData, + timing: &mut TimingTree, + ) -> Result> { + for (t, trace) in batch_traces.iter().enumerate() { + ensure!( + log2_strict(trace[0].len()) == self.degree_bits[t], + "batch table {t}: trace height differs from the statement's" + ); + } + batch_prove::( + &self.batch_starks(), + &self.config, + batch_traces, + &self.batch_public_inputs(blake3_pis), + &self.ctls, + &FP16_GROUPED_TABLES, + Some(preprocessed), + Some(&self.known), + timing, + ) + } + + /// Verifies one tile's proof against this statement and the consensus LUT cap: the degree + /// profile must equal the statement's, the public inputs must be empty, and the batch verifier + /// then checks every constraint, the class (a) openings against the recomputed known columns, + /// the CTL balances and the batched FRI argument. + pub fn verify>( + &self, + proof: &BatchStarkProofWithPublicInputs, + expected_blake3_pis: &[F], + lut_cap: &MerkleCap, + ) -> Result<()> { + ensure!( + proof.proof.degree_bits == self.degree_bits, + "the proof's degree profile differs from the statement's" + ); + ensure!( + expected_blake3_pis.len() == NUM_BLAKE3_PUBLIC_INPUTS, + "the expected Blake3 public inputs must be {NUM_BLAKE3_PUBLIC_INPUTS} limbs" + ); + // Pin every public-input slot to the expectation — the Blake3 table's HASH_A/HASH_B/ + // HASH_JACKPOT/key slots, and (6e-3d) the noise-BLAKE3 table's KEY_A/KEY_B slots, which + // `batch_public_inputs` sets to `noise_seeds` recomputed from the expected HASH_A/HASH_B + + // keys + this system's `p`. So the proof's noise seeds are forced to be the root-derived ones; + // a prover cannot substitute seeds not derived from the committed operand roots. + self.verify_pinned::(proof, &self.batch_public_inputs(expected_blake3_pis), lut_cap) + } + + /// The degree-profile + full public-input pin + batched-constraint/CTL/FRI verification, against a + /// fully-assembled expected public-input set (one `Vec` per table). Both [`Self::verify`] (which + /// builds the expectation from caller-supplied Blake3 limbs) and [`Self::verify_with_headers`] + /// (which builds it from the block headers) funnel through here, so the batch argument is checked + /// identically; only the source of the pinned expectation differs. + fn verify_pinned>( + &self, + proof: &BatchStarkProofWithPublicInputs, + expected: &[Vec; NUM_FP16_TABLES], + lut_cap: &MerkleCap, + ) -> Result<()> { + ensure!( + proof.proof.degree_bits == self.degree_bits, + "the proof's degree profile differs from the statement's" + ); + ensure!( + proof.public_inputs == *expected, + "the proof's public inputs differ from the expected ones" + ); + // Only the Blake3 table declares public inputs; the matmul, policy and XorFold AIRs do not. + const _: () = assert!( + NUM_MATMUL_A100_PUBLIC_INPUTS == 0 + && NUM_POLICY_A100_PUBLIC_INPUTS == 0 + && super::xor_fold_stark::columns::NUM_XOR_FOLD_PUBLIC_INPUTS == 0 + ); + batch_verify::( + &self.batch_starks(), + &self.config, + proof, + &self.ctls, + &FP16_GROUPED_TABLES, + Some(&self.preprocessed_verifier_data::(lut_cap)), + Some(&self.known), + &Default::default(), + ) + } + + /// The header-pinned consensus verify GATEWAY: the sound ZK entry that mirrors the plaintext + /// certificate's [`crate::api::fp16::verify::verify_fp16_plain_proof`] key/seed derivation, so + /// NOTHING feeding the noise seeds or the operand-tree commitment keys is test-supplied — it all + /// comes from the block headers + the public job params, exactly as the plaintext path does. + /// + /// Given the proposed header, the proof-carried `job` (ancestor header, `k`/`r`/device, per-side + /// `num_rows`/`hash_id`/pattern) and `nbits`, it: + /// 1. derives `keyA = key_a(proposed)`, `keyB = key_b(ancestor)` ([`commitment_keys`]) and + /// `p_a`/`p_b` ([`Fp16JobParams::encode_p_a`]/`encode_p_b`) — bit-exact with the plaintext cert; + /// 2. builds the EXPECTED Blake3 public inputs from the PROOF's committed `HASH_A`/`HASH_B`/ + /// `HASH_JACKPOT` (the operand roots + lottery output, which — as in the plaintext cert, whose + /// root likewise comes from the proof — are not header-derivable) with the operand-tree + /// `KEY_A`/`KEY_B` OVERWRITTEN by the header-derived keys, and sets the noise-BLAKE3 + /// `KEY_A`/`KEY_B` to `noise_seeds({keyA, keyB}, {HASH_A, HASH_B}, {p_a, p_b})`; + /// 3. pins `proof.public_inputs` to that expected set (so a proof whose operand-tree keys or whose + /// noise seeds are not header-derived is rejected), runs the full batch verification, and checks + /// `check_jackpot_difficulty` on the proven jackpot against `nbits`. + /// + /// The ONLY remaining consensus boundary is inherent: the caller supplies the header + `nbits`, and + /// is responsible for authenticating the `job.ancestor_header` as a member of the state window the + /// same way the plaintext FFI does ([`crate::bindings`]' hash-walk) before calling this — the + /// gateway assumes that window authentication, exactly as the plaintext `verify_fp16_plain_proof` + /// assumes its caller has. + /// Header-bound EXPECTED operand-Blake3 public inputs: the proof's own committed `HASH_A`/ + /// `HASH_B`/`HASH_JACKPOT` (operand roots + lottery output — not header-derivable, exactly as + /// the plaintext cert takes the root from the proof) with the three keys OVERWRITTEN by their + /// header/root-derived values: + /// * `PI_KEY_A = key_a(proposed)`, `PI_KEY_B = key_b(ancestor)` (the operand-tree opening keys); + /// * `PI_JACKPOT_KEY = jackpot_key(seed_a)` — the lottery-compression key, where + /// `seed_a = noise_seeds(keys, {HASH_A, HASH_B}, p).a`, exactly as the plaintext + /// [`compute_jackpot_ticket`](crate::api::fp8::transcript::compute_jackpot_ticket) keys the + /// ticket. Pinning it stops a prover grinding the jackpot key to hit difficulty without redoing + /// the tile work. + /// + /// Returns the expected operand-Blake3 PIs and the root-derived noise `seeds` (which + /// [`noise_blake3_public_inputs`] turns into the noise-BLAKE3 table's `KEY_A`/`KEY_B` pins). This + /// is the single source of truth for the key/seed/pow-key derivation shared by + /// [`Self::verify_with_headers`] and the wrapper's header-bound gateway + /// ([`crate::circuit::fp16::wrapper::verify_wrapped_proof_with_headers`]). + pub(crate) fn header_bound_blake3_pis( + &self, + proof_blake3_pis: &[F], + proposed_header: &IncompleteBlockHeader, + job: &Fp16JobParams, + ) -> (Vec, Sides) { + let keys = commitment_keys(proposed_header, &job.ancestor_header); + let p = Sides { a: job.encode_p_a(), b: job.encode_p_b() }; + let hash_to_words = |h: Hash256| -> [F; 8] { + core::array::from_fn(|i| F::from_canonical_u32(u32::from_le_bytes(h[4 * i..4 * i + 4].try_into().unwrap()))) + }; + let mut e = proof_blake3_pis.to_vec(); + e[PI_KEY_A..PI_KEY_A + 8].copy_from_slice(&hash_to_words(keys.a)); + e[PI_KEY_B..PI_KEY_B + 8].copy_from_slice(&hash_to_words(keys.b)); + let root_a: [F; 8] = e[PI_HASH_A..PI_HASH_A + 8].try_into().unwrap(); + let root_b: [F; 8] = e[PI_HASH_B..PI_HASH_B + 8].try_into().unwrap(); + let roots = Sides { a: u32_field_array_to_hash(&root_a), b: u32_field_array_to_hash(&root_b) }; + let seeds = noise_seeds(&keys, &roots, &p); + e[PI_JACKPOT_KEY..PI_JACKPOT_KEY + 8].copy_from_slice(&hash_to_words(jackpot_key(&seeds.a))); + (e, seeds) + } + + pub fn verify_with_headers>( + &self, + proof: &BatchStarkProofWithPublicInputs, + proposed_header: &IncompleteBlockHeader, + job: &Fp16JobParams, + nbits: u32, + lut_cap: &MerkleCap, + ) -> Result<()> { + ensure!( + proof.public_inputs[BLAKE3_A100_TABLE].len() == NUM_BLAKE3_PUBLIC_INPUTS, + "the proof's Blake3 public inputs must be {NUM_BLAKE3_PUBLIC_INPUTS} limbs" + ); + // 1-3. Header-derived expected operand-Blake3 PIs (keyA/keyB + the lottery-compression + // jackpot key pinned to their header/root-derived values) and the root-derived noise seeds. + let (expected_blake3, seeds) = + self.header_bound_blake3_pis(&proof.public_inputs[BLAKE3_A100_TABLE], proposed_header, job); + let expected: [Vec; NUM_FP16_TABLES] = core::array::from_fn(|t| { + if t == BLAKE3_A100_TABLE { + expected_blake3.clone() + } else if t == NOISE_BLAKE3_A100_TABLE { + noise_blake3_public_inputs::(&seeds.a, &seeds.b) + } else { + Vec::new() + } + }); + + // 4. Pin + full batch verification, then the native difficulty check on the proven jackpot — + // reusing `check_jackpot_difficulty` exactly as the plaintext `verify_tile_proof` does. + self.verify_pinned::(proof, &expected, lut_cap)?; + let jackpot = hash_jackpot::(&proof.public_inputs[BLAKE3_A100_TABLE]); + check_jackpot_difficulty(&jackpot, nbits, self.h as u32, self.w as u32, self.k as u32) + } + + /// The consensus-meaningful output gateway (the FP8 `zk.rs` `verify` + `native_epilogue` + /// analogue): runs [`Self::verify`] — the full batch verification plus the public-input pinning + /// that forces `HASH_A`/`HASH_B`/`HASH_JACKPOT` and the three keys to the caller-supplied + /// `expected_blake3_pis` (the consensus layer supplies these from the block header's proof + /// commitment + opening keys) — then applies the native difficulty check on the proven + /// `HASH_JACKPOT`, reusing [`check_jackpot_difficulty`] exactly as the plaintext + /// [`crate::api::fp16::verify::verify_tile_proof`] and the FP8 `zk.rs` epilogue do. Because + /// [`Self::verify`] has pinned `proof.public_inputs == expected`, the `HASH_JACKPOT` the + /// difficulty check reads off the proof equals the expected limbs. Returns `Ok(())` only if the + /// proof verifies, its public inputs equal the expectation, and the jackpot clears `nbits`. + pub fn verify_with_difficulty>( + &self, + proof: &BatchStarkProofWithPublicInputs, + expected_blake3_pis: &[F], + nbits: u32, + lut_cap: &MerkleCap, + ) -> Result<()> { + self.verify::(proof, expected_blake3_pis, lut_cap)?; + // The plain winning condition on the proven lottery digest (pinned equal to the expectation + // by the public-input check above), against the block's `nbits` — the succinct analogue of + // the plaintext certificate's difficulty epilogue. + let jackpot = hash_jackpot::(&proof.public_inputs[BLAKE3_A100_TABLE]); + check_jackpot_difficulty(&jackpot, nbits, self.h as u32, self.w as u32, self.k as u32) + } +} + +/// The canonical lottery layout for an `h x w` tile: a pair of [`AxisPattern`]s whose Blake digits +/// select exactly [`JACKPOT_ENTRIES`](crate::api::layout::JACKPOT_ENTRIES) `= 16` lanes, covering all +/// `h*w` cells. We split the 16 lanes as `br * bc` with `br | h` and `bc | w` (preferring the largest +/// `br`), putting the remaining factor of each axis into a leading Fold dim. `h*w` must admit such a +/// split (every geometry the extractor envelope allows does); a mismatched geometry panics. +pub fn default_lane_layout(h: usize, w: usize) -> (AxisPattern, AxisPattern) { + let axis = |fold: usize, blake: usize| -> AxisPattern { + let mut dims = Vec::new(); + if fold > 1 { + dims.push((fold as u32, DimType::Fold)); + } + if blake > 1 { + dims.push((blake as u32, DimType::Blake)); + } + if dims.is_empty() { + dims.push((1, DimType::Fold)); + } + AxisPattern::new(&dims).expect("valid canonical axis pattern") + }; + for br in (1..=16).rev() { + if 16 % br != 0 { + continue; + } + let bc = 16 / br; + if h % br == 0 && w % bc == 0 { + return (axis(h / br, br), axis(w / bc, bc)); + } + } + panic!("tile {h}x{w} admits no 16-lane Blake split (need br|h, bc|w, br*bc=16)"); +} + +/// Row-major trace rows -> the column-major `PolynomialValues` layout of the batch prover. +fn column_major(rows: &[[F; N]]) -> Vec> { + (0..N) + .map(|c| PolynomialValues::new(rows.iter().map(|r| r[c]).collect())) + .collect() +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + + use super::*; + use crate::api::fp16::accumulate::{GROUP as ACC_GROUP, a100_dot}; + use crate::api::fp16::policy::replay_and_evaluate; + use crate::api::fp8::transcript::{compute_jackpot_ticket, jackpot_key}; + use crate::api::fp8::utils::xor_fold_extract; + use crate::api::layout::lane_assignment; + use crate::api::fp16::commitment::commit_operand; + use crate::api::proof_utils::check_jackpot_difficulty; + use crate::circuit::fp8::blake3_stark::columns::{PI_HASH_A, PI_HASH_B, PI_HASH_JACKPOT}; + use super::super::ctl::{ + BLAKE3_A100_TABLE, MATMUL_A100_TABLE, NOISE_MATMUL_A_A100_TABLE, NOISE_MATMUL_B_A100_TABLE, + NOISY_QUANT_A100_TABLE, NOISY_QUANT_FMA_A100_TABLE, ROW_SCALE_A100_TABLE, XOR_FOLD_A100_TABLE, + }; + use super::super::matmul_a100_stark::columns::MATMUL_A100_COL_MAP; + use super::super::noisy_quant_fma_stark::columns::FMA_COL_MAP; + use super::super::noisy_quant_stark::columns::NOISY_QUANT_COL_MAP; + use super::super::row_scale_stark::columns::ROW_SCALE_COL_MAP; + use super::super::xor_fold_stark::columns::XOR_FOLD_COL_MAP; + use crate::api::fp16::quantization::{noisy_quantize, row_norms}; + + type F = GoldilocksField; + type C = PoseidonGoldilocksConfig; + const D: usize = 2; + + const VECTORS: &str = include_str!("../../api/fp16/testdata/a100_dot_vectors.txt"); + const SEED_A: Hash256 = [0x3c; 32]; + /// The operand-tree opening keys and leaf size for these tests. (In production these come from + /// the seed chain / header; passing them in is this increment's documented scope — see the + /// driver module docs.) `Blake3Chunk512` keeps the `4x4`/`4x16` Blake3 tables on the consensus + /// ladder (`2^8`). + const KEY_A: Hash256 = [0x11; 32]; + const KEY_B: Hash256 = [0x22; 32]; + const OP_HASH_ID: HashId = HashId::Blake3Chunk512; + + /// The 8 LE `u32` field words of `commit_operand(rows, num_rows, k, OP_HASH_ID, key).root()`. + fn operand_root_words(rows: &[u16], num_rows: usize, k: usize, key: Hash256) -> Vec { + let root = commit_operand(rows, num_rows, k, OP_HASH_ID, key).unwrap().root(); + (0..8) + .map(|i| F::from_canonical_u32(u32::from_le_bytes(root[4 * i..4 * i + 4].try_into().unwrap()))) + .collect() + } + + /// The smallest `1 x 1 x k` cell (`k >= 16`, `32 | GROUP | k`) from the GPU reference vectors + /// whose NOISED `4 x 4` tile (`a0`/`b0` on every A/B row, each noised under the fixed witness + /// noise) clears the policy gate — the operands the batch's matmul actually multiplies. (Noising + /// adds breakpoints, so a noised tile typically clears the gate more readily than its clean twin.) + fn accepting_cell() -> (usize, Vec, Vec) { + let mut best: Option<(usize, Vec, Vec)> = None; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % ACC_GROUP != 0 || k < 16 { + continue; + } + if best.as_ref().is_some_and(|(bk, _, _)| k >= *bk) { + continue; + } + let a0: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b0: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let (a, b) = (a0.repeat(4), b0.repeat(4)); + let Ok((noised_a, noised_b)) = fp16_noised_operands(4, 4, k, &a, &b, KEY_A, KEY_B, OP_HASH_ID, OP_HASH_ID) else { continue }; + if replay_and_evaluate(&noised_a, &noised_b, 4, 4, k).1.accept { + best = Some((k, a0, b0)); + } + } + best.expect("reference vectors must contain a cell whose noised 4x4 tile accepts") + } + + /// The 8 LE `u32` field words of the plaintext jackpot digest for the `h x w` tile whose cell + /// `(r, c)` is the A100 dot of the NOISED operand rows `(noised_a[r], noised_b[c])` — the same + /// noised operands the batch's matmul multiplies (the matmul is over the quant chain's `out`). + fn plaintext_jackpot_words(noised_a: &[u16], noised_b: &[u16], h: usize, w: usize, k: usize) -> Vec { + let mut tile = vec![0f32; h * w]; + for r in 0..h { + for c in 0..w { + tile[r * w + c] = a100_dot(&noised_a[r * k..r * k + k], &noised_b[c * k..c * k + k], 0.0, None); + } + } + let (row_axis, col_axis) = default_lane_layout(h, w); + let msg = xor_fold_extract(&tile, &lane_assignment(&row_axis, &col_axis)); + let jk = compute_jackpot_ticket(&SEED_A, &msg).jackpot; + (0..8) + .map(|i| F::from_canonical_u32(u32::from_le_bytes(jk[4 * i..4 * i + 4].try_into().unwrap()))) + .collect() + } + + /// The driver's output -> jackpot chain end to end: an honest tile proves and verifies, its + /// committed `HASH_JACKPOT` equals the plaintext jackpot, and a tampered cell result and a + /// tampered lottery word are rejected by the batch verifier. + #[test] + fn batch_binds_output_tile_to_hash_jackpot_and_rejects_tampering() { + let (k, a0, b0) = accepting_cell(); + // A 4x4 tile: 16 output cells, one per lottery lane. + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- Honest proof: proves and verifies. ---- + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system + .verify::(&proof, &blake3_pis, &lut_cap) + .expect("honest FP16 proof must verify"); + + // ---- HASH_JACKPOT is bit-exact with the plaintext extractor -> jackpot transcript over the + // NOISED operands the matmul multiplies (the quant chain's `out`). ---- + let (noised_a, noised_b) = system.noised_operands(&a, &b, KEY_A, KEY_B); + assert_eq!( + &blake3_pis[PI_HASH_JACKPOT..PI_HASH_JACKPOT + 8], + plaintext_jackpot_words(&noised_a, &noised_b, h, w, k).as_slice(), + "committed HASH_JACKPOT must equal the plaintext jackpot over the noised operands" + ); + + // ---- HASH_A / HASH_B are bit-exact with the committed operand Merkle roots the plaintext + // certificate opens against (`commit_operand(..).root()`). A is `h x k`, B is `w x k`. ---- + assert_eq!( + &blake3_pis[PI_HASH_A..PI_HASH_A + 8], + operand_root_words(&a, h, k, KEY_A).as_slice(), + "committed HASH_A must equal commit_operand(A).root()" + ); + assert_eq!( + &blake3_pis[PI_HASH_B..PI_HASH_B + 8], + operand_root_words(&b, w, k, KEY_B).as_slice(), + "committed HASH_B must equal commit_operand(B).root()" + ); + + // ---- Tampering: mutate one honest trace cell and assert the batch verifier rejects. ---- + let xf = &XOR_FOLD_COL_MAP; + let (honest, _) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + // Every live XorFold row here is lane-final (16 lanes of one cell); pick the first. + let xf_live = (0..honest[XOR_FOLD_A100_TABLE][xf.is_pad].values.len()) + .find(|&r| honest[XOR_FOLD_A100_TABLE][xf.is_pad].values[r] == F::ZERO) + .expect("a live XorFold row"); + + let prove_tampered = |col: usize, row: usize| { + let (mut traces, blake3_pis) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + traces[XOR_FOLD_A100_TABLE][col].values[row] += F::ONE; + let mut timing = TimingTree::default(); + match system.prove_batch_traces::(traces, &blake3_pis, &preprocessed, &mut timing) { + Ok(bad) => system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + Err(_) => true, + } + }; + + // (a) a tampered cell result: the folded cell word no longer matches the matmul's proven + // output, unbalancing the matmul -> XorFold cell-results channel. + assert!( + prove_tampered(xf.cell_result_f32_lo, xf_live), + "a tampered cell result must be rejected by the cell-results CTL" + ); + // (b) a tampered lottery word: the lane's folded output word changes, unbalancing the + // XorFold -> Blake3 lottery-words channel (and breaking the mixer's rotation split). + assert!( + prove_tampered(xf.rotation_input_top13, xf_live), + "a tampered lottery word must be rejected by the lottery-words CTL" + ); + } + + /// The quantization chain (increment 6b) proves `noised = Q(alpha*raw + beta*N)` end-to-end + /// in-batch: an honest tile's batch proof verifies, the proven noisy-quant `out` column is + /// bit-exact with the plaintext `noisy_quantize` kernel over the same (fixed, in-envelope) witness + /// operand, and tampering any of the three quant tables (row-scale scales, the G1/G3 noisy-quant, + /// or the G2 FMA) is rejected by the batch verifier — via the quant AIR constraints, the shared + /// LUTs, or the two internal quant-chain CTLs (scales import, FMA pairing). + #[test] + fn batch_proves_quant_chain_and_rejects_tampering() { + let (k, a0, b0) = accepting_cell(); + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- Honest proof: proves and verifies with the three quant tables wired in. ---- + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile with quant chain must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system.verify::(&proof, &blake3_pis, &lut_cap).expect("honest quant-chain proof must verify"); + + // ---- The proven noisy-quant `out` column is bit-exact with `noisy_quantize` over the FULL + // A operand AND the FULL B operand (every operand row of both), over the REAL ROOT-DERIVED + // noise with DISTINCT F_A/F_B (N_A = E_A@F_A^T, N_B = E_B@F_B^T), per side. ---- + let mut expected_out: Vec = Vec::new(); + let seeds = fp16_root_derived_seeds(h, w, k, OP_HASH_ID, OP_HASH_ID, KEY_A, KEY_B, &a, &b).unwrap(); + let (e_a, f_a, e_b, f_b) = fp16_tile_noise(seeds, h, w, k); + for (codes, num_rows, e, f) in [(&a, h, &e_a, &f_a), (&b, w, &e_b, &f_b)] { + let norms: Vec<(u16, u16)> = + (0..num_rows).map(|i| row_norms(&codes[i * k..(i + 1) * k]).unwrap()).collect(); + let built = noisy_quantize(codes, e, f, &norms, FP16_QUANT_R).unwrap(); + expected_out.extend_from_slice(&built.noised_part); + } + let (honest, _) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + for (j, &want) in expected_out.iter().enumerate() { + let got = honest[NOISY_QUANT_A100_TABLE][NOISY_QUANT_COL_MAP.out].values[j].to_canonical_u64() as u16; + assert_eq!(got, want, "proven noised out column mismatch at element {j}"); + } + assert_eq!(expected_out.len(), (h + w) * k, "quant chain covers every operand row of both operands"); + + // ---- Tampering any quant table is rejected by batch_verify. ---- + let prove_tampered = |table: usize, col: usize, row: usize| { + let (mut traces, blake3_pis) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + traces[table][col].values[row] += F::ONE; + let mut timing = TimingTree::default(); + match system.prove_batch_traces::(traces, &blake3_pis, &preprocessed, &mut timing) { + Ok(bad) => system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + Err(_) => true, + } + }; + + // (a) row-scale: a tampered derived scale breaks the row-scale AIR / the scales-import CTL. + assert!( + prove_tampered(ROW_SCALE_A100_TABLE, ROW_SCALE_COL_MAP.alpha_code, 0), + "a tampered row-scale alpha must be rejected" + ); + // (b) noisy-quant: a tampered FP16 output breaks the G3 cast encode. + assert!( + prove_tampered(NOISY_QUANT_A100_TABLE, NOISY_QUANT_COL_MAP.out, 0), + "a tampered noisy-quant output must be rejected" + ); + // (c) G2 FMA: a tampered `noised` breaks the FMA AIR / the FMA-pairing CTL. + assert!( + prove_tampered(NOISY_QUANT_FMA_A100_TABLE, FMA_COL_MAP.noised_lo, 0), + "a tampered G2 FMA noised must be rejected" + ); + } + + /// Increments 6c + 6d — the operand-provenance capstone (audit Finding 3). The matmul provably + /// multiplies the NOISED quantization of the COMMITTED operands, end to end: + /// * (a) the honest tile proves+verifies with the matmul over `noisy_quantize(committed a/b)` — + /// the `batch_proves_quant_chain` + `batch_binds_output_tile` tests already pin the `out` column + /// and the noised jackpot; here we pin HASH_A/HASH_B to the committed operands and fail-close the + /// two binding channels; + /// * (d) HASH_A / HASH_B are bit-exact with `commit_operand` of the committed (clean) operands the + /// noised codes derive from; + /// * (b) tampering a matmul operand code away from the noised committed value is rejected (the + /// noised->matmul operand-codes channel, 6d); + /// * (c) tampering a committed operand byte (Blake3) is rejected (the operand-bytes channel, 6c). + #[test] + fn batch_binds_matmul_operands_to_committed_and_rejects_tampering() { + use crate::circuit::fp8::blake3_stark::columns::{BLAKE3_COL_MAP, PI_HASH_A, PI_HASH_B}; + let (k, a0, b0) = accepting_cell(); + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- (a) honest proof over the noised committed operands verifies. ---- + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system.verify::(&proof, &blake3_pis, &lut_cap).expect("honest proof must verify"); + + // ---- (d) HASH_A / HASH_B commit the clean operands the noised codes derive from. ---- + assert_eq!( + &blake3_pis[PI_HASH_A..PI_HASH_A + 8], + operand_root_words(&a, h, k, KEY_A).as_slice(), + "HASH_A must equal commit_operand of the committed A operand" + ); + assert_eq!( + &blake3_pis[PI_HASH_B..PI_HASH_B + 8], + operand_root_words(&b, w, k, KEY_B).as_slice(), + "HASH_B must equal commit_operand of the committed B operand" + ); + + let prove_tampered = |table: usize, col: usize, row: usize| { + let (mut traces, blake3_pis) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + traces[table][col].values[row] += F::ONE; + let mut timing = TimingTree::default(); + match system.prove_batch_traces::(traces, &blake3_pis, &preprocessed, &mut timing) { + Ok(bad) => system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + Err(_) => true, + } + }; + + let m = &MATMUL_A100_COL_MAP; + let bm = &BLAKE3_COL_MAP; + let (honest, _) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + let mat_live = (0..honest[MATMUL_A100_TABLE][m.is_padding].values.len()) + .find(|&r| honest[MATMUL_A100_TABLE][m.is_padding].values[r] == F::ZERO) + .expect("a live matmul row"); + let b3_live = (0..honest[BLAKE3_A100_TABLE][bm.is_int8_message].values.len()) + .find(|&r| honest[BLAKE3_A100_TABLE][bm.is_int8_message].values[r] == F::ONE) + .expect("a live operand-values row"); + + // ---- (b) a matmul operand code tampered away from the noised committed value is rejected + // (the operand-codes channel binds it to the noisy-quant `out`). ---- + assert!( + prove_tampered(MATMUL_A100_TABLE, m.operand_codes_a[0], mat_live), + "a tampered matmul operand code must be rejected by the operand-codes (6d) channel" + ); + // ---- (c) a committed operand byte (Blake3) tampered is rejected (the operand-bytes channel + // binds the committed byte to the quant `raw`). ---- + assert!( + prove_tampered(BLAKE3_A100_TABLE, bm.uint8_data[0], b3_live), + "a tampered committed operand byte must be rejected by the operand-bytes (6c) channel" + ); + } + + /// The batch's committed operand roots (HASH_A / HASH_B) are bit-exact with + /// `commit_operand(..).root()` across several tile shapes and every allowed leaf size — and the + /// A and B sides are keyed independently (A under KEY_A / `a_hash_id`, B under KEY_B / + /// `b_hash_id`). Exercises the whole generate_batch_traces -> Blake3 operand-tree path, including + /// a mixed-`HashId` A/B job to prove the two trees do not cross-contaminate. + #[test] + fn batch_binds_operand_roots_to_hash_a_and_hash_b() { + let (k, a0, b0) = accepting_cell(); + let jk = jackpot_key(&SEED_A); + // (h, w, a_hash_id, b_hash_id): every leaf size, two shapes, plus a mixed-id job. + let cases = [ + (4usize, 4usize, HashId::Blake3Chunk128, HashId::Blake3Chunk128), + (2, 8, HashId::Blake3Chunk256, HashId::Blake3Chunk256), + (4, 4, HashId::Blake3Chunk512, HashId::Blake3Chunk1024), + (8, 2, HashId::Blake3Chunk1024, HashId::Blake3Chunk512), + ]; + for (h, w, a_hash_id, b_hash_id) in cases { + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let system = Fp16System::::new(h, w, k, a_hash_id, b_hash_id); + let (_, blake3_pis) = system + .generate_batch_traces(&a, &b, KEY_A, KEY_B, jk) + .expect("honest traces"); + + let root_a = commit_operand(&a, h, k, a_hash_id, KEY_A).unwrap().root(); + let root_b = commit_operand(&b, w, k, b_hash_id, KEY_B).unwrap().root(); + let words = |root: Hash256| -> Vec { + (0..8) + .map(|i| F::from_canonical_u32(u32::from_le_bytes(root[4 * i..4 * i + 4].try_into().unwrap()))) + .collect() + }; + assert_eq!( + &blake3_pis[PI_HASH_A..PI_HASH_A + 8], + words(root_a).as_slice(), + "HASH_A mismatch for {h}x{w} a_id={a_hash_id:?}" + ); + assert_eq!( + &blake3_pis[PI_HASH_B..PI_HASH_B + 8], + words(root_b).as_slice(), + "HASH_B mismatch for {h}x{w} b_id={b_hash_id:?}" + ); + } + } + + /// Increment 6e-2 — the per-side noise matmuls with DISTINCT `F_A`/`F_B`. The `beta*N` noise the + /// noisy-quant G1 rounding consumes is proven in-batch by two `MatmulStarkA100` instances — + /// `N_A = E_A @ F_A^T` (`h x k`) and `N_B = E_B @ F_B^T` (`w x k`) — matching the plaintext + /// `sample_noise`'s distinct-`F` layout (6e-1 used one shared `F`, which diverged). The noise-word + /// CTL binds their cell results to noisy-quant's `(NOISE_LO, NOISE_HI)` (A cells -> `[0,h*k)`, B + /// cells -> `[h*k,(h+w)*k)`), and the E/F-operand CTL binds their `E`/`F` operands to NoiseStark's + /// proven normalized lines. This test shows: + /// * (a) the honest tile proves+verifies with the two noise matmuls + NoiseStark wired in; + /// * (b) the matmuls' cell results are bit-exact with `a100_matmul(e, f)` per side (distinct `F`) AND + /// equal the noise noisy-quant consumed (so the noised `out` is still bit-exact); + /// * (c) tampering a noise matmul's `N` output at a finished cell is rejected (noise-word channel); + /// * (d) tampering noisy-quant's `N` input (`NOISE_LO`) is rejected (same channel, consuming side). + /// + /// E/F are now bound to NoiseStark's proven normalized lines (the E/F-operand channel; a tampered + /// line is rejected in `ctl::tests::forged_noise_line_breaks_the_ef_channel`). + /// CAVEAT: the raw XOF bytes NoiseStark normalizes remain free witness (seed-keyed-BLAKE3-XOF + /// binding is increment 6e-3), so the noise is still grindable through those bytes; but `E`/`F` are + /// now provably the normalized seed-derived lines with distinct `F_A`/`F_B` matching the plaintext. + #[test] + fn batch_binds_noise_to_ef_matmul_and_rejects_tampering() { + let (k, a0, b0) = accepting_cell(); + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- (a) honest proof verifies. ---- + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile with noise matmul must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system.verify::(&proof, &blake3_pis, &lut_cap).expect("honest noise-matmul proof must verify"); + + // ---- (b) the proven noise is bit-exact with `a100_matmul` per side with DISTINCT F_A/F_B + // (N_A = E_A@F_A^T, N_B = E_B@F_B^T) AND equals the noise noisy-quant consumed (A rows then B + // rows, element index i*k + j). ---- + let r = FP16_QUANT_R; + let seeds = fp16_root_derived_seeds(h, w, k, OP_HASH_ID, OP_HASH_ID, KEY_A, KEY_B, &a, &b).unwrap(); + let (e_a, f_a, e_b, f_b) = fp16_tile_noise(seeds, h, w, k); + let mut expected_noise = a100_matmul(&e_a, &f_a, None, h, k, r); + expected_noise.extend(a100_matmul(&e_b, &f_b, None, w, k, r)); + assert_eq!(expected_noise.len(), (h + w) * k); + // Distinct F is the correctness fix: F_A != F_B per the plaintext `sample_noise`. + assert_ne!(f_a, f_b, "F_A and F_B must be distinct (Side::A vs Side::B)"); + + let m2 = &MATMUL_A100_COL_MAP; + let nq = &NOISY_QUANT_COL_MAP; + let (honest, _) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + + // The two noise matmuls' proven cell results (A cells -> [0,h*k), B cells -> [h*k,(h+w)*k)). + let mut matmul_noise = vec![f32::NAN; (h + w) * k]; + for (table, base) in [(NOISE_MATMUL_A_A100_TABLE, 0usize), (NOISE_MATMUL_B_A100_TABLE, h * k)] { + let noise_tbl = &honest[table]; + for row in 0..noise_tbl[m2.is_cell_final].values.len() { + if noise_tbl[m2.is_cell_final].values[row] == F::ONE && noise_tbl[m2.is_padding].values[row] == F::ZERO { + let cell = noise_tbl[m2.cell_id].values[row].to_canonical_u64() as usize; + let lo = noise_tbl[m2.cell_result_f32_lo].values[row].to_canonical_u64(); + let hi = noise_tbl[m2.cell_result_f32_hi].values[row].to_canonical_u64(); + matmul_noise[base + cell] = f32::from_bits(((hi << 16) | lo) as u32); + } + } + } + for (e, &want) in expected_noise.iter().enumerate() { + assert_eq!( + matmul_noise[e].to_bits(), + want.to_bits(), + "noise matmul cell {e} must be bit-exact with a100_matmul(e, f)" + ); + } + + // The noise noisy-quant consumed (NOISE_LO/HI per live element) must equal the SAME product. + for row in 0..honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values.len() { + if honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values[row] == F::ZERO { + let e = honest[NOISY_QUANT_A100_TABLE][nq.element_index].values[row].to_canonical_u64() as usize; + let lo = honest[NOISY_QUANT_A100_TABLE][nq.noise_lo].values[row].to_canonical_u64(); + let hi = honest[NOISY_QUANT_A100_TABLE][nq.noise_hi].values[row].to_canonical_u64(); + let consumed = f32::from_bits(((hi << 16) | lo) as u32); + assert_eq!( + consumed.to_bits(), + expected_noise[e].to_bits(), + "noisy-quant consumed noise at element {e} must equal the E@F product" + ); + } + } + + let prove_tampered = |table: usize, col: usize, row: usize| { + let (mut traces, blake3_pis) = system.generate_batch_traces(&a, &b, KEY_A, KEY_B, jk).expect("honest traces"); + traces[table][col].values[row] += F::ONE; + let mut timing = TimingTree::default(); + match system.prove_batch_traces::(traces, &blake3_pis, &preprocessed, &mut timing) { + Ok(bad) => system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + Err(_) => true, + } + }; + + // ---- (c) tamper the noise matmul's N output at a finished live cell -> rejected. The + // noise-word CTL binds this `cell_result` to noisy-quant's consumed noise; `cell_result` also + // feeds the matmul's own MA9 encode, so a lone tamper is caught end to end (the CTL-attributed + // isolation is in `ctl::tests::forged_noise_word_breaks_the_noise_channel`). ---- + let noise_tbl_a = &honest[NOISE_MATMUL_A_A100_TABLE]; + let noise_final = (0..noise_tbl_a[m2.is_cell_final].values.len()) + .find(|&row| { + noise_tbl_a[m2.is_cell_final].values[row] == F::ONE + && noise_tbl_a[m2.is_padding].values[row] == F::ZERO + }) + .expect("a finished live noise-matmul cell"); + assert!( + prove_tampered(NOISE_MATMUL_A_A100_TABLE, m2.cell_result_f32_lo, noise_final), + "a tampered noise-matmul N output must be rejected (noise-word channel + MA9)" + ); + + // ---- (d) tamper noisy-quant's N input (NOISE_LO) at a live element -> rejected (the + // noise-word CTL unbinds it from the proven product; `NOISE_LO` also feeds the G1 rounding). ---- + let nq_live = (0..honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values.len()) + .find(|&row| honest[NOISY_QUANT_A100_TABLE][nq.is_pad].values[row] == F::ZERO) + .expect("a live noisy-quant element"); + assert!( + prove_tampered(NOISY_QUANT_A100_TABLE, nq.noise_lo, nq_live), + "a tampered noisy-quant N input must be rejected (noise-word 6e-1 channel + G1)" + ); + } + + /// Increment 6e-3d — the noise is now DERIVED FROM THE COMMITTED OPERAND ROOTS, closing the last + /// anti-grind gap. This test shows: + /// * (a) the root-derived seeds match `api::fp16::noise::noise_seeds` over `commit_operand(..).root()` + /// + the opening keys + the `p` encodings, and the honest tile's noise (E/F, N, noised, tile, + /// jackpot) is bit-exact with the plaintext `sample_noise` over those seeds (the honest proof + /// verifies and the other capstone tests pin N / noised-out / jackpot over the same seeds); + /// * (b) operand-dependence: changing an operand (hence its root) changes the derived seeds and the + /// whole noise draw — the noise is no longer a fixed public value; + /// * (c) `verify` pins the noise-BLAKE3 `KEY_A`/`KEY_B` public inputs to `noise_seeds` recomputed + /// from the proof's `HASH_A`/`HASH_B` + keys + `p`, so a seed not derived from the committed roots + /// is rejected. + #[test] + fn noise_seeds_are_root_derived_operand_dependent_and_pinned() { + use crate::api::fp16::noise::noise_seeds as api_noise_seeds; + use crate::circuit::fp16::blake3_fp16_stark::columns::PI_KEY_A as NB_PI_KEY_A; + use super::super::ctl::NOISE_BLAKE3_A100_TABLE; + + let (k, a0, b0) = accepting_cell(); + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // ---- (a) the driver's root-derived seeds equal `api::fp16::noise::noise_seeds` over the real + // committed roots + keys + p — i.e. the EXACT plaintext seed chain. ---- + let seeds = system.root_derived_seeds(&a, &b, KEY_A, KEY_B).expect("root-derived seeds"); + let root_a = commit_operand(&a, h, k, OP_HASH_ID, KEY_A).unwrap().root(); + let root_b = commit_operand(&b, w, k, OP_HASH_ID, KEY_B).unwrap().root(); + let p = fp16_noise_seed_params(h, w, k, OP_HASH_ID, OP_HASH_ID); + let want = api_noise_seeds(&Sides { a: KEY_A, b: KEY_B }, &Sides { a: root_a, b: root_b }, &p); + assert_eq!(seeds, want, "driver seeds must equal api::fp16::noise::noise_seeds over the committed roots"); + + // The honest proof verifies with the root-derived noise wired through every noise table. + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile with root-derived noise must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + system.verify::(&proof, &blake3_pis, &lut_cap).expect("honest root-derived-noise proof must verify"); + + // ---- (b) operand-dependence: a different operand -> different root -> different seeds -> + // different noise draw. Changing A moves seedA (which folds root_A); changing B moves seedB. ---- + let mut a2 = a.clone(); + a2[0] ^= 0x4000; // perturb one A code (a high mantissa bit; stays a valid FP16 pattern) + let mut b2 = b.clone(); + b2[0] ^= 0x4000; + let seeds_a2 = system.root_derived_seeds(&a2, &b, KEY_A, KEY_B).expect("seeds for perturbed A"); + let seeds_b2 = system.root_derived_seeds(&a, &b2, KEY_A, KEY_B).expect("seeds for perturbed B"); + assert_ne!(seeds.a, seeds_a2.a, "perturbing A must move seedA (operand-dependence)"); + assert_ne!(seeds.b, seeds_b2.b, "perturbing B must move seedB (operand-dependence)"); + // The full noise draw changes with the seeds. + assert_ne!( + fp16_tile_noise(seeds, h, w, k), + fp16_tile_noise(seeds_a2, h, w, k), + "a changed operand must change the noise draw" + ); + + // ---- (c) `verify` pins the noise-BLAKE3 KEY_A to `noise_seeds` of the committed roots: a + // noise seed not derived from the roots (here a tampered KEY_A limb) is rejected. ---- + let mut bad = proof.clone(); + bad.public_inputs[NOISE_BLAKE3_A100_TABLE][NB_PI_KEY_A] += F::ONE; + assert!( + system.verify::(&bad, &blake3_pis, &lut_cap).is_err(), + "a noise seed (noise-BLAKE3 KEY_A) not derived from the committed roots must be rejected by verify's pinning" + ); + } + + /// Increment 6f — the consensus-meaningful OUTPUT gateway. An honest tile proves; the + /// Fiat-Shamir statement digest is DERIVED from the proof's own `HASH_JACKPOT` (not a + /// caller-opaque salt); [`Fp16System::verify_with_difficulty`] ACCEPTS at an easy target and + /// REJECTS at an impossible (all-zero) one — and its accept/reject decision equals the plaintext + /// [`check_jackpot_difficulty`] on the SAME tile for both targets. A tampered `HASH_JACKPOT` / + /// wrong expected public input is rejected by the gateway's public-input pinning. + #[test] + fn verify_with_difficulty_matches_plaintext_and_derives_statement_digest() { + let (k, a0, b0) = accepting_cell(); + let (h, w) = (4usize, 4usize); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + let jk = jackpot_key(&SEED_A); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + let proof = system + .prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing) + .expect("honest FP16 tile must prove"); + let blake3_pis = proof.public_inputs[BLAKE3_A100_TABLE].clone(); + + // ---- The statement digest is DERIVED from the proof's own jackpot limbs. ---- + let expected_digest = derive_statement_digest(hash_jackpot::(&blake3_pis)); + assert_eq!(expected_digest, Fp16System::::statement_digest(&blake3_pis)); + system + .ensure_statement_digest_binding(expected_digest) + .expect("prove must bind the jackpot-derived statement digest"); + assert!( + system.ensure_statement_digest_binding([0xAB; 32]).is_err(), + "a statement digest other than the jackpot-derived one must be rejected" + ); + + // ---- Difficulty: the ZK gateway decision equals the plaintext one on the SAME (noised) tile. ---- + let (noised_a, noised_b) = system.noised_operands(&a, &b, KEY_A, KEY_B); + let mut tile = vec![0f32; h * w]; + for r in 0..h { + for c in 0..w { + tile[r * w + c] = a100_dot(&noised_a[r * k..r * k + k], &noised_b[c * k..c * k + k], 0.0, None); + } + } + let (row_axis, col_axis) = default_lane_layout(h, w); + let msg = xor_fold_extract(&tile, &lane_assignment(&row_axis, &col_axis)); + let plain_jackpot = compute_jackpot_ticket(&SEED_A, &msg).jackpot; + + // Easy target saturates the bound (accepts); the all-zero target is impossible (rejects) — + // the same two targets the plaintext `verify_tile_proof` test uses. + const EASY_NBITS: u32 = 0x207fffff; + const IMPOSSIBLE_NBITS: u32 = 0; + for nbits in [EASY_NBITS, IMPOSSIBLE_NBITS] { + let zk = system.verify_with_difficulty::(&proof, &blake3_pis, nbits, &lut_cap).is_ok(); + let plain = check_jackpot_difficulty(&plain_jackpot, nbits, h as u32, w as u32, k as u32).is_ok(); + assert_eq!(zk, plain, "ZK difficulty decision must equal the plaintext one at nbits={nbits:#x}"); + } + system + .verify_with_difficulty::(&proof, &blake3_pis, EASY_NBITS, &lut_cap) + .expect("easy target must accept"); + assert!( + system.verify_with_difficulty::(&proof, &blake3_pis, IMPOSSIBLE_NBITS, &lut_cap).is_err(), + "the impossible (all-zero) target must reject" + ); + + // ---- A tampered HASH_JACKPOT / wrong expected public input is rejected by the pinning. ---- + let mut bad_jackpot = blake3_pis.clone(); + bad_jackpot[PI_HASH_JACKPOT] += F::ONE; + assert!( + system.verify_with_difficulty::(&proof, &bad_jackpot, EASY_NBITS, &lut_cap).is_err(), + "a tampered expected HASH_JACKPOT must be rejected" + ); + let mut bad_key = blake3_pis.clone(); + bad_key[0] += F::ONE; // a KEY_A limb + assert!( + system.verify_with_difficulty::(&proof, &bad_key, EASY_NBITS, &lut_cap).is_err(), + "a wrong expected key public input must be rejected" + ); + } + + /// The header-pinned verify GATEWAY ([`Fp16System::verify_with_headers`]): nothing feeding the + /// noise seeds or the operand-tree commitment keys is test-supplied — it is all derived from the + /// block headers + the public job params, exactly as the plaintext certificate derives it. This + /// shows: + /// * (bit-exact) the gateway's `keyA`/`keyB` equal `api::fp16::noise::commitment_keys` and its noise + /// seeds equal `api::fp16::noise::noise_seeds` over the committed operand roots + header keys + `p`; + /// * (accept) an honest tile proved under those header-derived keys/`p` verifies through the gateway; + /// * (reject) a DIFFERENT proposed header (moves `keyA` -> `seedA`), a different ancestor header + /// (moves `keyB`/`p_b` -> `seedB`), and a different `p` alone (a changed pattern, `keys` fixed, moves + /// `seedA`) are each rejected by the header-derived public-input pinning; + /// * (difficulty) the gateway's accept/reject at an easy vs an impossible `nbits` matches the plaintext + /// `check_jackpot_difficulty` on the SAME noised tile. + #[test] + fn verify_with_headers_binds_to_the_header() { + use crate::api::fp16::noise::{commitment_keys as api_commitment_keys, key_a, key_b, noise_seeds as api_noise_seeds}; + use crate::api::fp16::params::Fp16Device; + use crate::api::fp16::plain_proof::{Fp16JobParams, Fp16OperandParams}; + use crate::api::layout::{AxisPattern, DimType}; + use crate::api::primitives::IncompleteBlockHeader; + + const EASY_NBITS: u32 = 0x207fffff; + const IMPOSSIBLE_NBITS: u32 = 0; + + // The headers that key the commitment + seed chain: the proposed header keys the A side, the + // ancestor header the B side (window-authenticated upstream, as the plaintext cert assumes). + let proposed = IncompleteBlockHeader::new_for_test(EASY_NBITS); + let ancestor = IncompleteBlockHeader::zero(); + let keys = api_commitment_keys(&proposed, &ancestor); + // Bit-exact with the plaintext cert's per-side opening keys. + assert_eq!(keys.a, key_a(&proposed), "gateway keyA must equal api key_a(proposed)"); + assert_eq!(keys.b, key_b(&ancestor), "gateway keyB must equal api key_b(ancestor)"); + + // A cell whose NOISED 4x4 tile clears the policy gate under THESE header-derived keys (+ the + // job's `p`, which for a zero-ancestor dense-tile job equals the system's default encoding, so + // the free `fp16_noised_operands` draws the same noise the proven system will). + let dense = |n: usize| AxisPattern::new(&[(n as u32, DimType::Blake)]).expect("dense tile pattern"); + let (h, w) = (4usize, 4usize); + let (k, a0, b0) = { + let mut best: Option<(usize, Vec, Vec)> = None; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let kk: usize = t[0].parse().unwrap(); + if kk % ACC_GROUP != 0 || kk < 16 { + continue; + } + if best.as_ref().is_some_and(|(bk, _, _)| kk >= *bk) { + continue; + } + let a0: Vec = t[1..1 + kk].iter().map(|x| x.parse().unwrap()).collect(); + let b0: Vec = t[1 + kk..1 + 2 * kk].iter().map(|x| x.parse().unwrap()).collect(); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let Ok((na, nb)) = fp16_noised_operands(h, w, kk, &a, &b, keys.a, keys.b, OP_HASH_ID, OP_HASH_ID) else { + continue; + }; + if replay_and_evaluate(&na, &nb, h, w, kk).1.accept { + best = Some((kk, a0, b0)); + } + } + best.expect("a reference cell whose header-noised 4x4 tile accepts") + }; + let (a, b) = (a0.repeat(h), b0.repeat(w)); + + // The public job params (the plaintext cert's `Fp16JobParams`), from which the gateway derives + // `p_a`/`p_b`. The honest prover folds the SAME `p` into its seed chain via `set_noise_seed_params`. + let job = Fp16JobParams { + ancestor_header: ancestor, + device: Fp16Device::A100, + k: k as u32, + r: FP16_QUANT_R as u32, + operands: Sides { + a: Fp16OperandParams { num_rows: h as u32, hash_id: OP_HASH_ID, pattern: dense(h) }, + b: Fp16OperandParams { num_rows: w as u32, hash_id: OP_HASH_ID, pattern: dense(w) }, + }, + }; + + let mut system = Fp16System::::new(h, w, k, OP_HASH_ID, OP_HASH_ID); + system.set_noise_seed_params(Sides { a: job.encode_p_a(), b: job.encode_p_b() }); + let mut timing = TimingTree::default(); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + // The gateway's noise seeds are bit-exact with api::fp16::noise::noise_seeds over the committed + // operand roots (HASH_A/HASH_B) + header keys + the job's `p`. + let root_a = commit_operand(&a, h, k, OP_HASH_ID, keys.a).unwrap().root(); + let root_b = commit_operand(&b, w, k, OP_HASH_ID, keys.b).unwrap().root(); + let p = Sides { a: job.encode_p_a(), b: job.encode_p_b() }; + let want_seeds = api_noise_seeds(&keys, &Sides { a: root_a, b: root_b }, &p); + assert_eq!( + system.root_derived_seeds(&a, &b, keys.a, keys.b).unwrap(), + want_seeds, + "the header-derived seeds must equal api::fp16::noise::noise_seeds" + ); + + // The honest jackpot (lottery-compression) key is jackpot_key(seed_a) over the HEADER-DERIVED + // seed_a (want_seeds.a) -- exactly what the gateway now pins PI_JACKPOT_KEY to. (A test that + // keyed it on an unrelated seed would be rejected by that pin, as it should be.) + let jk = jackpot_key(&want_seeds.a); + + // ---- (accept) the honest tile, proved under the header-derived keys/p, verifies. ---- + let proof = system + .prove::(&a, &b, keys.a, keys.b, jk, &preprocessed, &mut timing) + .expect("honest header-keyed FP16 tile must prove"); + system + .verify_with_headers::(&proof, &proposed, &job, EASY_NBITS, &lut_cap) + .expect("the honest proof must verify through the header gateway"); + + // ---- (bind + reject) the jackpot (lottery-compression) key is pinned to the header/root- + // derived jackpot_key(seed_a); a proof carrying any other jackpot key is rejected (closes the + // pow-key grind: a prover cannot pick the key that hashes the lottery words to HASH_JACKPOT). ---- + { + use crate::circuit::fp8::blake3_stark::columns::PI_JACKPOT_KEY; + let hw = |h: Hash256| -> [F; 8] { + core::array::from_fn(|i| F::from_canonical_u32(u32::from_le_bytes(h[4 * i..4 * i + 4].try_into().unwrap()))) + }; + assert_eq!( + proof.public_inputs[BLAKE3_A100_TABLE][PI_JACKPOT_KEY..PI_JACKPOT_KEY + 8], + hw(jackpot_key(&want_seeds.a)), + "the honest proof's jackpot key must be jackpot_key(header-derived seed_a)" + ); + let mut forged = proof.clone(); + forged.public_inputs[BLAKE3_A100_TABLE][PI_JACKPOT_KEY] += F::ONE; + assert!( + system.verify_with_headers::(&forged, &proposed, &job, EASY_NBITS, &lut_cap).is_err(), + "a proof whose jackpot key is not jackpot_key(seed_a) must be rejected by the gateway pin" + ); + } + + // ---- (reject) a different proposed header moves keyA -> seedA; the proof's header-derived + // KEY_A / noise-BLAKE3 seed pins no longer match. ---- + let wrong_proposed = IncompleteBlockHeader { timestamp: proposed.timestamp ^ 0x5A5A, ..proposed }; + assert!( + system.verify_with_headers::(&proof, &wrong_proposed, &job, EASY_NBITS, &lut_cap).is_err(), + "a different proposed header must be rejected (keyA/seedA no longer header-derived)" + ); + + // ---- (reject) a different ancestor header moves keyB/p_b -> seedB. ---- + let mut wrong_ancestor_job = job.clone(); + wrong_ancestor_job.ancestor_header = + IncompleteBlockHeader { prev_block: [0x77; 32], ..ancestor }; + assert!( + system.verify_with_headers::(&proof, &proposed, &wrong_ancestor_job, EASY_NBITS, &lut_cap).is_err(), + "a different ancestor header must be rejected (keyB/p_b/seedB no longer header-derived)" + ); + + // ---- (reject) a different `p` alone (a changed A pattern, keys unchanged) moves seedA. ---- + let mut wrong_p_job = job.clone(); + wrong_p_job.operands.a.pattern = AxisPattern::new(&[(h as u32, DimType::Fold)]).unwrap(); + assert!( + system.verify_with_headers::(&proof, &proposed, &wrong_p_job, EASY_NBITS, &lut_cap).is_err(), + "a different p (changed pattern) must be rejected (seedA no longer header-derived)" + ); + + // ---- (difficulty) the gateway decision equals the plaintext one on the SAME noised tile. ---- + let (noised_a, noised_b) = system.noised_operands(&a, &b, keys.a, keys.b); + let mut tile = vec![0f32; h * w]; + for r in 0..h { + for c in 0..w { + tile[r * w + c] = a100_dot(&noised_a[r * k..r * k + k], &noised_b[c * k..c * k + k], 0.0, None); + } + } + let (row_axis, col_axis) = default_lane_layout(h, w); + let msg = xor_fold_extract(&tile, &lane_assignment(&row_axis, &col_axis)); + let plain_jackpot = compute_jackpot_ticket(&want_seeds.a, &msg).jackpot; + for nbits in [EASY_NBITS, IMPOSSIBLE_NBITS] { + let zk = system.verify_with_headers::(&proof, &proposed, &job, nbits, &lut_cap).is_ok(); + let plain = check_jackpot_difficulty(&plain_jackpot, nbits, h as u32, w as u32, k as u32).is_ok(); + assert_eq!(zk, plain, "gateway difficulty decision must equal the plaintext one at nbits={nbits:#x}"); + } + } +} diff --git a/zk-pow/src/circuit/fp16/matmul_a100_stark/columns.rs b/zk-pow/src/circuit/fp16/matmul_a100_stark/columns.rs new file mode 100644 index 000000000..81d4d73a2 --- /dev/null +++ b/zk-pow/src/circuit/fp16/matmul_a100_stark/columns.rs @@ -0,0 +1,277 @@ +//! Trace columns for one A100 `HMMA.16816.F32` accumulation step (one `G = 8` +//! group per row). +//! +//! A live row aligns 8 FP16 products and the incoming FP32 carry to the greatest +//! stored exponent `eta`, sums the signed terms as integers on the `2^(eta-24)` +//! grid, and truncates the result toward zero to a 24-bit FP32 significand. The +//! exponent axis is biased by +127 (the FP32 bias): a nonzero product's +//! `e_u = eps(a)+eps(b)` maps to `e_u + 127 in [99, 157]`, the carry's clamped +//! exponent `el` maps to `el + 127 in [1, 254]` (i.e. the FP32 exponent field), +//! and sentinel `0` marks a zero product / zero carry. +//! +//! See `docs/fp16_scheme/stark_feasibility.md` for the derivation and +//! `crate::api::fp16::accumulate` for the bit-exact plaintext oracle this trace +//! must match. Constraint labels `MA1..MA10` refer to `super::stark`. + +use crate::circuit::fp8::columns_view::columns_view; + +/// FP16 products per hardware accumulation group (A100 `HMMA` group size). +pub const GROUP: usize = 8; + +/// Length of the eta-attainment chain (MA2): 8 affine lane factors accumulated at +/// most two new factors per link after a first link of three, so every link +/// constraint stays degree <= 3. `3 + 2 + 2 + 1 = 8`. +pub const NUM_ATT_LINKS: usize = 4; + +/// View of one `MatmulStarkA100` trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct MatmulA100ColumnsView { + // ---- Structural, class (a): verifier-recomputable from the AIR geometry. ---- + /// Output cell index, constant across the cell's `k/8` rows. + pub cell_id: T, + /// 1 on each cell's last row. Gates the f32 encode and the carry reset. + pub is_cell_final: T, + /// Operand flat-index base for this row's 8 A lanes. + pub operand_index_base_a: T, + /// Operand flat-index base for the 8 B lanes (carries the `h*k` B-plane offset). + pub operand_index_base_b: T, + /// 1 on trailing power-of-two padding rows (single-row phantom cells). + pub is_padding: T, + + // ---- Per-lane operand decode (FP16DECODE LUT-served) + product (in-AIR). ---- + /// The lane's 16-bit FP16 A-operand code. + pub operand_codes_a: [T; GROUP], + /// The lane's 16-bit FP16 B-operand code. + pub operand_codes_b: [T; GROUP], + /// Decoded 11-bit A significand `m_a in [0, 2047]` (0 for a zero operand). + /// FP16DECODE value 0, keyed on [`Self::operand_codes_a`]. + pub sig_a: [T; GROUP], + /// Decoded 11-bit B significand `m_b in [0, 2047]`. + pub sig_b: [T; GROUP], + /// Raw sign bit of operand A (FP16DECODE value 1). Load-bearing only on nonzero lanes. + pub sign_a: [T; GROUP], + /// Raw sign bit of operand B (FP16DECODE value 1). + pub sign_b: [T; GROUP], + /// Biased stored exponent of operand A, `eps_a + 15 in [1, 30]` (FP16DECODE value 2). + pub eps_a: [T; GROUP], + /// Biased stored exponent of operand B, `eps_b + 15 in [1, 30]` (FP16DECODE value 2). + pub eps_b: [T; GROUP], + /// `[sig_a == 0]` (FP16DECODE value 3): operand A is a zero code. + pub is_zero_a: [T; GROUP], + /// `[sig_b == 0]` (FP16DECODE value 3): operand B is a zero code. + pub is_zero_b: [T; GROUP], + /// Product sign `sign_a xor sign_b` (boolean; MA1 derives it from the decoded sign bits). + pub lane_sign: [T; GROUP], + /// The product's biased stored exponent `ea + eb + 127 in [99, 157]`, or the + /// sentinel 0 for a zero product. MA1 derives it from the decoded per-operand + /// `eps_a/eps_b/is_zero_a/is_zero_b`: + /// `(1-is_zero_a)*(1-is_zero_b) * (eps_a + eps_b + 97)`. + pub product_biased_exp: [T; GROUP], + /// Exact product significand `P = m_a * m_b in [0, 2^22)` (MA1: `sig_a*sig_b`). + pub product_sig: [T; GROUP], + + // ---- Per-lane alignment (Euclidean truncation toward zero; MA3). ---- + /// `2^min(rel, 26)` for the lane's gap `rel = GROUP_MAX_BIASED_EXPONENT - + /// PRODUCT_BIASED_EXPONENT` (POW2 LUT). 1 on padding / zero lanes. + pub lane_shift_power: [T; GROUP], + /// Unsigned aligned lane magnitude `floor(P*16 / 2^rel) < 2^26`. + pub aligned_mag: [T; GROUP], + /// Euclidean remainder `P*16 - ALIGNED_MAG * LANE_SHIFT_POWER` (< LANE_SHIFT_POWER). + pub lane_rem: [T; GROUP], + /// Two-sidedness witness `LANE_SHIFT_POWER - 1 - LANE_REM`. + pub lane_rem_bound: [T; GROUP], + /// Census: 1 iff this product's truncation discarded a nonzero bit + /// (`LANE_REM != 0`). Boolean, pinned to `[LANE_REM != 0]` *exactly* by MA3's + /// two-sided census (clean `(1-flag)*rem = 0`, tight `flag*(1 - rem*inv) = 0`). + pub products_truncated_flag: [T; GROUP], + /// Tight-census inverse witness: `LANE_REM^{-1}` when the lane truncated, else 0. + /// MA3 pins `products_truncated_flag = 1 => LANE_REM != 0` via `flag*(rem*inv - 1) = 0`. + pub lane_rem_inv: [T; GROUP], + + // ---- Incoming-carry alignment (reads previous row's output as the carry). ---- + /// "The carry entering this row is zero" flag (propagated; MA7). + pub incoming_carry_is_zero: T, + /// `2^min(rel_c, 26)` for the carry gap (POW2 LUT), on the consuming row. + pub carry_shift_power: T, + /// Unsigned aligned carry `floor(2 * prev.OUT_SIG / 2^rel_c) < 2^25`. + pub aligned_carry: T, + /// Euclidean remainder of the carry alignment and its two-sided bound. + pub carry_rem: T, + pub carry_rem_bound: T, + /// Census: 1 iff the carry alignment discarded a nonzero bit (`CARRY_REM != 0`). + /// Boolean, pinned to `[CARRY_REM != 0]` exactly by MA11 (one half of a breakpoint). + pub carry_dropped: T, + /// Tight-census inverse witness: `CARRY_REM^{-1}` when the carry truncated, else 0. + pub carry_rem_inv: T, + + // ---- Window max + exact sum + round-toward-zero. ---- + /// The window anchor `eta + 127`: max biased stored exponent over nonzero + /// products and the carry; sentinel 0 on an all-zero + zero-carry row. + pub group_max_biased_exponent: T, + /// Inverse witness pinning [`group_nonempty`] (`group_max * inv = nonempty`). + pub group_max_inv: T, + /// 1 iff the group did real work (`GROUP_MAX_BIASED_EXPONENT != 0`). + pub group_nonempty: T, + /// Attainment chain (MA2): running product of the 8 affine lane factors + /// `GROUP_MAX_BIASED_EXPONENT - PRODUCT_BIASED_EXPONENT_i`; vanishes at the end. + pub max_exponent_attainment: [T; NUM_ATT_LINKS], + /// Sign of the signed window sum (boolean). + pub group_sum_sign: T, + /// Magnitude of the signed window sum (< 2^30). + pub group_sum_abs: T, + /// Zero-sum flag (boolean). + pub group_sum_is_zero: T, + /// Claimed bit width `W` of `GROUP_SUM_ABS` (in [1, 30]); WIDTH LUT key. + pub group_sum_width: T, + /// WIDTH-LUT pair for `W`: `2^max(W-24,0)` and `2^max(24-W,0)`. + pub truncation_power: T, + pub lifting_power: T, + /// `floor(GROUP_SUM_ABS * LIFTING_POWER / TRUNCATION_POWER) in [2^23, 2^24)`. + pub norm_sig: T, + /// Euclidean remainder of the normalization and its two-sided bound. + pub trunc_rem: T, + pub trunc_rem_bound: T, + /// Census: 1 iff the RZ normalization discarded a nonzero bit (`TRUNC_REM != 0`). + /// Boolean, pinned to `[TRUNC_REM != 0]` exactly by MA11 (the other half of a breakpoint). + pub rz_dropped: T, + /// Tight-census inverse witness: `TRUNC_REM^{-1}` when the RZ dropped a bit, else 0. + pub trunc_rem_inv: T, + /// Census: 1 iff the carry alignment or the RZ normalization dropped a bit + /// (a breakpoint). Boolean, pinned *exactly* to + /// `GROUP_NONEMPTY * (CARRY_DROPPED OR RZ_DROPPED)` by MA11 — equals the + /// `a100_dot` breakpoint census bit-for-bit, so it can neither be over- nor + /// under-stated (the policy AIR's `rho`/`f_bp` gate depends on this tightness). + pub group_breakpoint: T, + + // ---- Group output (= the carry entering the next row). ---- + /// Output sign (mux of the normal and +0 paths; MA8). + pub out_sign: T, + /// Output biased exponent: `GROUP_MAX_BIASED_EXPONENT + W - 25` (the FP32 + /// exponent field) on the normal path, sentinel 0 on both the zero path and + /// the subnormal path (an FP32 subnormal has exponent field 0). + pub out_biased_exp: T, + /// Output significand: the normalized 24-bit `NORM_SIG` on the normal path, + /// the (`< 2^23`) subnormal mantissa on the subnormal path, 0 on the zero path. + pub out_sig: T, + + // ---- Subnormal FP32-output RZ branch (MA13). An output whose normal biased + // exponent `GROUP_MAX_BIASED_EXPONENT + W - 25` would be `<= 0` is an FP32 + // subnormal (`|x| < 2^-126`): it is encoded on the `2^-149` grid with exponent + // field 0 and a `< 2^23` mantissa holding fewer significand bits. The honest + // from-zero matmul datapath never reaches this branch (FP16 products align at + // `eta >= 99`, so a group output floors at `~2^-52`); the constraints below pin + // the flag so the branch is a sound guard, and give the bit-exact `2^-149` + // encode for the accumulation datapath (subnormal carry-in) the oracle + // `a100_dot` already models. ---- + /// 1 iff this group's output is an FP32 subnormal (boolean; MA13). Forced 0 on + /// the zero path and, in the from-zero AIR, on every live row (unreachable). + pub out_is_subnormal: T, + /// Nonnegative RANGE16 slack pinning the subnormal flag against the raw exponent + /// `raw = GROUP_MAX_BIASED_EXPONENT + W - 25`: `raw - 1` on the normal path (so + /// `raw >= 1`), `-raw` on the subnormal path (so `raw <= 0`). 0 on the zero path. + pub exp_slack: T, + /// Subnormal right-shift exponent `k = 1 - raw = 26 - GROUP_MAX_BIASED_EXPONENT - W` + /// (`>= 1` on the subnormal path): the number of low `NORM_SIG` bits dropped to + /// land the mantissa on the `2^-149` grid. FP16POW2 key (subnormal-filtered). + pub sub_shift_exp: T, + /// `2^sub_shift_exp` (FP16POW2 value, subnormal-filtered): the subnormal RZ divisor + /// `NORM_SIG = OUT_SIG * SUB_SHIFT_POWER` (exact — the reachable subnormal outputs + /// keep whole `NORM_SIG` high bits). 1 (inert) off the subnormal path. + pub sub_shift_power: T, + /// `OUT_SIG` low/high limbs on the subnormal path (`OUT_SIG < 2^23`): RANGE16-checked + /// and reconstructed (`OUT_SIG = lo + 2^16*hi`) so the subnormal mantissa is a genuine + /// small integer, not a field-wrapped quotient. 0 off the subnormal path. + pub out_sig_lo: T, + pub out_sig_hi: T, + + // ---- Limb splits of the 26-bit Euclidean-floor witnesses (MA12). Each tracked magnitude is + // reconstructed as `lo + 2^16 * hi` with `lo` RANGE16-checked (`< 2^16`) and `hi` scaled by + // `2^6` and RANGE16-checked (`< 2^10`, so the magnitude is `< 2^26`). This makes the per-lane + // and carry `floor` identities integer-exact against Goldilocks field-fraction aliasing in a + // real FRI proof: a wrapped quotient/remainder has no valid 16/10-bit limb witness. ---- + /// `aligned_mag[i]` low/high limbs. + pub aligned_mag_lo: [T; GROUP], + pub aligned_mag_hi: [T; GROUP], + /// `lane_rem[i]` low/high limbs. + pub lane_rem_lo: [T; GROUP], + pub lane_rem_hi: [T; GROUP], + /// `lane_rem_bound[i]` low/high limbs. + pub lane_rem_bound_lo: [T; GROUP], + pub lane_rem_bound_hi: [T; GROUP], + /// `aligned_carry` low/high limbs. + pub aligned_carry_lo: T, + pub aligned_carry_hi: T, + /// `carry_rem` low/high limbs. + pub carry_rem_lo: T, + pub carry_rem_hi: T, + /// `carry_rem_bound` low/high limbs. + pub carry_rem_bound_lo: T, + pub carry_rem_bound_hi: T, + /// `norm_sig` low/high limbs (`norm_sig < 2^24`, so the `2^6`-scaled hi check bounds it by + /// `2^26` — ample for the RZ floor's no-wrap guarantee). + pub norm_sig_lo: T, + pub norm_sig_hi: T, + + // ---- Cell result + policy census totals. ---- + /// Low / high 16-bit limbs of the cell result's FP32 word (MA9, cell-final rows). + pub cell_result_f32_lo: T, + pub cell_result_f32_hi: T, + /// In-cell running count of `products_truncated_flag` (rides the result channel). + pub cell_products_truncated: T, + /// In-cell running count of `group_breakpoint`. + pub cell_breakpoints: T, +} + +/// Total number of committed `MatmulStarkA100` columns. +pub const NUM_MATMUL_A100_COLUMNS: usize = size_of::>(); + +// 19 per-lane arrays of 8 (= 152) + 5 structural + 7 carry + 19 window/RZ +// + 3 output + 4 result/census = 190, plus the MA12 limb splits: 6 per-lane arrays of 8 (= 48) +// + 8 carry/RZ limb singles = 56 -> 246, plus the MA13 subnormal-branch block +// (out_is_subnormal, exp_slack, sub_shift_exp, sub_shift_power, out_sig_lo, out_sig_hi) = 6 -> 252. +const _: () = assert!(NUM_MATMUL_A100_COLUMNS == 252); + +columns_view!(MatmulA100ColumnsView, NUM_MATMUL_A100_COLUMNS, MATMUL_A100_COL_MAP); + +/// Number of leading class (a) ("known") columns (pure functions of AIR geometry). +pub const NUM_MATMUL_A100_KNOWN_COLUMNS: usize = MATMUL_A100_COL_MAP.is_padding + 1; + +/// Number of public inputs — none: the AIR is program-independent. +pub const NUM_MATMUL_A100_PUBLIC_INPUTS: usize = 0; + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_MATMUL_A100_COLUMNS] = MATMUL_A100_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + assert_eq!(MATMUL_A100_COL_MAP.cell_id, 0); + assert_eq!(MATMUL_A100_COL_MAP.is_cell_final, 1); + assert_eq!(MATMUL_A100_COL_MAP.operand_index_base_a, 2); + assert_eq!(MATMUL_A100_COL_MAP.operand_index_base_b, 3); + assert_eq!(MATMUL_A100_COL_MAP.is_padding, 4); + assert_eq!(NUM_MATMUL_A100_KNOWN_COLUMNS, 5); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_MATMUL_A100_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: MatmulA100ColumnsView = arr.into(); + assert_eq!(view.cell_id, 1); + assert_eq!(view.product_sig[0], MATMUL_A100_COL_MAP.product_sig[0] as u64 * 3 + 1); + let back: [u64; NUM_MATMUL_A100_COLUMNS] = view.into(); + assert_eq!(back, arr); + let borrowed: &MatmulA100ColumnsView = arr.borrow(); + assert_eq!(borrowed.group_max_biased_exponent, arr[MATMUL_A100_COL_MAP.group_max_biased_exponent]); + } +} diff --git a/zk-pow/src/circuit/fp16/matmul_a100_stark/ctl.rs b/zk-pow/src/circuit/fp16/matmul_a100_stark/ctl.rs new file mode 100644 index 000000000..6f1f7c29f --- /dev/null +++ b/zk-pow/src/circuit/fp16/matmul_a100_stark/ctl.rs @@ -0,0 +1,305 @@ +//! Committed-LUT inventory for the A100 FP16 matmul AIR. +//! +//! The matmul AIR trusts a family of auxiliary columns — the per-operand decode fields, the +//! per-lane and carry alignment powers, the RZ truncation/lifting powers, and the FP32 result +//! limbs. This module declares, as [`LutLookup`]s, how each is served by a committed LUT whose +//! own AIR constrains it, so that the matmul STARK's *own* verification (the CTL multiset +//! balance of [`super::super::ctl`]) enforces them: +//! +//! * **FP16DECODE** (`2^16` keys), two lookups per lane: `code -> (sig, sign, eps_biased, +//! is_zero)`. MA1 derives each lane's product significand, sign, and biased stored exponent +//! from these, so a forged decode breaks either the lookup or MA1. +//! * **FP16POW2** (`2^min(d, 26)`, `d in [0, 255]`), one lookup per lane, one for the +//! incoming carry, and one (subnormal-filtered) for the MA13 subnormal RZ divisor +//! `SUB_SHIFT_POWER = 2^k`: the alignment divisor keyed on the relative shift +//! `GROUP_MAX_BIASED_EXPONENT - PRODUCT_BIASED_EXPONENT`. A negative shift wraps out of the +//! key domain, so the lookup also proves the eta ">=" side +//! (`GROUP_MAX_BIASED_EXPONENT >= PRODUCT_BIASED_EXPONENT`). The carry instance is anchored +//! at the producing row and reads the consuming (next) row's witness, filtered off when the +//! carry is zero — mirroring FP8 B200's `Pow2Gb` carry lookup. +//! * **WIDTH32** (keys `[1, 32]`), one filtered lookup: `W -> (2^max(W-24,0), 2^max(24-W,0))`. +//! The shifted-ramp domain also proves `1 <= GROUP_SUM_WIDTH <= 32`. +//! * **RANGE16**, the FP32 result limbs `CELL_RESULT_F32_LO/HI < 2^16` (MA9's limb split), the +//! MA12 limb-range splits of the Euclidean-floor witnesses (`aligned_mag`, `lane_rem`, +//! `lane_rem_bound` per lane; `aligned_carry`, `carry_rem`, `carry_rem_bound`; `norm_sig` — each +//! as `lo < 2^16` and `2^6*hi < 2^16`, bounding the magnitude by `~2^26`), `norm_sig` +//! additionally pinned to the normalized range `[2^23, 2^24)` on nonzero-sum rows (so the MA7 +//! width identity cannot admit a false `GROUP_SUM_WIDTH` — the B200 MB7 check), and the RZ +//! remainder `trunc_rem`/`trunc_rem_bound` (`< TRUNCATION_POWER <= 2^6`). +//! +//! With MA12's reconstruction constraints (`value = lo + 2^16*hi`), the limb ranges make the +//! per-lane and carry `floor` identities integer-exact against Goldilocks field-fraction aliasing +//! in a real FRI proof (a wrapped quotient/remainder has no valid 16/10-bit limb witness), closing +//! the gap-1 residual the feasibility doc flagged. The decode/shift/width facts are the ones it +//! enumerated as "every decoded sig/eps, every shift power, every width". + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::{GROUP, MATMUL_A100_COL_MAP}; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// The A100 matmul's **looked** side of the cell-results channel: the finished output tile cell +/// `(CELL_ID, CELL_RESULT_F32_LO, CELL_RESULT_F32_HI)`, filtered to each cell's final, live row +/// (`IS_CELL_FINAL * (1 - IS_PADDING)`). The XorFold AIR's looking side +/// ([`super::super::xor_fold_stark::ctl::ctl_cell_results_looking_xor_fold`]) folds exactly these +/// cell words into the lottery lanes, so the multiset equality binds the folded tile to the matmul's +/// proven output. +/// +/// This is the FP16 analogue of +/// [`crate::circuit::fp8::matmul_h100::ctl::ctl_cell_results_looked_matmul`], dropping the FP8 +/// `CELL_SKIPS` census field (FP16 scores its jackpot in the policy AIR, and the matmul -> policy +/// census-import CTL carries the per-step census). The matmul table's batch index is supplied by the +/// batch-integration step. +pub fn ctl_cell_results_looked_matmul(matmul_table: usize) -> TableWithColumns { + ctl_cell_results_looked_matmul_offset(matmul_table, 0) +} + +/// Like [`ctl_cell_results_looked_matmul`] but adds a constant `cell_offset` to the `CELL_ID` key. +/// Used by the noise-word channel (6e-2) to shift the B-side noise matmul's cell ids (`0..w*k`) into +/// the shared noisy-quant element-index space (`h*k..(h+w)*k`), so both noise matmuls' cell results +/// balance one noisy-quant looked side keyed by the global element index. +pub fn ctl_cell_results_looked_matmul_offset(matmul_table: usize, cell_offset: usize) -> TableWithColumns { + let m = &MATMUL_A100_COL_MAP; + TableWithColumns::new( + TableIdx::from(matmul_table), + vec![ + Column::linear_combination_with_constant([(m.cell_id, F::ONE)], F::from_canonical_usize(cell_offset)), + Column::single(m.cell_result_f32_lo), + Column::single(m.cell_result_f32_hi), + ], + Filter::new( + vec![( + Column::single(m.is_cell_final), + Column::linear_combination_with_constant([(m.is_padding, -F::ONE)], F::ONE), + )], + vec![], + ), + ) +} + +/// The A100 matmul's **looking** side of the operand-codes channel (6d): per live row, for each of +/// the 8 lanes of each operand, the tuple `(operand_index_base_{a,b} + lane, operand_codes_{a,b}[lane])` +/// — the global operand element index and the FP16 code the matmul multiplies. Filter +/// `1 - IS_PADDING`. `operand_index_base_a/b` are class (a) known columns (verifier-recomputed from +/// geometry), so the keys are fixed and only the `operand_codes` values are witness. The counterpart +/// looked side ([`crate::circuit::fp16::noisy_quant_stark::ctl::ctl_operand_codes_looked_noisy_quant`]) +/// emits each element's noised `OUT` once, with the reuse multiplicity, so the multiset balance binds +/// every matmul operand code to the noised quantization of the committed operand — and forces cells +/// of one output row (resp. column) to reuse the same A (resp. B) element, since they key on the same +/// `operand_index_base + lane`. The FP16 analogue of +/// [`crate::circuit::fp8::matmul_h100::ctl::ctl_operand_codes_looking_matmul`] (one u16 code per lane, +/// not a packed int8 pair; no summand-score lambdas — FP16 scores its jackpot in the policy AIR). The +/// matmul table's batch index is supplied by the batch-integration step. +pub fn ctl_operand_codes_looking_matmul(matmul_table: usize) -> Vec> { + ctl_operand_codes_looking_matmul_offset(matmul_table, 0) +} + +/// Like [`ctl_operand_codes_looking_matmul`] but adds a constant `index_offset` to every operand +/// element key (`operand_index_base + lane + index_offset`). Used by the E/F-operand binding channel +/// (6e-2): a noise matmul's operand codes (`E`/`F`) are bound to NoiseStark's proven normalized line +/// entries, keyed by the global entry index `line * rank + entry`. The A-side noise matmul needs no +/// offset (its own `[0, (h+k)*r)` index space already matches NoiseStark's leading `E_A`,`F_A` +/// blocks); the B-side matmul's entire `[0, (w+k)*r)` space is shifted by `(h+k)*r` onto the trailing +/// `E_B`,`F_B` blocks. +pub fn ctl_operand_codes_looking_matmul_offset( + matmul_table: usize, + index_offset: usize, +) -> Vec> { + let m = &MATMUL_A100_COL_MAP; + let not_padding = || { + Filter::from_column(Column::linear_combination_with_constant([(m.is_padding, -F::ONE)], F::ONE)) + }; + let mut lookups = Vec::with_capacity(2 * GROUP); + for i in 0..GROUP { + for (base, codes) in [(m.operand_index_base_a, &m.operand_codes_a), (m.operand_index_base_b, &m.operand_codes_b)] { + lookups.push(TableWithColumns::new( + TableIdx::from(matmul_table), + vec![ + Column::linear_combination_with_constant( + [(base, F::ONE)], + F::from_canonical_usize(i + index_offset), + ), + Column::single(codes[i]), + ], + not_padding(), + )); + } + } + lookups +} + +/// Every committed-LUT instance the A100 matmul AIR consumes on a row: FP16DECODE x16 (8 lanes +/// x 2 operands), FP16POW2 x10 (8 lanes + 1 carry + 1 MA13 subnormal RZ divisor), WIDTH32 x1, +/// RANGE16 x64 (2 result limbs + 58 MA12/MA13 floor-witness limb checks + 2 RZ-remainder checks +/// + 1 MA13 exp_slack + 1 NORM_SIG [2^23,2^24) range pin) — 91 instances. The inventory is +/// program-independent (no geometry +/// constants bake into any key/value/filter). +pub fn matmul_a100_lut_lookups() -> Vec> { + let m = &MATMUL_A100_COL_MAP; + let one = F::ONE; + let neg = -F::ONE; + let mut lookups = Vec::with_capacity(2 * GROUP + (GROUP + 1) + 1 + 60); + + // ---- FP16DECODE: the per-operand decode of both operands of every lane. ---- + for i in 0..GROUP { + lookups.push(LutLookup { + table: LutTable::Fp16Decode, + keys: vec![Column::single(m.operand_codes_a[i])], + values: Column::singles([m.sig_a[i], m.sign_a[i], m.eps_a[i], m.is_zero_a[i]]).collect(), + filter: Filter::default(), + }); + lookups.push(LutLookup { + table: LutTable::Fp16Decode, + keys: vec![Column::single(m.operand_codes_b[i])], + values: Column::singles([m.sig_b[i], m.sign_b[i], m.eps_b[i], m.is_zero_b[i]]).collect(), + filter: Filter::default(), + }); + } + + // ---- FP16POW2: per-lane alignment divisor, keyed on the relative shift. ---- + for i in 0..GROUP { + lookups.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::linear_combination([ + (m.group_max_biased_exponent, one), + (m.product_biased_exp[i], neg), + ])], + values: vec![Column::single(m.lane_shift_power[i])], + filter: Filter::default(), + }); + } + + // ---- FP16POW2: the incoming-carry alignment, anchored at the producing row (reads the + // consuming/next row), filtered off when that carry is zero. Out-of-domain negative keys + // prove GROUP_MAX_BIASED_EXPONENT' >= the carry's exponent; the cyclic wrap is inert because + // row 0's INCOMING_CARRY_IS_ZERO is anchored to 1 (MA6). ---- + lookups.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::linear_combination_and_next_row_with_constant( + vec![(m.out_biased_exp, neg)], + vec![(m.group_max_biased_exponent, one)], + F::ZERO, + )], + values: vec![Column::single_next_row(m.carry_shift_power)], + filter: Filter::from_column(Column::linear_combination_and_next_row_with_constant( + vec![], + vec![(m.incoming_carry_is_zero, neg)], + one, + )), + }); + + // ---- WIDTH32: the RZ truncate/lift powers, keyed on the claimed width (1..=32). ---- + let group_sum_is_nonzero = Filter::from_column(Column::linear_combination_with_constant([(m.group_sum_is_zero, neg)], one)); + lookups.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.group_sum_width)], + values: Column::singles([m.truncation_power, m.lifting_power]).collect(), + filter: group_sum_is_nonzero.clone(), + }); + + // ---- FP16POW2: the subnormal RZ divisor SUB_SHIFT_POWER = 2^k (MA13), keyed on the + // subnormal shift exponent k = 1 - raw, filtered to subnormal-output rows. The key domain + // (k in [1, 26]) bounds the shift; the lookup binds the committed power. ---- + lookups.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.sub_shift_exp)], + values: vec![Column::single(m.sub_shift_power)], + filter: Filter::from_column(Column::single(m.out_is_subnormal)), + }); + + // ---- RANGE16: the FP32 cell-result limbs (MA9). ---- + lookups.push(LutLookup::rc16(Column::single(m.cell_result_f32_lo))); + lookups.push(LutLookup::rc16(Column::single(m.cell_result_f32_hi))); + + // ---- RANGE16: the MA13 subnormal flag slack (`exp_slack < 2^16`; pins the flag to + // `[raw <= 0]` by having no valid nonnegative witness for the wrong claim). ---- + lookups.push(LutLookup::rc16(Column::single(m.exp_slack))); + + // ---- RANGE16: MA12 limb-range splits of the Euclidean-floor witnesses. For each tracked + // magnitude, `lo` is checked `< 2^16` and `2^6 * hi` is checked `< 2^16` (so `hi < 2^10`, + // bounding the magnitude by `~2^26`). With MA12's reconstruction constraint + // (`value = lo + 2^16*hi`) these make the per-lane and carry `floor` identities integer-exact + // against Goldilocks field-fraction aliasing in a real FRI proof. ---- + let hi6 = F::from_canonical_u64(1 << 6); + let mut split = |lo: usize, hi: usize| { + lookups.push(LutLookup::rc16(Column::single(lo))); + lookups.push(LutLookup::rc16(Column::linear_combination([(hi, hi6)]))); + }; + for i in 0..GROUP { + split(m.aligned_mag_lo[i], m.aligned_mag_hi[i]); + split(m.lane_rem_lo[i], m.lane_rem_hi[i]); + split(m.lane_rem_bound_lo[i], m.lane_rem_bound_hi[i]); + } + split(m.aligned_carry_lo, m.aligned_carry_hi); + split(m.carry_rem_lo, m.carry_rem_hi); + split(m.carry_rem_bound_lo, m.carry_rem_bound_hi); + split(m.norm_sig_lo, m.norm_sig_hi); + // MA13: the subnormal mantissa OUT_SIG's limbs (0 off the subnormal path, so the check is + // vacuous there; on subnormal rows it bounds OUT_SIG < 2^26). Combined with the NORM_SIG + // normalized-range pin below (NORM_SIG < 2^24 on nonzero-sum rows) and the exact division + // NORM_SIG = OUT_SIG * 2^k (k >= 1), this forces OUT_SIG < 2^23 — a valid subnormal mantissa. + split(m.out_sig_lo, m.out_sig_hi); + drop(split); + + // ---- RANGE16: pin NORM_SIG into the normalized range [2^23, 2^24) on nonzero-sum rows. ---- + // The MA12 split above only bounds NORM_SIG < 2^26. That is NOT enough: the MA7 width identity + // `GROUP_SUM_ABS * LIFTING_POWER = NORM_SIG * TRUNCATION_POWER + TRUNC_REM` (with 0 <= TRUNC_REM + // < TRUNCATION_POWER) then admits *any* GROUP_SUM_WIDTH in [1,32] for a given sum magnitude — + // the prover can pick a false width, choose TRUNC_REM != 0, and so forge RZ_DROPPED (MA11), + // hence GROUP_BREAKPOINT, hence the jackpot census (f_bp / rho). Forcing + // `(NORM_SIG_HI - 128) * 2^9 < 2^16` pins NORM_SIG_HI in [128, 256), i.e. NORM_SIG in + // [2^23, 2^24), which pins GROUP_SUM_WIDTH to the true bit-width and makes the RZ breakpoint + // exact. This mirrors the FP8 B200 MB7 normalized-significand check (whose omission here was a + // soundness gap); filtered off on zero-sum rows, where NORM_SIG is unconstrained (and 0). + lookups.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant( + [(m.norm_sig_hi, F::from_canonical_u64(1 << 9))], + -F::from_canonical_u64(128 << 9), + ), + group_sum_is_nonzero.clone(), + )); + + // ---- RANGE16: the RZ Euclidean remainder and its two-sided bound (both < TRUNCATION_POWER + // <= 2^6 < 2^16, so no limb split is needed). Together they pin `0 <= TRUNC_REM < + // TRUNCATION_POWER` as genuine small integers, making the MA7 normalization floor exact. ---- + lookups.push(LutLookup::rc16(Column::single(m.trunc_rem))); + lookups.push(LutLookup::rc16(Column::single(m.trunc_rem_bound))); + + lookups +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + + type F = GoldilocksField; + + #[test] + fn cell_results_looked_half_is_well_formed() { + // Any placeholder table index is fine; the real index is supplied at batch integration. + let _ = ctl_cell_results_looked_matmul::(0); + assert_eq!(ctl_operand_codes_looking_matmul::(0).len(), 2 * GROUP, "8 lanes x 2 operands"); + } + + #[test] + fn inventory_matches_documented_counts() { + let lookups = matmul_a100_lut_lookups::(); + let count = |t: LutTable| lookups.iter().filter(|l| l.table == t).count(); + assert_eq!(count(LutTable::Fp16Decode), 2 * GROUP); + // 8 lanes + 1 carry + 1 subnormal RZ divisor (MA13). + assert_eq!(count(LutTable::Fp16Pow2), GROUP + 2); + assert_eq!(count(LutTable::Width32), 1); + // RANGE16: 2 cell-result limbs + 2 per MA12-split witness (3 per lane + 3 carry + norm_sig + // + the MA13 out_sig mantissa = 29 witnesses -> 58 limb checks) + the RZ remainder and its + // bound + the MA13 exp_slack + the NORM_SIG [2^23,2^24) normalized-range pin = 64. + let range16 = 2 + 2 * (3 * GROUP + 3 + 1 + 1) + 2 + 1 + 1; + assert_eq!(count(LutTable::Range16), range16); + assert_eq!(count(LutTable::Range16), 64); + assert_eq!(lookups.len(), 2 * GROUP + (GROUP + 2) + 1 + range16); + } +} diff --git a/zk-pow/src/circuit/fp16/matmul_a100_stark/mod.rs b/zk-pow/src/circuit/fp16/matmul_a100_stark/mod.rs new file mode 100644 index 000000000..508474111 --- /dev/null +++ b/zk-pow/src/circuit/fp16/matmul_a100_stark/mod.rs @@ -0,0 +1,15 @@ +//! A100 (`sm_80`) FP16 `HMMA.16816.F32` matrix-multiplication AIR. +//! +//! Each row computes one `G = 8`-lane accumulation step on the `2^(eta-24)` window +//! and truncates its carry toward zero to a 24-bit FP32 significand; cell-final rows +//! emit an FP32 cell result. This is the ZK analogue of +//! `crate::api::fp16::accumulate::a100_dot`. See `docs/fp16_scheme/stark_feasibility.md`. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{ + MATMUL_A100_COL_MAP, MatmulA100ColumnsView, NUM_MATMUL_A100_COLUMNS, NUM_MATMUL_A100_KNOWN_COLUMNS, +}; +pub use stark::MatmulStarkA100; diff --git a/zk-pow/src/circuit/fp16/matmul_a100_stark/stark.rs b/zk-pow/src/circuit/fp16/matmul_a100_stark/stark.rs new file mode 100644 index 000000000..7e69bd2ee --- /dev/null +++ b/zk-pow/src/circuit/fp16/matmul_a100_stark/stark.rs @@ -0,0 +1,1400 @@ +//! Proves the NVIDIA A100 (`sm_80`) `HMMA.16816.F32` FP16 matmul accumulation, +//! one `G = 8` group per trace row. +//! +//! This AIR is the ZK analogue of `crate::api::fp16::accumulate::a100_dot`, which +//! it must match bit-for-bit. See `docs/fp16_scheme/stark_feasibility.md` for the +//! derivation and the GO-WITH-CHANGES verdict; the structure forks +//! `circuit::fp8::matmul_b200_stark`, with the two documented changes: +//! +//! * FP16 operand pairs span `2^32`, so there is no operand-keyed product LUT. +//! Each lane decodes its two operands (an `FP16DECODE` LUT, 2^16 keys), the +//! product significand is an in-AIR multiply, and the alignment is an in-AIR +//! Euclidean floor against a `POW2` LUT — exactly B200's carry-alignment gadget, +//! applied per lane. +//! * `G = 8` gives `k/8` rows per cell (4x B200). For production-size tiles the +//! feasibility doc recommends packing several groups per row; the delivered AIR +//! keeps one group per row (correct; test geometries stay small). +//! +//! # Exponent axis +//! +//! Biased by +127 (the FP32 bias). A nonzero product's `e_u = eps(a)+eps(b)` maps +//! to `PRODUCT_BIASED_EXP = e_u + 127 in [99, 157]`; the carry's clamped exponent +//! `el` maps to `el + 127 in [1, 254]` (the FP32 exponent field). Sentinel 0 marks +//! a zero product / zero carry. +//! +//! # One group step (live row) +//! +//! `eta = max(PRODUCT_BIASED_EXP over nonzero lanes, carry exponent)`; the window +//! unit is `2^(eta - 24)`. Each lane contributes `±floor(P*16 / 2^rel)`, +//! `rel = eta - PRODUCT_BIASED_EXP` (the `*16` lifts the product's +//! `2^(e_u-20)` scale onto the window; `P*16 < 2^26` so `rel >= 26` drops it). The +//! carry contributes `±floor(2*cm / 2^rel_c)` (`2*cm < 2^25`). The 8 terms and the +//! carry sum exactly (`|sum| < 2^30`); the sum is truncated toward zero to a 24-bit +//! significand and re-biased to FP32. A cell-final row exports the FP32 word. +//! +//! # Scope (honest) +//! +//! The normal, zero, and subnormal output paths are all constrained. The normal and +//! zero paths cover the 238 GPU-validated reference vectors (237 normal + 1 zero). +//! Subnormal FP32 outputs (value `< 2^-126`) take a distinct RZ branch — exponent field +//! 0, mantissa `NORM_SIG >> k` on the `2^-149` grid — now written as MA13 and gated by +//! the `out_is_subnormal` flag, which MA13 pins to `[raw exp <= 0]` via a nonnegative +//! RANGE16 slack. The from-zero datapath never reaches the subnormal branch (FP16 +//! products align at `eta >= 99`, so a group output floors at `~2^-52`), so MA13 is a +//! sound guard there; the branch is exercised by the subnormal carry-in the oracle +//! `a100_dot` models, and the generator computes it bit-exactly. +//! +//! The semantic auxiliary columns — the per-operand decode (`sig_*`, `sign_*`, +//! `eps_*`, `is_zero_*`), the per-lane/carry alignment powers (`*_shift_power`) and +//! the RZ truncate/lift powers (`truncation_power`/`lifting_power`), plus the FP32 +//! result limbs — are enforced by committed-LUT cross-table lookups (see +//! [`super::ctl`] and [`crate::circuit::fp16::ctl`]): FP16DECODE, FP16POW2, WIDTH32, +//! and RANGE16. The per-step census that feeds the policy AIR is pinned bit-exactly +//! by MA3/MA11. The 16/10-bit limb-range RANGE16 splits (MA12) make the per-lane and +//! carry Euclidean floors integer-exact against field-fraction aliasing (the +//! `aligned_*`/`*_rem`/`*_bound` 26-bit magnitudes and the RZ `norm_sig`/`trunc_rem`), +//! so the AIR is sound under a real FRI proof — see [`super::ctl`] and +//! [`crate::circuit::fp16::driver`]. **Remaining follow-on:** the recursive FRI wrapper +//! to a constant-size proof. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +#[allow(unused_imports)] +use plonky2::field::types::Field; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +#[allow(unused_imports)] +use super::columns::MATMUL_A100_COL_MAP; +use super::columns::{ + GROUP, MatmulA100ColumnsView, NUM_ATT_LINKS, NUM_MATMUL_A100_COLUMNS, NUM_MATMUL_A100_PUBLIC_INPUTS, +}; +use crate::api::fp16::dtype::fp16_decode_fields; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// Internal accumulator precision (FP32 significand bits). +const W: u64 = 24; +/// The window keeps 24 fractional bits: shifts of a lifted operand cap here, since +/// `P*16 < 2^26` and `2*cm < 2^25` are both floored to 0 by any larger shift. +const SHIFT_CAP: u64 = 26; +/// `GROUP_MAX_BIASED_EXPONENT + W - 25`: the `-25` is the 24 window bits plus the +/// leading-bit position, mirroring B200's `-26` at its 25-bit window. +const OUT_EXP_OFFSET: u64 = 25; +/// Normalized significands live in `[2^23, 2^24)`. +const SIG24_MIN: u64 = 1 << 23; + +// ================================================================================================== +// Program geometry +// ================================================================================================== + +/// The A100 `HMMA` AIR for one FP16 matmul: `out[r,c] = sum_t A[r,t] * B[t,c]`. +#[derive(Clone, Debug)] +pub struct MatmulStarkA100, const D: usize> { + /// Output rows (rows of A). + pub h: usize, + /// Output columns (rows of B — B is the transposed logical operand). + pub w: usize, + /// Inner dimension; must be a multiple of [`GROUP`]. + pub k: usize, + /// Committed trace height (a power of two `>= live_rows`). Defaults to the next power of + /// two above the live rows ([`Self::new`]); a larger on-ladder height can be forced with + /// [`Self::new_with_height`] (used by the FP16 batch's noise matmul to keep its height on the + /// consensus FRI fold ladder). The extra rows are single-row phantom cells. + height: usize, + _phantom: PhantomData, +} + +impl, const D: usize> MatmulStarkA100 { + pub fn new(h: usize, w: usize, k: usize) -> Self { + assert_eq!(k % GROUP, 0, "k must be a multiple of the group size {GROUP}"); + let height = (h * w * (k / GROUP)).next_power_of_two(); + Self { h, w, k, height, _phantom: PhantomData } + } + + /// Like [`Self::new`] but pads the trace to `height` (a power of two `>= live_rows`) rather + /// than only to the next power of two. The FP16 batch uses this for the `N = E@F^T` noise + /// matmul so its committed height lands on a [`crate::circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS`] + /// member (the next power of two is not always on the ladder); the extra rows are phantom cells. + pub fn new_with_height(h: usize, w: usize, k: usize, height: usize) -> Self { + assert_eq!(k % GROUP, 0, "k must be a multiple of the group size {GROUP}"); + assert!(height.is_power_of_two(), "the forced height must be a power of two"); + assert!(height >= h * w * (k / GROUP), "the forced height must cover the live rows"); + Self { h, w, k, height, _phantom: PhantomData } + } + + /// Trace rows per output cell: its `k/8` live group-steps. + pub fn rows_per_cell(&self) -> usize { + self.k / GROUP + } + + /// Rows covering real cells (`h*w` cells, row-major). + pub fn live_rows(&self) -> usize { + self.h * self.w * self.rows_per_cell() + } + + /// Trace height: live rows padded to [`Self::height`] with single-row phantom cells. + pub fn num_rows(&self) -> usize { + self.height + } + + /// The class (a) ("known") columns — pure functions of the AIR geometry, + /// bit-exact with [`Self::generate_trace`]'s fill. + pub fn known_values(&self) -> Vec> { + let (h, w, k) = (self.h, self.w, self.k); + let rpc = self.rows_per_cell(); + let num_rows = self.num_rows(); + let mut cell_id = Vec::with_capacity(num_rows); + let mut is_cell_final = Vec::with_capacity(num_rows); + let mut base_a = Vec::with_capacity(num_rows); + let mut base_b = Vec::with_capacity(num_rows); + let mut is_padding = Vec::with_capacity(num_rows); + for r in 0..h { + for c in 0..w { + for j in 0..rpc { + cell_id.push(F::from_canonical_usize(r * w + c)); + is_cell_final.push(F::from_bool(j == rpc - 1)); + base_a.push(F::from_canonical_usize(r * k + j * GROUP)); + base_b.push(F::from_canonical_usize(h * k + c * k + j * GROUP)); + is_padding.push(F::ZERO); + } + } + } + for t in 0..num_rows - self.live_rows() { + cell_id.push(F::from_canonical_usize(h * w + t)); + is_cell_final.push(F::ONE); + base_a.push(F::ZERO); + base_b.push(F::ZERO); + is_padding.push(F::ONE); + } + [cell_id, is_cell_final, base_a, base_b, is_padding] + .into_iter() + .map(PolynomialValues::new) + .collect() + } +} + +// ================================================================================================== +// Decoded operands and the carry triple +// ================================================================================================== + +/// One decoded FP16 x FP16 product. The per-operand fields (`sig_*`, `sign_*`, `eps_*`, +/// `is_zero_*`) are exactly the FP16DECODE LUT outputs CTL-bound into the trace; everything +/// else is the in-AIR derivation MA1 re-checks against them. +#[derive(Clone, Copy, Debug)] +struct A100Product { + sig_a: u64, + sig_b: u64, + /// Raw sign bits of the two operands (FP16DECODE value 1). + sign_a: bool, + sign_b: bool, + /// Biased stored exponents `eps + 15 in [1, 30]` (FP16DECODE value 2). + eps_a: u64, + eps_b: u64, + /// `[sig == 0]` per operand (FP16DECODE value 3). + is_zero_a: bool, + is_zero_b: bool, + /// `sig_a * sig_b < 2^22`. + product_sig: u64, + /// `sign_a xor sign_b` (irrelevant on zero lanes, whose aligned term is 0). + sign: bool, + /// `ea + eb + 127 in [99, 157]`, or 0 for a zero product. + biased_exp: u64, + is_zero: bool, +} + +impl A100Product { + fn new(code_a: u16, code_b: u16) -> Self { + let (sig_a, sign_a, eps_a, zero_a) = fp16_decode_fields(code_a); + let (sig_b, sign_b, eps_b, zero_b) = fp16_decode_fields(code_b); + let (is_zero_a, is_zero_b) = (zero_a == 1, zero_b == 1); + let is_zero = is_zero_a || is_zero_b; + A100Product { + sig_a, + sig_b, + sign_a: sign_a == 1, + sign_b: sign_b == 1, + eps_a, + eps_b, + is_zero_a, + is_zero_b, + product_sig: sig_a * sig_b, + sign: (sign_a == 1) != (sign_b == 1), + // (eps_a+eps_b+97) = (ea+15)+(eb+15)+97 = ea+eb+127; gated to 0 on zero lanes. + biased_exp: if is_zero { 0 } else { eps_a + eps_b + 97 }, + is_zero, + } + } +} + +/// A group output / the carry entering the next row: `value = sign * cm * 2^(el-23)` +/// with `el = biased_exp - 127`. Mirrors `acc_parts` of the oracle. +#[derive(Clone, Copy, Debug)] +struct Carry { + sign: bool, + /// 24-bit significand (normal), subnormal mantissa, or 0. + cm: u64, + /// `el + 127` (= the FP32 exponent field); 0 for a zero carry. + biased_exp: u64, + is_zero: bool, + is_subnormal: bool, +} + +impl Carry { + const ZERO: Self = Self { sign: false, cm: 0, biased_exp: 0, is_zero: true, is_subnormal: false }; + + /// Decomposes an incoming FP32 accumulator (the oracle's `acc_parts`). + fn from_f32(c: f32) -> Self { + debug_assert!(c.is_finite()); + if c == 0.0 { + return Self::ZERO; + } + let bits = c.to_bits(); + let sign = c.is_sign_negative(); + let exp_field = (bits >> 23) & 0xFF; + let man = (bits & 0x7F_FFFF) as u64; + if exp_field > 0 { + Self { sign, cm: 0x80_0000 | man, biased_exp: exp_field as u64, is_zero: false, is_subnormal: false } + } else { + // Subnormal: el clamped to -126 -> biased_exp 1, cm = mantissa. + Self { sign, cm: man, biased_exp: 1, is_zero: false, is_subnormal: true } + } + } + + /// The exact FP32 bit pattern of this carry. + fn to_f32_bits(self) -> u64 { + if self.cm == 0 { + return 0; + } + if self.is_subnormal { + return ((self.sign as u64) << 31) | self.cm; + } + ((self.sign as u64) << 31) | (self.biased_exp << 23) | (self.cm - SIG24_MIN) + } +} + +fn bit_length(x: u64) -> u64 { + (64 - x.leading_zeros()) as u64 +} + +// ================================================================================================== +// Trace generation +// ================================================================================================== + +impl, const D: usize> MatmulStarkA100 { + /// Generates the trace: `a_codes` row-major (`h*k`), `b_codes` row-major over + /// the transposed B (`w*k`), optional `m*n` FP32 carry-in. Cells row-major, one + /// row per `G = 8` group step. The committed cell results match + /// [`crate::api::fp16::accumulate::a100_matmul`] bit-for-bit. + pub fn generate_trace( + &self, + a_codes: &[u16], + b_codes: &[u16], + acc: Option<&[f32]>, + ) -> Vec<[F; NUM_MATMUL_A100_COLUMNS]> { + let (h, w, k) = (self.h, self.w, self.k); + assert_eq!(a_codes.len(), h * k, "a_codes must be h*k FP16 codes"); + assert_eq!(b_codes.len(), w * k, "b_codes must be w*k FP16 codes"); + let rpc = self.rows_per_cell(); + let num_rows = self.num_rows(); + let mut rows: Vec<[F; NUM_MATMUL_A100_COLUMNS]> = Vec::with_capacity(num_rows); + + for r in 0..h { + for c in 0..w { + let cell_id = r * w + c; + let mut carry = Carry::from_f32(acc.map_or(0.0, |a| a[r * w + c])); + let mut incoming_carry_is_zero = carry.is_zero; + let cell_start = rows.len(); + let mut cell_pt = 0u64; + let mut cell_bp = 0u64; + + for j in 0..rpc { + let is_final = j == rpc - 1; + let mut row = MatmulA100ColumnsView:: { + cell_id: F::from_canonical_usize(cell_id), + is_cell_final: F::from_bool(is_final), + operand_index_base_a: F::from_canonical_usize(r * k + j * GROUP), + operand_index_base_b: F::from_canonical_usize(h * k + c * k + j * GROUP), + incoming_carry_is_zero: F::from_bool(incoming_carry_is_zero), + ..Default::default() + }; + + // Decode the 8 lanes. + let mut lanes = [A100Product::new(0, 0); GROUP]; + for i in 0..GROUP { + let ca = a_codes[r * k + j * GROUP + i]; + let cb = b_codes[c * k + j * GROUP + i]; + lanes[i] = A100Product::new(ca, cb); + row.operand_codes_a[i] = F::from_canonical_u16(ca); + row.operand_codes_b[i] = F::from_canonical_u16(cb); + row.sig_a[i] = F::from_canonical_u64(lanes[i].sig_a); + row.sig_b[i] = F::from_canonical_u64(lanes[i].sig_b); + row.sign_a[i] = F::from_bool(lanes[i].sign_a); + row.sign_b[i] = F::from_bool(lanes[i].sign_b); + row.eps_a[i] = F::from_canonical_u64(lanes[i].eps_a); + row.eps_b[i] = F::from_canonical_u64(lanes[i].eps_b); + row.is_zero_a[i] = F::from_bool(lanes[i].is_zero_a); + row.is_zero_b[i] = F::from_bool(lanes[i].is_zero_b); + row.lane_sign[i] = F::from_bool(lanes[i].sign); + row.product_biased_exp[i] = F::from_canonical_u64(lanes[i].biased_exp); + row.product_sig[i] = F::from_canonical_u64(lanes[i].product_sig); + } + + // Window anchor eta (biased): max over nonzero products and the carry. + let mut eta: u64 = if incoming_carry_is_zero { 0 } else { carry.biased_exp }; + for lane in &lanes { + if !lane.is_zero { + eta = eta.max(lane.biased_exp); + } + } + row.group_max_biased_exponent = F::from_canonical_u64(eta); + let nonempty = eta != 0; + row.group_nonempty = F::from_bool(nonempty); + row.group_max_inv = if eta == 0 { F::ZERO } else { F::from_canonical_u64(eta).inverse() }; + + // Attainment chain over the 8 lane factors. + let factor = |i: usize| F::from_canonical_u64(eta) - row.product_biased_exp[i]; + row.max_exponent_attainment[0] = factor(0) * factor(1) * factor(2); + row.max_exponent_attainment[1] = row.max_exponent_attainment[0] * factor(3) * factor(4); + row.max_exponent_attainment[2] = row.max_exponent_attainment[1] * factor(5) * factor(6); + row.max_exponent_attainment[3] = row.max_exponent_attainment[2] * factor(7); + + // Align + sum the 8 products. + let mut sum: i64 = 0; + for i in 0..GROUP { + if lanes[i].is_zero { + // Zero lane: honest shift power keeps the Euclidean identity 0 = 0. + let rel = eta.saturating_sub(lanes[i].biased_exp).min(SHIFT_CAP); + row.lane_shift_power[i] = F::from_canonical_u64(1 << rel); + row.lane_rem_bound[i] = F::from_canonical_u64((1 << rel) - 1); + continue; + } + let rel = (eta - lanes[i].biased_exp).min(SHIFT_CAP); + let sp = 1u64 << rel; + let p16 = lanes[i].product_sig * 16; + let aligned = p16 / sp; + let rem = p16 - aligned * sp; + row.lane_shift_power[i] = F::from_canonical_u64(sp); + row.aligned_mag[i] = F::from_canonical_u64(aligned); + row.lane_rem[i] = F::from_canonical_u64(rem); + row.lane_rem_bound[i] = F::from_canonical_u64(sp - 1 - rem); + let truncated = rem != 0; + row.products_truncated_flag[i] = F::from_bool(truncated); + if truncated { + row.lane_rem_inv[i] = F::from_canonical_u64(rem).inverse(); + } + cell_pt += u64::from(truncated); + sum += if lanes[i].sign { -(aligned as i64) } else { aligned as i64 }; + } + + // Align + add the carry. + let mut carry_dropped = false; + if incoming_carry_is_zero { + row.carry_shift_power = F::ONE; // inert; remainder identity picks (0,0,1). + } else { + let rel = (eta - carry.biased_exp).min(SHIFT_CAP); + let sp = 1u64 << rel; + let two_cm = 2 * carry.cm; + let aligned = two_cm / sp; + let rem = two_cm - aligned * sp; + row.carry_shift_power = F::from_canonical_u64(sp); + row.aligned_carry = F::from_canonical_u64(aligned); + row.carry_rem = F::from_canonical_u64(rem); + row.carry_rem_bound = F::from_canonical_u64(sp - 1 - rem); + carry_dropped = rem != 0; + if carry_dropped { + row.carry_rem_inv = F::from_canonical_u64(rem).inverse(); + } + sum += if carry.sign { -(aligned as i64) } else { aligned as i64 }; + } + row.carry_dropped = F::from_bool(carry_dropped); + + // Signed sum + round toward zero to FP32. + row.group_sum_sign = F::from_bool(sum < 0); + row.group_sum_abs = F::from_canonical_u64(sum.unsigned_abs()); + row.group_sum_is_zero = F::from_bool(sum == 0); + debug_assert!(sum.unsigned_abs() < 1 << 30, "window sums fit 30 bits"); + + let mut rz_dropped = false; + let out = if sum == 0 { + row.truncation_power = F::ONE; + row.lifting_power = F::ONE; + row.sub_shift_power = F::ONE; + Carry::ZERO + } else { + let mag = sum.unsigned_abs(); + let width = bit_length(mag); + let tp = 1u64 << width.saturating_sub(W); + let lp = 1u64 << W.saturating_sub(width); + let norm_sig = mag * lp / tp; + let trunc_rem = mag * lp - norm_sig * tp; + row.group_sum_width = F::from_canonical_u64(width); + row.truncation_power = F::from_canonical_u64(tp); + row.lifting_power = F::from_canonical_u64(lp); + row.norm_sig = F::from_canonical_u64(norm_sig); + row.trunc_rem = F::from_canonical_u64(trunc_rem); + row.trunc_rem_bound = F::from_canonical_u64(tp - 1 - trunc_rem); + if trunc_rem != 0 { + row.trunc_rem_inv = F::from_canonical_u64(trunc_rem).inverse(); + rz_dropped = true; + } + // `raw` is the normal-path FP32 biased exponent `eta + W - 25`. When it is + // `>= 1` the output is a normal FP32; when it is `<= 0` the output is an + // FP32 subnormal (`|x| < 2^-126`), encoded on the `2^-149` grid with + // exponent field 0 and a `< 2^23` mantissa = `NORM_SIG >> k`, `k = 1 - raw` + // (MA13). The from-zero datapath never takes the subnormal branch (FP16 + // products align at `eta >= 99`, so a group output floors at `~2^-52`); it + // is reached only by a subnormal carry-in (the accumulation datapath the + // oracle `a100_dot` models). `exp_slack` is the nonnegative flag witness. + let raw = eta as i64 + width as i64 - OUT_EXP_OFFSET as i64; + if raw >= 1 { + let out_biased_exp = raw as u64; + row.exp_slack = F::from_canonical_u64(out_biased_exp - 1); + row.sub_shift_power = F::ONE; + Carry { sign: sum < 0, cm: norm_sig, biased_exp: out_biased_exp, is_zero: false, is_subnormal: false } + } else { + let k = (1 - raw) as u64; // = 26 - eta - width >= 1 + let sub_shift_power = 1u64 << k; + let mantissa = norm_sig / sub_shift_power; + debug_assert_eq!(norm_sig % sub_shift_power, 0, "a reachable subnormal keeps whole NORM_SIG bits"); + debug_assert!(mantissa < SIG24_MIN, "a subnormal mantissa fits 23 bits"); + row.out_is_subnormal = F::ONE; + row.exp_slack = F::from_canonical_u64(k - 1); // = -raw + row.sub_shift_exp = F::from_canonical_u64(k); + row.sub_shift_power = F::from_canonical_u64(sub_shift_power); + (row.out_sig_lo, row.out_sig_hi) = split_limbs(F::from_canonical_u64(mantissa)); + Carry { sign: sum < 0, cm: mantissa, biased_exp: 0, is_zero: mantissa == 0, is_subnormal: true } + } + }; + row.rz_dropped = F::from_bool(rz_dropped); + let breakpoint = nonempty && (carry_dropped || rz_dropped); + row.out_sign = F::from_bool(out.sign); + row.out_biased_exp = F::from_canonical_u64(out.biased_exp); + row.out_sig = F::from_canonical_u64(out.cm); + row.group_breakpoint = F::from_bool(breakpoint); + cell_bp += u64::from(breakpoint); + row.cell_products_truncated = F::from_canonical_u64(cell_pt); + row.cell_breakpoints = F::from_canonical_u64(cell_bp); + + if is_final { + let bits = out.to_f32_bits(); + row.cell_result_f32_lo = F::from_canonical_u64(bits & 0xFFFF); + row.cell_result_f32_hi = F::from_canonical_u64(bits >> 16); + } + + incoming_carry_is_zero = sum == 0; + carry = out; + fill_limbs(&mut row); + rows.push(row.into()); + } + let _ = cell_start; + } + } + + for t in 0..num_rows - self.live_rows() { + rows.push(phantom_row::(h * w + t).into()); + } + rows + } +} + +/// An all-zero single-row trailing phantom cell. +fn phantom_row(cell_id: usize) -> MatmulA100ColumnsView { + let mut row = MatmulA100ColumnsView:: { + cell_id: F::from_canonical_usize(cell_id), + is_cell_final: F::ONE, + is_padding: F::ONE, + incoming_carry_is_zero: F::ONE, + carry_shift_power: F::ONE, + group_sum_is_zero: F::ONE, + truncation_power: F::ONE, + lifting_power: F::ONE, + ..Default::default() + }; + for i in 0..GROUP { + row.lane_shift_power[i] = F::ONE; + // Phantom lanes read operand code 0, which FP16DECODE serves as (0, 0, 15, 1): both + // operands are zero, so the product sentinel stays 0 and MA1's derivation holds. + row.is_zero_a[i] = F::ONE; + row.is_zero_b[i] = F::ONE; + row.eps_a[i] = F::from_canonical_u64(15); + row.eps_b[i] = F::from_canonical_u64(15); + } + fill_limbs(&mut row); + row +} + +/// `(value & 0xFFFF, value >> 16)` of a canonical field integer — the `(lo, hi)` limbs MA12 +/// reconstructs and RANGE16-checks. +fn split_limbs(value: F) -> (F, F) { + let v = value.to_canonical_u64(); + (F::from_canonical_u64(v & 0xFFFF), F::from_canonical_u64(v >> 16)) +} + +/// Fills every MA12 limb column from the corresponding Euclidean-floor witness column, so the +/// reconstruction constraints hold on every row (live, zero-lane, and phantom). +fn fill_limbs(row: &mut MatmulA100ColumnsView) { + for i in 0..GROUP { + (row.aligned_mag_lo[i], row.aligned_mag_hi[i]) = split_limbs(row.aligned_mag[i]); + (row.lane_rem_lo[i], row.lane_rem_hi[i]) = split_limbs(row.lane_rem[i]); + (row.lane_rem_bound_lo[i], row.lane_rem_bound_hi[i]) = split_limbs(row.lane_rem_bound[i]); + } + (row.aligned_carry_lo, row.aligned_carry_hi) = split_limbs(row.aligned_carry); + (row.carry_rem_lo, row.carry_rem_hi) = split_limbs(row.carry_rem); + (row.carry_rem_bound_lo, row.carry_rem_bound_hi) = split_limbs(row.carry_rem_bound); + (row.norm_sig_lo, row.norm_sig_hi) = split_limbs(row.norm_sig); +} + +// ================================================================================================== +// Constraints +// ================================================================================================== + +/// `1 - 2*bit`. +fn double_complement>(eval: &mut E, one: V, bit: V) -> V { + let twice = eval.add(bit, bit); + eval.sub(one, twice) +} + +/// Evaluates every arithmetic constraint of `MatmulStarkA100` (degree <= 3). LUT +/// facts (decode, POW2, WIDTH, range) are not emitted here; see the module docs. +pub(crate) fn eval_matmul_a100_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_MATMUL_A100_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &MatmulA100ColumnsView = lv.borrow(); + let nv: &[V; NUM_MATMUL_A100_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let nv: &MatmulA100ColumnsView = nv.borrow(); + + let one = eval.i32(1); + let not_final = eval.sub(one, lv.is_cell_final); + let z = lv.group_sum_is_zero; + let one_minus_z = eval.sub(one, z); + let limb_shift = eval.u64(1 << 16); + + eval.constraint_bool(lv.is_padding); + + // ---- MA1 — product significand + decode derivations + per-lane booleans. The decoded + // per-operand fields (`sig_*`, `sign_*`, `eps_*`, `is_zero_*`) are FP16DECODE LUT outputs + // CTL-bound to the operand codes (see `super::ctl`); here they are turned into the lane's + // product significand, sign, and biased stored exponent, so a prover cannot forge the sign + // or exponent a code decodes to. ---- + for i in 0..GROUP { + // product_sig = sig_a * sig_b. + let prod = eval.mul(lv.sig_a[i], lv.sig_b[i]); + let c = eval.sub(lv.product_sig[i], prod); + eval.constraint(c); + eval.constraint_bool(lv.sign_a[i]); + eval.constraint_bool(lv.sign_b[i]); + eval.constraint_bool(lv.is_zero_a[i]); + eval.constraint_bool(lv.is_zero_b[i]); + eval.constraint_bool(lv.lane_sign[i]); + eval.constraint_bool(lv.products_truncated_flag[i]); + // lane_sign = sign_a XOR sign_b = sign_a + sign_b - 2*sign_a*sign_b. + let sasb = eval.mul(lv.sign_a[i], lv.sign_b[i]); + let two_sasb = eval.add(sasb, sasb); + let xor = eval.add(lv.sign_a[i], lv.sign_b[i]); + let xor = eval.sub(xor, two_sasb); + let c = eval.sub(lv.lane_sign[i], xor); + eval.constraint(c); + // product_biased_exp = (1-is_zero_a)*(1-is_zero_b) * (eps_a + eps_b + 97), the + // zero-sentinel being the all-or-either-zero case (padding reads code 0 => is_zero, + // so this subsumes the old padding pin). 97 = 127 - 2*15 re-biases eps+15 twins to f32. + let ninety_seven = eval.i32(97); + let eps_sum = eval.add(lv.eps_a[i], lv.eps_b[i]); + let eps_sum = eval.add(eps_sum, ninety_seven); + let nz_a = eval.sub(one, lv.is_zero_a[i]); + let nz_b = eval.sub(one, lv.is_zero_b[i]); + let nz = eval.mul(nz_a, nz_b); + let expect = eval.mul(nz, eps_sum); + let c = eval.sub(lv.product_biased_exp[i], expect); + eval.constraint(c); + } + + // ---- MA2 — eta attainment (the "<=" side of the max; ">=" is the POW2 key + // domain). Links are local; the closing (reading the next row as the carry's + // consumer) multiplies in the zero-gated carry factor and demands the product + // vanish. ---- + let factor = |eval: &mut E, view: &MatmulA100ColumnsView, i: usize| { + eval.sub(view.group_max_biased_exponent, view.product_biased_exp[i]) + }; + let f0 = factor(eval, lv, 0); + let f1 = factor(eval, lv, 1); + let f2 = factor(eval, lv, 2); + let f01 = eval.mul(f0, f1); + let link = eval.msub(f01, f2, lv.max_exponent_attainment[0]); + eval.constraint(link); + for l in 1..NUM_ATT_LINKS - 1 { + let fa = factor(eval, lv, 2 * l + 1); + let fb = factor(eval, lv, 2 * l + 2); + let fab = eval.mul(fa, fb); + let link = eval.msub(lv.max_exponent_attainment[l - 1], fab, lv.max_exponent_attainment[l]); + eval.constraint(link); + } + let f_last = factor(eval, lv, GROUP - 1); + let link = eval.msub(lv.max_exponent_attainment[NUM_ATT_LINKS - 2], f_last, lv.max_exponent_attainment[NUM_ATT_LINKS - 1]); + eval.constraint(link); + // Closing: the next row's chain tail times its zero-gated carry factor vanishes. + let carry_is_live = eval.sub(one, nv.incoming_carry_is_zero); + let carry_gap = eval.sub(nv.group_max_biased_exponent, lv.out_biased_exp); + let carry_factor = eval.mul(carry_is_live, carry_gap); + let carry_factor = eval.add(carry_factor, nv.incoming_carry_is_zero); + let closing = eval.mul(nv.max_exponent_attainment[NUM_ATT_LINKS - 1], carry_factor); + eval.constraint(closing); + + // group_nonempty = [GROUP_MAX_BIASED_EXPONENT != 0]. + eval.constraint_bool(lv.group_nonempty); + let prod = eval.mul(lv.group_max_biased_exponent, lv.group_max_inv); + let c = eval.sub(prod, lv.group_nonempty); + eval.constraint(c); + let not_nonempty = eval.sub(one, lv.group_nonempty); + let c = eval.mul(not_nonempty, lv.group_max_biased_exponent); + eval.constraint(c); + + // ---- MA3 — per-lane Euclidean truncation (local). ---- + for i in 0..GROUP { + let sixteen = eval.i32(16); + let p16 = eval.mul(sixteen, lv.product_sig[i]); + let shifted = eval.mul(lv.aligned_mag[i], lv.lane_shift_power[i]); + let floor_diff = eval.sub(p16, shifted); + let floor_diff = eval.sub(floor_diff, lv.lane_rem[i]); + eval.constraint(floor_diff); + let rem_sum = eval.add(lv.lane_rem[i], lv.lane_rem_bound[i]); + let rem_sum = eval.add(rem_sum, one); + let rem_id = eval.sub(rem_sum, lv.lane_shift_power[i]); + eval.constraint(rem_id); + // Census (clean direction): a non-truncated lane has zero remainder. + let not_trunc = eval.sub(one, lv.products_truncated_flag[i]); + let c = eval.mul(not_trunc, lv.lane_rem[i]); + eval.constraint(c); + // Census (tight direction): a truncated lane has nonzero remainder, pinned by + // the inverse witness (`flag * (rem*inv - 1) = 0`). Together with the clean + // direction this makes `products_truncated_flag == [LANE_REM != 0]` exactly, so + // the per-lane census cannot be inflated to overstate certified work. + let rem_inv = eval.mul(lv.lane_rem[i], lv.lane_rem_inv[i]); + let rem_inv_m1 = eval.sub(rem_inv, one); + let c = eval.mul(lv.products_truncated_flag[i], rem_inv_m1); + eval.constraint(c); + } + + // ---- MA4 — carry alignment (anchored at the producing row; reads next row). ---- + let carry_is_nonzero_next = eval.sub(one, nv.incoming_carry_is_zero); + let two = eval.i32(2); + let two_sig = eval.mul(two, lv.out_sig); + let shifted = eval.mul(nv.aligned_carry, nv.carry_shift_power); + let floor_diff = eval.sub(two_sig, shifted); + let floor_diff = eval.sub(floor_diff, nv.carry_rem); + let c = eval.mul(carry_is_nonzero_next, floor_diff); + eval.constraint(c); + // Unfiltered remainder identity (local). + let rem_sum = eval.add(lv.carry_rem, lv.carry_rem_bound); + let rem_sum = eval.add(rem_sum, one); + let rem_id = eval.sub(rem_sum, lv.carry_shift_power); + eval.constraint(rem_id); + // Zero carries contribute nothing (kills the stale value, incl. the cyclic wrap). + let kill = eval.mul(lv.incoming_carry_is_zero, lv.aligned_carry); + eval.constraint(kill); + + // ---- MA5 — signed window sum (anchored at the producing row). ---- + let mut terms: Vec = Vec::with_capacity(GROUP); + for i in 0..GROUP { + let sign_factor = double_complement(eval, one, nv.lane_sign[i]); + terms.push(eval.mul(sign_factor, nv.aligned_mag[i])); + } + let terms_sum = eval.sum(&terms); + let carry_sign_factor = double_complement(eval, one, lv.out_sign); + let signed_carry = eval.mul(carry_sign_factor, nv.aligned_carry); + let bracket = eval.add(terms_sum, signed_carry); + let group_sum_sign_factor = double_complement(eval, one, nv.group_sum_sign); + let recovered = eval.mul(group_sum_sign_factor, bracket); + let sum_eq = eval.sub(nv.group_sum_abs, recovered); + eval.constraint(sum_eq); + eval.constraint_bool(lv.group_sum_sign); + eval.constraint_bool(lv.group_sum_is_zero); + let ban = eval.mul(lv.group_sum_is_zero, lv.group_sum_abs); + eval.constraint(ban); + let plus_zero = eval.mul(lv.group_sum_is_zero, lv.group_sum_sign); + eval.constraint(plus_zero); + + // ---- MA6 — carry-zero flag propagation. ---- + let diff = eval.sub(nv.incoming_carry_is_zero, z); + let c = eval.mul(not_final, diff); + eval.constraint(c); + let reset = eval.sub(nv.incoming_carry_is_zero, one); + let c = eval.mul(lv.is_cell_final, reset); + eval.constraint(c); + let first_anchor = eval.sub(lv.incoming_carry_is_zero, one); + eval.constraint_first_row(first_anchor); + + // ---- MA7 — width + round toward zero (local, filter 1 - z). ---- + let lifted = eval.mul(lv.group_sum_abs, lv.lifting_power); + let truncated = eval.mul(lv.norm_sig, lv.truncation_power); + let width_diff = eval.sub(lifted, truncated); + let width_diff = eval.sub(width_diff, lv.trunc_rem); + let c = eval.mul(one_minus_z, width_diff); + eval.constraint(c); + let rem_sum = eval.add(lv.trunc_rem, lv.trunc_rem_bound); + let rem_sum = eval.add(rem_sum, one); + let rem_id = eval.sub(rem_sum, lv.truncation_power); + let c = eval.mul(one_minus_z, rem_id); + eval.constraint(c); + + // ---- MA8 — output mux (normal path / subnormal path / +0 path; MA13 pins the flag). ---- + let f = lv.out_is_subnormal; + let one_minus_f = eval.sub(one, f); + let offset = eval.u64(OUT_EXP_OFFSET); + let raw_exp = eval.add(lv.group_max_biased_exponent, lv.group_sum_width); + let raw_exp = eval.sub(raw_exp, offset); + // The normal path exports the biased exponent `raw_exp`; the subnormal path exports + // exponent field 0 (MA13 pins the mantissa). `+0` path (z) exports 0. + let normal_exp = eval.mul(one_minus_f, raw_exp); + let exp_diff = eval.sub(lv.out_biased_exp, normal_exp); + let c = eval.mul(one_minus_z, exp_diff); + eval.constraint(c); + // Normal path: OUT_SIG = NORM_SIG. (The subnormal OUT_SIG is pinned by MA13.) + let sig_diff = eval.sub(lv.out_sig, lv.norm_sig); + let sig_diff = eval.mul(one_minus_f, sig_diff); + let c = eval.mul(one_minus_z, sig_diff); + eval.constraint(c); + let sign_diff = eval.sub(lv.out_sign, lv.group_sum_sign); + let c = eval.mul(one_minus_z, sign_diff); + eval.constraint(c); + let c = eval.mul(z, lv.out_biased_exp); + eval.constraint(c); + let c = eval.mul(z, lv.out_sig); + eval.constraint(c); + let c = eval.mul(z, lv.out_sign); + eval.constraint(c); + + // ---- MA9 — FP32 encode at cell-final. ---- + // W := LO + 2^16*HI = OUT_SIGN*2^31 + OUT_BIASED_EXP*2^23 + (OUT_SIG - 2^23*(1-z)*(1-f)). + // The implicit leading `2^23` is subtracted only on the NORMAL nonzero path; a subnormal + // output (`f = 1`, exponent field 0) stores OUT_SIG directly as the 23-bit mantissa field. + let word = eval.mad(lv.cell_result_f32_hi, limb_shift, lv.cell_result_f32_lo); + let c2_31 = eval.u64(1 << 31); + let sign_term = eval.mul(lv.out_sign, c2_31); + let c2_23 = eval.u64(1 << 23); + let exp_term = eval.mul(lv.out_biased_exp, c2_23); + let residue = eval.mul(c2_23, one_minus_z); + let residue = eval.mul(residue, one_minus_f); + let encode = eval.sub(word, sign_term); + let encode = eval.sub(encode, exp_term); + let encode = eval.sub(encode, lv.out_sig); + let encode = eval.add(encode, residue); + let c = eval.mul(lv.is_cell_final, encode); + eval.constraint(c); + + // ---- MA13 — subnormal FP32-output RZ branch (the `2^-149`-grid encode). An output whose + // normal biased exponent `raw = GROUP_MAX_BIASED_EXPONENT + W - 25` is `<= 0` is an FP32 + // subnormal: exponent field 0 (MA8), mantissa `OUT_SIG = NORM_SIG >> k`, `k = 1 - raw`. The + // `exp_slack` RANGE16 witness pins the flag to `[raw <= 0]` exactly — `raw - 1 >= 0` on the + // normal path, `-raw >= 0` on the subnormal path — so neither over- nor under-claiming the + // subnormal regime has a valid witness. (The from-zero matmul never takes this branch; it is + // a sound guard plus the bit-exact encode for the subnormal carry-in the oracle models.) ---- + eval.constraint_bool(lv.out_is_subnormal); + // A zero-sum output is `+0`, never subnormal; its slack is pinned to 0. + let c = eval.mul(z, lv.out_is_subnormal); + eval.constraint(c); + let c = eval.mul(z, lv.exp_slack); + eval.constraint(c); + // Flag witness (nonzero-sum rows): exp_slack = (1-f)*(raw-1) + f*(-raw) = (raw-1) - f*(2*raw-1). + let raw_minus_one = eval.sub(raw_exp, one); + let two_raw = eval.add(raw_exp, raw_exp); + let two_raw_minus_one = eval.sub(two_raw, one); + let f_term = eval.mul(f, two_raw_minus_one); + let slack_expected = eval.sub(raw_minus_one, f_term); + let slack_diff = eval.sub(lv.exp_slack, slack_expected); + let c = eval.mul(one_minus_z, slack_diff); + eval.constraint(c); + // Subnormal shift exponent `k = 1 - raw = exp_slack + 1` (pinned only on subnormal rows; + // it is the FP16POW2 key for SUB_SHIFT_POWER = 2^k, which the committed LUT CTL binds). + let k_expected = eval.add(lv.exp_slack, one); + let k_diff = eval.sub(lv.sub_shift_exp, k_expected); + let c = eval.mul(f, k_diff); + eval.constraint(c); + // Subnormal mantissa (exact division): NORM_SIG = OUT_SIG * SUB_SHIFT_POWER. OUT_SIG is + // reconstructed from its RANGE16 limbs, so it is a genuine integer; with NORM_SIG < 2^24 (the + // normalized-range pin in this AIR's `ctl.rs`, active on these nonzero-sum rows) and + // SUB_SHIFT_POWER = 2^k >= 2 this forces OUT_SIG < 2^23 — a valid subnormal mantissa field. + let scaled = eval.mul(lv.out_sig, lv.sub_shift_power); + let div_diff = eval.sub(lv.norm_sig, scaled); + let c = eval.mul(f, div_diff); + eval.constraint(c); + let combined = eval.mad(lv.out_sig_hi, limb_shift, lv.out_sig_lo); + let recon_diff = eval.sub(lv.out_sig, combined); + let c = eval.mul(f, recon_diff); + eval.constraint(c); + + // ---- MA10 — census booleans + in-cell running counts. ---- + eval.constraint_bool(lv.group_breakpoint); + // products-truncated running count. + let flags_sum = eval.sum(&lv.products_truncated_flag); + let anchor = eval.sub(lv.cell_products_truncated, flags_sum); + eval.constraint_first_row(anchor); + let flags_sum_next = eval.sum(&nv.products_truncated_flag); + let reset_diff = eval.sub(nv.cell_products_truncated, flags_sum_next); + let c = eval.mul(lv.is_cell_final, reset_diff); + eval.constraint(c); + let kept = eval.add(lv.cell_products_truncated, flags_sum_next); + let step_diff = eval.sub(nv.cell_products_truncated, kept); + let c = eval.mul(not_final, step_diff); + eval.constraint(c); + // breakpoints running count. + let anchor = eval.sub(lv.cell_breakpoints, lv.group_breakpoint); + eval.constraint_first_row(anchor); + let reset_diff = eval.sub(nv.cell_breakpoints, nv.group_breakpoint); + let c = eval.mul(lv.is_cell_final, reset_diff); + eval.constraint(c); + let kept = eval.add(lv.cell_breakpoints, nv.group_breakpoint); + let step_diff = eval.sub(nv.cell_breakpoints, kept); + let c = eval.mul(not_final, step_diff); + eval.constraint(c); + + // ---- MA11 — tight breakpoint census. `group_breakpoint` is the one census input + // that INCREASES certified work (rho), so it is pinned bit-exactly to the + // `a100_dot` definition `nonempty && (acc_truncated || rz_dropped)`: an attacker can + // neither over- nor under-state it. + // + // `carry_dropped` and `rz_dropped` each equal `[rem != 0]` of their Euclidean + // remainder — clean direction `(1-flag)*rem = 0`, tight direction + // `flag*(rem*inv - 1) = 0` — and the stale remainders of the inert branches are + // forced to zero (`incoming_carry_is_zero*carry_rem = 0`, `z*trunc_rem = 0`) so the + // flags cannot latch onto an unconstrained witness on a zero-carry / zero-sum row. ---- + eval.constraint_bool(lv.carry_dropped); + eval.constraint_bool(lv.rz_dropped); + // carry_dropped == [carry_rem != 0], with the zero-carry remainder pinned to 0. + let kill = eval.mul(lv.incoming_carry_is_zero, lv.carry_rem); + eval.constraint(kill); + let not_cd = eval.sub(one, lv.carry_dropped); + let c = eval.mul(not_cd, lv.carry_rem); + eval.constraint(c); + let cd_inv = eval.mul(lv.carry_rem, lv.carry_rem_inv); + let cd_inv_m1 = eval.sub(cd_inv, one); + let c = eval.mul(lv.carry_dropped, cd_inv_m1); + eval.constraint(c); + // rz_dropped == [trunc_rem != 0], with the zero-sum remainder pinned to 0. + let kill = eval.mul(z, lv.trunc_rem); + eval.constraint(kill); + let not_rz = eval.sub(one, lv.rz_dropped); + let c = eval.mul(not_rz, lv.trunc_rem); + eval.constraint(c); + let rz_inv = eval.mul(lv.trunc_rem, lv.trunc_rem_inv); + let rz_inv_m1 = eval.sub(rz_inv, one); + let c = eval.mul(lv.rz_dropped, rz_inv_m1); + eval.constraint(c); + // group_breakpoint == nonempty * (carry_dropped OR rz_dropped). + let cd_rz = eval.mul(lv.carry_dropped, lv.rz_dropped); + let or_drop = eval.add(lv.carry_dropped, lv.rz_dropped); + let or_drop = eval.sub(or_drop, cd_rz); + let bp = eval.mul(lv.group_nonempty, or_drop); + let c = eval.sub(lv.group_breakpoint, bp); + eval.constraint(c); + + // ---- MA12 — limb reconstruction of the Euclidean-floor witnesses. Each tracked magnitude + // equals `lo + 2^16 * hi`; `lo` and `2^6 * hi` are RANGE16-checked by the committed-LUT CTLs + // (see `super::ctl`), so `lo < 2^16` and `hi < 2^10`, i.e. the magnitude is a genuine integer + // `< 2^26`. This is what makes the MA3/MA4/MA7 `floor` identities exact against field-fraction + // aliasing under a real FRI proof: a wrapped quotient/remainder has no valid 16/10-bit limb + // witness, so no field element `q >= 2^26` can satisfy `q * shift_power + r = N` here. ---- + let reconstruct = |eval: &mut E, value: V, lo: V, hi: V| { + let combined = eval.mad(hi, limb_shift, lo); + let c = eval.sub(value, combined); + eval.constraint(c); + }; + for i in 0..GROUP { + reconstruct(eval, lv.aligned_mag[i], lv.aligned_mag_lo[i], lv.aligned_mag_hi[i]); + reconstruct(eval, lv.lane_rem[i], lv.lane_rem_lo[i], lv.lane_rem_hi[i]); + reconstruct(eval, lv.lane_rem_bound[i], lv.lane_rem_bound_lo[i], lv.lane_rem_bound_hi[i]); + } + reconstruct(eval, lv.aligned_carry, lv.aligned_carry_lo, lv.aligned_carry_hi); + reconstruct(eval, lv.carry_rem, lv.carry_rem_lo, lv.carry_rem_hi); + reconstruct(eval, lv.carry_rem_bound, lv.carry_rem_bound_lo, lv.carry_rem_bound_hi); + reconstruct(eval, lv.norm_sig, lv.norm_sig_lo, lv.norm_sig_hi); +} + +// ================================================================================================== +// Stark impl +// ================================================================================================== + +impl, const D: usize> Stark for MatmulStarkA100 { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_MATMUL_A100_COLUMNS, NUM_MATMUL_A100_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_matmul_a100_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_matmul_a100_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + /// The matmul AIR is a looking side of the FP16 batch's committed-LUT and census-import CTLs. + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::PrimeField64; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + + use super::*; + use crate::api::fp16::accumulate::{a100_dot, a100_matmul}; + use crate::api::fp16::dtype::f32_to_fp16; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type S = MatmulStarkA100; + + const VECTORS: &str = include_str!("../../../api/fp16/testdata/a100_dot_vectors.txt"); + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + /// A pool of finite FP16 codes spanning normals (both signs) and a subnormal, + /// giving mixed product exponents and alignment depths. + fn pool() -> Vec { + [1.0f32, -1.0, 2.0, -0.5, 3.5, -4.25, 0.125, 17.0, -0.03125, 256.0] + .into_iter() + .map(|x| f32_to_fp16(x).unwrap()) + .collect() + } + + fn codes(len: usize, salt: u64, zero_every: usize) -> Vec { + let p = pool(); + (0..len) + .map(|i| { + if zero_every != 0 && i % zero_every == 0 { + 0u16 + } else { + p[((i as u64).wrapping_mul(salt) ^ (i as u64 >> 3)) as usize % p.len()] + } + }) + .collect() + } + + fn assert_all_constraints(stark: &S, rows: &[[F; NUM_MATMUL_A100_COLUMNS]]) { + let n = rows.len(); + for i in 0..n { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::ONE, + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + for acc in consumer.accumulators() { + assert_eq!(acc, F::ZERO, "constraints do not vanish on row {i}"); + } + } + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + let program = S::new(4, 4, 64); + let a = codes(program.h * program.k, 0x9E3779B97F4A7C15, 7); + let b = codes(program.w * program.k, 0xC2B2AE3D27D4EB4F, 11); + let rows = program.generate_trace(&a, &b, None); + assert_all_constraints(&program, &rows); + } + + #[test] + fn trace_results_are_bit_exact_vs_oracle_matmul() { + for (h, w, k, sa, sb, za, zb) in [ + (4usize, 4usize, 64usize, 0x9E3779B97F4A7C15u64, 0xC2B2AE3D27D4EB4Fu64, 7usize, 11usize), + (3, 5, 32, 0xD1B54A32D192ED03, 0x2545F4914F6CDD1D, 5, 3), + (4, 16, 128, 0x94D049BB133111EB, 0xBF58476D1CE4E5B9, 0, 4), + ] { + let program = S::new(h, w, k); + let a = codes(h * k, sa, za); + let b = codes(w * k, sb, zb); + let expected = a100_matmul(&a, &b, None, h, w, k); + let rows = program.generate_trace(&a, &b, None); + for (cell, chunk) in rows[..program.live_rows()].chunks(program.rows_per_cell()).enumerate() { + let last: &MatmulA100ColumnsView = chunk.last().unwrap().borrow(); + assert_eq!(last.is_cell_final, F::ONE); + let got = to_u64(last.cell_result_f32_lo) | (to_u64(last.cell_result_f32_hi) << 16); + assert_eq!(got as u32, expected[cell].to_bits(), "cell {cell} (h={h},w={w},k={k})"); + } + assert_all_constraints(&program, &rows); + } + } + + /// The GPU-validated reference vectors. For every `k%8==0` vector the trace + /// generator's committed FP32 result must equal the oracle `d` (generator + /// bit-exactness, carry-in threaded via the tile accumulator). The AIR models a + /// *from-zero* device tile (the scheme always accumulates with `c = 0.0`; see + /// `api::fp16::policy` / `quantization`), so the full constraint check is run on + /// the `c == 0` subset, where row 0's incoming carry is honestly zero. (Multi-row + /// carry chains are covered from zero by `trace_results_are_bit_exact_vs_oracle_matmul`.) + #[test] + fn reference_vectors_bit_exact_and_constraints_hold() { + let mut total = 0; + let mut zero_carry = 0; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % GROUP != 0 { + continue; // the AIR requires k a multiple of the group size. + } + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let c = f32::from_bits(t[1 + 2 * k].parse().unwrap()); + let d = f32::from_bits(t[2 + 2 * k].parse().unwrap()); + assert_eq!(a100_dot(&a, &b, c, None).to_bits(), d.to_bits(), "oracle mismatch, vector {total}"); + + let program = S::new(1, 1, k); + let rows = program.generate_trace(&a, &b, Some(&[c])); + let last: &MatmulA100ColumnsView = rows[program.live_rows() - 1].borrow(); + let got = to_u64(last.cell_result_f32_lo) | (to_u64(last.cell_result_f32_hi) << 16); + assert_eq!(got as u32, d.to_bits(), "vector {total} (k={k}): STARK result != oracle d"); + total += 1; + if c == 0.0 { + assert_all_constraints(&program, &rows); + zero_carry += 1; + } + } + assert!(total >= 200, "expected many k%8==0 reference vectors, got {total}"); + assert!(zero_carry >= 50, "expected many from-zero vectors for the constraint check, got {zero_carry}"); + } + + #[test] + fn padded_trace_matches_known_values() { + let program = S::new(3, 5, 32); // 15 cells x 4 rows = 60 live -> 64. + let a = codes(program.h * program.k, 0x9E3779B97F4A7C15, 7); + let b = codes(program.w * program.k, 0xC2B2AE3D27D4EB4F, 11); + let rows = program.generate_trace(&a, &b, None); + assert_eq!(program.live_rows(), 60); + assert_eq!(rows.len(), 64); + let known = program.known_values(); + for (col, poly) in known.iter().enumerate() { + assert_eq!(poly.len(), 64); + for (r, row) in rows.iter().enumerate() { + assert_eq!(poly.values[r], row[col], "known column {col} row {r}"); + } + } + assert_all_constraints(&program, &rows); + } + + /// No arithmetic constraint is vacuous: bumping a load-bearing witness cell of + /// an honest trace must violate some constraint. (Columns whose integrity is a + /// LUT's job — operand codes, decoded significands, shift powers, widths — are + /// exercised by the LUT CTLs in the follow-on driver, not here.) + #[test] + fn tampered_cells_break_constraints() { + let program = S::new(4, 4, 64); + let a = codes(program.h * program.k, 0x9E3779B97F4A7C15, 7); + let b = codes(program.w * program.k, 0xC2B2AE3D27D4EB4F, 11); + let rows = program.generate_trace(&a, &b, None); + let m = &MATMUL_A100_COL_MAP; + + let violates = |rows: &[[F; NUM_MATMUL_A100_COLUMNS]]| -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::ONE, + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + program.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().into_iter().any(|acc| acc != F::ZERO) + }) + }; + let view = |r: usize| -> &MatmulA100ColumnsView { rows[r].borrow() }; + let live = (0..rows.len() - 1) + .find(|&r| view(r).is_cell_final == F::ZERO && view(r).group_sum_is_zero == F::ZERO) + .expect("fixture has live mid-cell rows"); + let final_row = (0..rows.len()).find(|&r| view(r).is_cell_final == F::ONE).unwrap(); + + let bumps = [ + ("product_sig (MA1)", live, m.product_sig[2]), + ("aligned_mag (MA3/MA5)", live, m.aligned_mag[2]), + ("lane_rem (MA3)", live, m.lane_rem[2]), + ("group_max_biased_exponent (MA2/MA8)", live, m.group_max_biased_exponent), + ("max_exponent_attainment tail (MA2)", live, m.max_exponent_attainment[NUM_ATT_LINKS - 1]), + ("aligned_carry (MA4/MA5)", live + 1, m.aligned_carry), + ("carry_rem (MA4)", live + 1, m.carry_rem), + ("group_sum_abs (MA5)", live, m.group_sum_abs), + ("norm_sig (MA7/MA8)", live, m.norm_sig), + ("trunc_rem (MA7)", live, m.trunc_rem), + ("out_biased_exp (MA8)", live, m.out_biased_exp), + ("out_sig (MA8)", live, m.out_sig), + ("cell_result_f32_lo (MA9)", final_row, m.cell_result_f32_lo), + ("cell_products_truncated (MA10)", live, m.cell_products_truncated), + ("cell_breakpoints (MA10)", live, m.cell_breakpoints), + ("group_max_inv (MA2 nonempty)", live, m.group_max_inv), + ("aligned_mag_lo (MA12 reconstruction)", live, m.aligned_mag_lo[2]), + ("norm_sig_hi (MA12 reconstruction)", live, m.norm_sig_hi), + ]; + for (what, row, col) in bumps { + let mut tampered = rows.clone(); + tampered[row][col] += F::ONE; + assert!(violates(&tampered), "{what}: +1 at row {row} must break a constraint"); + } + + let flips = [ + ("group_sum_is_zero (MA5 ban)", live, m.group_sum_is_zero), + ("group_sum_sign (MA5)", live, m.group_sum_sign), + ("incoming_carry_is_zero (MA6)", live + 1, m.incoming_carry_is_zero), + ("lane_sign (MA5)", live, m.lane_sign[2]), + ("group_nonempty (MA2)", live, m.group_nonempty), + ]; + for (what, row, col) in flips { + let mut tampered = rows.clone(); + tampered[row][col] = F::ONE - tampered[row][col]; + assert!(violates(&tampered), "{what}: flip at row {row} must break a constraint"); + } + } + + /// Census tightness (gap 2): the census bits that *increase* certified work cannot be + /// inflated. Starting from an honest trace, forcing any breakpoint or products-truncated + /// flag ON where the real census is OFF (or forcing a drop flag ON with a zero remainder) + /// must violate MA3/MA11. This is what stops a prover overstating `rho`/`f_bp`. + fn violates_fn(program: &S) -> impl Fn(&[[F; NUM_MATMUL_A100_COLUMNS]]) -> bool + '_ { + move |rows: &[[F; NUM_MATMUL_A100_COLUMNS]]| -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::ONE, + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + program.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().into_iter().any(|acc| acc != F::ZERO) + }) + } + } + + #[test] + fn inflated_census_breaks_constraints() { + let program = S::new(4, 4, 64); + let a = codes(program.h * program.k, 0x9E3779B97F4A7C15, 7); + let b = codes(program.w * program.k, 0xC2B2AE3D27D4EB4F, 11); + let rows = program.generate_trace(&a, &b, None); + let m = &MATMUL_A100_COL_MAP; + let violates = violates_fn(&program); + assert!(!violates(&rows), "the honest trace must satisfy every constraint"); + let view = |r: usize| -> &MatmulA100ColumnsView { rows[r].borrow() }; + + // A nonempty mid-cell row that is NOT already a breakpoint — forcing its breakpoint on + // overstates the work ratio and must break MA11. + let non_bp = (0..rows.len() - 1) + .find(|&r| { + view(r).group_nonempty == F::ONE + && view(r).group_breakpoint == F::ZERO + && view(r).is_padding == F::ZERO + }) + .expect("fixture has a nonempty non-breakpoint row"); + let mut t = rows.clone(); + t[non_bp][m.group_breakpoint] = F::ONE; + assert!(violates(&t), "inflated group_breakpoint must break MA11"); + + // Forcing the carry / RZ drop flags on (with their remainders honestly zero) is the + // same attack one level down: MA11's clean/kill directions reject it. + let mut t = rows.clone(); + t[non_bp][m.carry_dropped] = F::ONE; + assert!(violates(&t), "inflated carry_dropped must break MA11"); + let mut t = rows.clone(); + t[non_bp][m.rz_dropped] = F::ONE; + assert!(violates(&t), "inflated rz_dropped must break MA11"); + + // Forcing a products-truncated flag on where the lane's remainder is zero overstates + // N_pt and must break MA3's tight census. + let clean_lane = (0..rows.len() - 1) + .find_map(|r| { + (0..GROUP) + .find(|&i| view(r).products_truncated_flag[i] == F::ZERO && view(r).is_padding == F::ZERO) + .map(|i| (r, i)) + }) + .expect("fixture has an untruncated lane"); + let mut t = rows.clone(); + t[clean_lane.0][m.products_truncated_flag[clean_lane.1]] = F::ONE; + assert!(violates(&t), "inflated products_truncated_flag must break MA3 tight census"); + + // Inflating the running breakpoint/products counters (the policy inputs) must also break. + let mut t = rows.clone(); + t[non_bp][m.cell_breakpoints] += F::ONE; + assert!(violates(&t), "inflated cell_breakpoints must break MA10"); + } + + /// MA13 — the subnormal FP32-output RZ branch. The from-zero matmul never produces an FP32 + /// subnormal (FP16 products align at `eta >= 99`, so a group output floors at `~2^-52`), so + /// the branch is reached through the accumulation datapath the oracle models: a subnormal + /// FP32 carry-in with zero operands, passed through onto the `2^-149` grid. The generator's + /// committed FP32 word must equal `a100_dot` bit-for-bit, and the committed columns must + /// satisfy the MA13/MA8/MA9 subnormal-encode relations exactly. + #[test] + fn subnormal_output_is_bit_exact_and_satisfies_ma13() { + let k = GROUP; // one group per cell: no cross-group carry chaining. + let zeros = vec![0u16; k]; + // A spread of FP32 subnormals (|x| < 2^-126, exponent field 0): min, mid, and max + // mantissa, plus negative ones. + let subnormals = [1u32, 5, 0x40_0000, 0x7F_FFFF, 0x8000_0005, 0x807F_FFFF]; + let mut covered = 0; + for &bits in &subnormals { + let c = f32::from_bits(bits); + assert_eq!((bits >> 23) & 0xFF, 0, "fixture must be an FP32 subnormal"); + // The oracle passes a subnormal carry-in through unchanged (zero operands). + let expected = a100_dot(&zeros, &zeros, c, None).to_bits(); + assert_eq!(expected, bits, "oracle subnormal pass-through, bits {bits:#010x}"); + + let program = S::new(1, 1, k); + let rows = program.generate_trace(&zeros, &zeros, Some(&[c])); + let row: &MatmulA100ColumnsView = rows[0].borrow(); + + // (1) Generator bit-exactness vs the oracle. + let got = to_u64(row.cell_result_f32_lo) | (to_u64(row.cell_result_f32_hi) << 16); + assert_eq!(got as u32, expected, "subnormal STARK word != oracle, bits {bits:#010x}"); + + // (2) The committed columns satisfy the MA13/MA8/MA9 subnormal relations. + assert_eq!(row.out_is_subnormal, F::ONE, "flag set on the subnormal row"); + assert_eq!(row.group_sum_is_zero, F::ZERO, "a subnormal output has a nonzero sum"); + assert_eq!(row.out_biased_exp, F::ZERO, "MA8: subnormal exponent field is 0"); + // Flag slack: exp_slack = -raw, where raw = group_max + width - 25. + let raw = to_u64(row.group_max_biased_exponent) as i64 + to_u64(row.group_sum_width) as i64 + - OUT_EXP_OFFSET as i64; + assert!(raw <= 0, "subnormal raw exponent must be <= 0 (got {raw})"); + assert_eq!(to_u64(row.exp_slack) as i64, -raw, "MA13: exp_slack = -raw"); + // Shift exponent and FP16POW2 value. + assert_eq!(row.sub_shift_exp, row.exp_slack + F::ONE, "MA13: k = exp_slack + 1"); + assert_eq!( + to_u64(row.sub_shift_power), + 1u64 << to_u64(row.sub_shift_exp), + "FP16POW2: sub_shift_power = 2^k" + ); + // Exact mantissa division and limb reconstruction. + assert_eq!( + row.norm_sig, + row.out_sig * row.sub_shift_power, + "MA13: NORM_SIG = OUT_SIG * SUB_SHIFT_POWER" + ); + assert_eq!( + row.out_sig, + row.out_sig_lo + row.out_sig_hi * F::from_canonical_u64(1 << 16), + "MA13: OUT_SIG limb reconstruction" + ); + assert!(to_u64(row.out_sig) < (1 << 23), "subnormal mantissa fits 23 bits"); + // MA9 encode with the (1-f) residue: subnormal word = sign<<31 | mantissa. + let word = to_u64(row.out_sign) * (1 << 31) + to_u64(row.out_sig); + assert_eq!(word as u32, expected, "MA9: subnormal encode = sign<<31 | mantissa"); + covered += 1; + } + assert_eq!(covered, subnormals.len()); + } + + /// MA13 soundness guard: on an honest from-zero trace the subnormal flag is 0 everywhere, and + /// forging a subnormal claim (flag on, or a full forged subnormal encode) on a live normal row + /// is rejected by the AIR — the flag has no valid nonnegative `exp_slack` witness when the raw + /// exponent is `>= 1`. This is the tamper-rejection on the subnormal encode. + #[test] + fn forged_subnormal_claim_is_rejected() { + let program = S::new(4, 4, 64); + let a = codes(program.h * program.k, 0x9E3779B97F4A7C15, 7); + let b = codes(program.w * program.k, 0xC2B2AE3D27D4EB4F, 11); + let rows = program.generate_trace(&a, &b, None); + let m = &MATMUL_A100_COL_MAP; + + // The honest from-zero trace never enters the subnormal branch. + for row in &rows { + let v: &MatmulA100ColumnsView = row.borrow(); + assert_eq!(v.out_is_subnormal, F::ZERO, "from-zero matmul never produces a subnormal"); + } + + let violates = violates_fn(&program); + assert!(!violates(&rows), "the honest trace must satisfy every constraint"); + let view = |r: usize| -> &MatmulA100ColumnsView { rows[r].borrow() }; + let live = (0..rows.len() - 1) + .find(|&r| view(r).group_sum_is_zero == F::ZERO && view(r).is_padding == F::ZERO) + .expect("fixture has a live nonzero-sum row"); + + // (a) Flipping the flag on alone: MA13's slack witness (exp_slack = raw-1 here) now + // contradicts the subnormal expectation -raw, and MA8 forces out_biased_exp to 0. + let mut t = rows.clone(); + t[live][m.out_is_subnormal] = F::ONE; + assert!(violates(&t), "a forged subnormal flag must be rejected"); + + // (b) A full forged subnormal encode (flag on, exponent field zeroed, a bogus mantissa and + // divisor) still has no valid nonnegative exp_slack for raw >= 1: the RANGE16 slack guard + // and MA13's slack identity reject it. + let mut t = rows.clone(); + t[live][m.out_is_subnormal] = F::ONE; + t[live][m.out_biased_exp] = F::ZERO; + t[live][m.sub_shift_exp] = F::ONE; + t[live][m.sub_shift_power] = F::from_canonical_u64(2); + assert!(violates(&t), "a forged subnormal encode must be rejected"); + + // (c) On a (white-box) honest subnormal row, corrupting the mantissa breaks the MA13 + // exact-division relation NORM_SIG = OUT_SIG * SUB_SHIFT_POWER. + let sub = S::new(1, 1, GROUP); + let c = f32::from_bits(0x40_0001); + let sub_rows = sub.generate_trace(&vec![0u16; GROUP], &vec![0u16; GROUP], Some(&[c])); + let r: &MatmulA100ColumnsView = sub_rows[0].borrow(); + assert_eq!(r.norm_sig, r.out_sig * r.sub_shift_power); + assert_ne!(r.norm_sig, (r.out_sig + F::ONE) * r.sub_shift_power, "a bumped mantissa breaks MA13"); + } + + #[test] + fn degree_is_at_most_three() { + test_stark_low_degree::(S::new(4, 4, 64)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + test_stark_circuit_constraints::(S::new(4, 4, 64)).unwrap(); + } +} diff --git a/zk-pow/src/circuit/fp16/mod.rs b/zk-pow/src/circuit/fp16/mod.rs new file mode 100644 index 000000000..f462c5817 --- /dev/null +++ b/zk-pow/src/circuit/fp16/mod.rs @@ -0,0 +1,55 @@ +//! ZK FP16 (A100) circuit — Stage 3 of the FP16 proof-of-useful-work scheme. +//! +//! This parallels `crate::circuit::fp8` but proves the FP16 / A100 scheme whose +//! plaintext ground truth lives in [`crate::api::fp16`]. The batched-FRI [`driver::Fp16System`] +//! batches, under one `batch_prove`/`batch_verify` with a recursive wrapper ([`wrapper`]): the +//! device matmul AIR ([`matmul_a100_stark`]), the rho/breakpoint policy AIR ([`policy_stark`]), +//! the lottery mixer ([`xor_fold_stark`]), the forked BLAKE3 engine ([`blake3_fp16_stark`]) driving +//! the operand-commitment + jackpot program ([`blake3_commit`]) and the noise-line keyed-XOF program +//! ([`noise_blake3`]), the seed-derived noise normalization ([`noise_stark`]), the per-row scale +//! derivation ([`row_scale_stark`]) and fused noisy quantization ([`noisy_quant_stark`], +//! [`noisy_quant_fma_stark`]), plus the committed LUTs — all tied together by the cross-table lookup +//! set ([`ctl`]). +//! +//! The AIRs reuse the fp8 circuit's shared, scheme-neutral plumbing (`circuit::utils` evaluators, +//! `circuit::fp8::columns_view`, the committed-LUT machinery of `circuit::fp8::luts`); the BLAKE3 +//! engine is **forked** ([`blake3_fp16_stark`]) so FP8's active consensus engine stays untouched. +//! +//! **Binding status.** The proof now binds, end-to-end and tested, the committed statement: +//! committed operand roots (`HASH_A`/`HASH_B`, bit-exact with `commit_operand`) → seed-derived noise +//! (`noise_seeds` over those roots) → noised operands (`Q(α·raw + β·E@F)`) → matmul (with cross-cell +//! row/column sharing) → policy gate → lottery tile → `HASH_JACKPOT` → statement digest → native +//! difficulty. Operand provenance, the output/ticket, and the anti-grind noise are all bound. +//! +//! **Header binding CLOSED.** The header-bound gateways — [`driver::Fp16System::verify_with_headers`] +//! for the batch proof and [`wrapper::verify_wrapped_proof_with_headers`] for the published wrapped +//! proof — derive the opening keys (`keyA`/`keyB`), the `p` encodings, the noise seeds, and the +//! lottery `jackpot_key` from the block header + public job params (bit-exact with the plaintext +//! certificate), pin the proof's corresponding public inputs to them, derive `statement_digest` from +//! the proven `HASH_JACKPOT`, and run the native difficulty check. So a verified proof is bound to +//! the specific block header exactly as the plaintext certificate is; nothing feeding the keys/seeds/ +//! jackpot key is caller-trusted. The only inherent boundary (shared with the plaintext FFI) is that +//! the caller supplies the header + `nbits` and window-authenticates `job.ancestor_header` first. +//! +//! **Remaining work (deployment, not soundness).** Making this proof the *wired* consensus path is a +//! deployment integration step: a wrapped-proof FFI entry, the Go/wire routing, and the miner +//! switching from plaintext-certificate assembly to proof generation. Until that lands the wired +//! consensus path remains the plaintext certificate ([`crate::api::fp16::verify`]). + +pub mod blake3_commit; +pub mod blake3_fp16_stark; +pub mod ctl; +pub mod driver; +pub mod matmul_a100_stark; +pub mod noise_blake3; +pub mod noise_stark; +pub mod noisy_quant_fma_stark; +pub mod noisy_quant_stark; +pub mod policy_stark; +pub mod row_scale_stark; +pub mod verifier_cache; +pub mod wrapper; +pub mod xor_fold_stark; + +#[cfg(test)] +mod consistency; diff --git a/zk-pow/src/circuit/fp16/noise_blake3.rs b/zk-pow/src/circuit/fp16/noise_blake3.rs new file mode 100644 index 000000000..323035421 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noise_blake3.rs @@ -0,0 +1,419 @@ +//! In-circuit derivation of the FP16 noise lines' keyed-BLAKE3-XOF bytes (ZK binding, increment +//! 6e-3c). +//! +//! This closes the last soundness gap of the FP16 noise: in increment 6e-2 the raw keyed-XOF bytes +//! [`crate::circuit::fp16::noise_stark::NoiseStark`] normalizes were **free witness**, so the noise +//! was still grindable (a prover could pick any bytes). Here the forked FP16 BLAKE3 engine +//! ([`super::blake3_fp16_stark`]) recomputes those bytes *in-circuit* from the real noise seeds, and +//! egresses each line's output `cv_out` so the egress CTL can bind them to NoiseStark's byte inputs. +//! +//! # The schedule, bit-exact with [`crate::api::fp16::noise`] +//! +//! The plaintext draws line `(side, factor, line)` under `seed` as +//! `keyed_blake3(line_key, material64)` where `line_key = subkey(LABEL_NOISE_LINE, seed) = +//! keyed_blake3(seed, LABEL_NOISE_LINE)` and `material64 = side | factor | line(u32 LE) | zero-pad` +//! (see [`crate::api::fp16::noise::sample_line_xof_bytes`]). The rank is [`FP16_QUANT_R`] `= 32`, so +//! the first `r = 32` XOF bytes are exactly the output `cv_out` (8 words LE). The schedule is: +//! +//! * **2 subkey compressions** — `subkey_A = keyed_blake3(seedA, label)` and +//! `subkey_B = keyed_blake3(seedB, label)`, keyed by `seedA`/`seedB` (fed as the engine's +//! `KEY_A`/`KEY_B` public inputs — the verifier pins them to the ROOT-DERIVED noise seeds +//! [`crate::circuit::fp16::driver::fp16_root_derived_seeds`], so they are a pure function of the +//! committed operand roots; see the scope note below). +//! * **`h + w + 2k` line compressions** in NoiseStark's line order `[E_A (h), F_A (k), E_B (w), +//! F_B (k)]`, each keyed by the appropriate subkey's `cv_out` (routed as a `Chain` CV), hashing +//! that line's `material64`, egressing its `cv_out` under the per-line key base `line * 16`. +//! * the one mandatory lottery compression (the engine requires exactly one). +//! +//! Every message block (the subkey `label` and each line's `material64`) is PUBLIC per-line data; it +//! is pinned verifier-fixed via the engine's general message-word pins +//! ([`Fp16RawBlake3Program::msg_pins`]) so a prover cannot grind the noise through the message. The +//! only remaining witness freedom is the seeds. +//! +//! **Scope (increment 6e-3d — the seed<-root gap is now CLOSED).** The seeds are derived from the +//! committed operand roots: the driver sets this engine's `KEY_A`/`KEY_B` public inputs to +//! `seedA`/`seedB = noise_seeds(keys, {HASH_A, HASH_B}, p)` — exactly +//! [`crate::api::fp16::noise::noise_seeds`] over the committed roots, the opening keys and the public +//! parameters ([`crate::circuit::fp16::driver::fp16_root_derived_seeds`]). `verify` recomputes those +//! seeds from the proof's pinned `HASH_A`/`HASH_B` + keys + `p` and pins the noise-BLAKE3 +//! `KEY_A`/`KEY_B` to them, so a prover can neither choose the noise *bytes* (they are the pinned +//! keyed-BLAKE3 XOF of the seeds) nor the *seeds* (they are forced to be `noise_seeds` of the +//! committed roots). The noise is now fully operand-dependent and bit-exact with the plaintext's +//! root-derived noise — the root-anchored anti-grind property holds. +//! +//! The only remaining test-vs-production boundary is shared with `HASH_A`/`HASH_B`: the opening keys +//! and the `p` encodings are supplied at the circuit boundary (by the driver / tests) rather than +//! derived from the block header in-circuit; the consensus layer supplies these header-derived values +//! the same way it supplies the expected `HASH_A`/`HASH_B`. +//! +//! # Egress -> NoiseStark binding +//! +//! Each line compression's `cv_out` (= the 32 XOF bytes) egresses as 16 little-endian 16-bit limbs +//! on keys `line*16 .. line*16 + 16` ([`super::blake3_fp16_stark::ctl::ctl_cv_egress_looking_blake3`]). +//! NoiseStark's egress-pair looked side ([`super::noise_stark::ctl::ctl_noise_egress_pair_looked`]) +//! recomposes its own two consecutive XOF bytes into the same 16-bit limbs on the same keys, so the +//! CTL multiset balance forces NoiseStark's bytes to equal the in-circuit-derived XOF bytes of the +//! root-derived seeds — closing the "free-witness noise bytes" grind, and (6e-3d) the seeds are +//! themselves bound to the committed operand roots, so the noise is fully operand-bound anti-grind. + +use pearl_blake3::{B3F_CHUNK_END, B3F_CHUNK_START, B3F_KEYED_HASH, B3F_ROOT, BLAKE3_MSG_LEN, blake3_digest}; +use plonky2::hash::hash_types::RichField; + +use crate::api::fp16::noise::{NoiseFactor, Side, noise_line_label, noise_line_material}; +use crate::api::primitives::Hash256; +use crate::circuit::fp16::blake3_commit::bytes32_to_words; +use crate::circuit::fp16::blake3_fp16_stark::columns::{PI_HASH_JACKPOT, PI_KEY_A, PI_KEY_B}; +use crate::circuit::fp16::blake3_fp16_stark::{ + Fp16RawBlake3Instruction, Fp16RawBlake3Program, Fp16RawCvSource, Fp16RawMessageSource, +}; + +/// The keyed-BLAKE3 flags of a one-block root hash (chunk start + end + root + keyed). +const KEYED_ONE_BLOCK: u32 = (B3F_CHUNK_START | B3F_CHUNK_END | B3F_ROOT | B3F_KEYED_HASH) as u32; + +/// The 16 little-endian `u32` words of one 64-byte message block — the per-row word pins the engine +/// fixes a compression's message to (`word 2j` / `word 2j+1` on row `j`). +fn block_pin_words(block: &[u8; 64]) -> [u32; 16] { + core::array::from_fn(|i| u32::from_le_bytes(block[4 * i..4 * i + 4].try_into().unwrap())) +} + +/// The `(side, factor, line_index)` address of NoiseStark line `L` for an `h x w` tile with inner +/// `k`, in the committed line order `[E_A (h), F_A (k), E_B (w), F_B (k)]`. `None` past the last +/// line. +fn line_address(l: usize, h: usize, w: usize, k: usize) -> Option<(Side, NoiseFactor, u32)> { + if l < h { + Some((Side::A, NoiseFactor::E, l as u32)) + } else if l < h + k { + Some((Side::A, NoiseFactor::F, (l - h) as u32)) + } else if l < h + k + w { + Some((Side::B, NoiseFactor::E, (l - h - k) as u32)) + } else if l < h + k + w + k { + Some((Side::B, NoiseFactor::F, (l - h - k - w) as u32)) + } else { + None + } +} + +/// `E_A` lines key off `seedA` (subkey_A); `F_A`, `E_B`, `F_B` off `seedB` (subkey_B) — the exact +/// seed assignment of [`crate::api::fp16::noise::sample_noise`]. +fn line_subkey_instr(l: usize, h: usize) -> usize { + if l < h { SUBKEY_A_INSTR } else { SUBKEY_B_INSTR } +} + +/// Instruction index of the `subkey_A = keyed_blake3(seedA, label)` compression. +pub const SUBKEY_A_INSTR: usize = 0; +/// Instruction index of the `subkey_B = keyed_blake3(seedB, label)` compression. +pub const SUBKEY_B_INSTR: usize = 1; +/// Instruction index of line `L` (the two subkeys come first). +pub const fn line_instr(l: usize) -> usize { + 2 + l +} +/// The number of noise lines of an `h x w` tile with inner `k`. +pub const fn num_lines(h: usize, w: usize, k: usize) -> usize { + h + w + 2 * k +} + +/// The egress key base of line `L` (16 limbs per line, disjoint 16-wide ranges). NoiseStark's +/// egress-pair looked side uses the same `L*16 + j` keys. +pub const fn line_egress_base(l: usize) -> u64 { + (l as u64) * 16 +} + +/// Builds the FP16 noise-derivation BLAKE3 program for an `h x w` tile with inner `k`: the two +/// subkey compressions, the `h + w + 2k` line compressions (each egressing its `cv_out`), and the +/// mandatory lottery compression. Every message block is pinned to its public constant via +/// `msg_pins`, so only the seeds (the engine's `KEY_A`/`KEY_B`, bound to the committed roots at the +/// batch) are witness. `height_bits`, when `Some`, forces an on-ladder trace height. +pub fn noise_blake3_program(h: usize, w: usize, k: usize, height_bits: Option) -> Fp16RawBlake3Program { + let lines = num_lines(h, w, k); + let label = noise_line_label(); + assert!(label.len() <= BLAKE3_MSG_LEN, "noise-line label must fit one BLAKE3 block"); + + // Aux message 0 is the shared `label || zero-pad` block; aux message 1 + L is line L's material64. + let mut label_block = [0u8; 64]; + label_block[..label.len()].copy_from_slice(label); + let label_pins = block_pin_words(&label_block); + + let mut instructions = Vec::with_capacity(lines + 3); + let mut msg_pins: Vec<(usize, [u32; 16])> = Vec::with_capacity(lines + 2); + + // subkey_A (keyed by seedA = KEY_A) and subkey_B (keyed by seedB = KEY_B), both hashing `label`. + for (instr_idx, key) in [(SUBKEY_A_INSTR, Fp16RawCvSource::KeyA), (SUBKEY_B_INSTR, Fp16RawCvSource::KeyB)] { + instructions.push(Fp16RawBlake3Instruction { + cv: key, + msg: Fp16RawMessageSource::AuxBytes { idx: 0 }, + counter: 0, + block_len: label.len() as u32, + flags: KEYED_ONE_BLOCK, + bind: None, + egress: None, + }); + msg_pins.push((instr_idx, label_pins)); + } + + // Line compressions, each keyed by its subkey's cv_out (Chain) and egressing cv_out. + for l in 0..lines { + let (side, factor, line) = line_address(l, h, w, k).expect("line index in range"); + let material = noise_line_material(side, factor, line); + let instr_idx = line_instr(l); + instructions.push(Fp16RawBlake3Instruction { + cv: Fp16RawCvSource::Chain(line_subkey_instr(l, h)), + msg: Fp16RawMessageSource::AuxBytes { idx: 1 + l }, + counter: 0, + block_len: BLAKE3_MSG_LEN as u32, + flags: KEYED_ONE_BLOCK, + bind: None, + egress: Some(line_egress_base(l)), + }); + msg_pins.push((instr_idx, block_pin_words(&material))); + } + + instructions.push(Fp16RawBlake3Instruction::lottery()); + + Fp16RawBlake3Program { + instructions, + num_aux_msgs: 1 + lines, + num_aux_cvs: 0, + routing_pins: Vec::new(), + moe: None, + msg_pins, + height_bits, + } +} + +/// The witness aux-message blocks for [`noise_blake3_program`]: aux 0 = `label || zero-pad`, aux +/// `1 + L` = line `L`'s `material64`. Seed-independent (the seeds enter as `KEY_A`/`KEY_B`), so the +/// prover has no freedom here — every block equals the pinned public constant. +pub fn noise_blake3_aux_msgs(h: usize, w: usize, k: usize) -> Vec<[u8; 64]> { + let lines = num_lines(h, w, k); + let label = noise_line_label(); + let mut aux = Vec::with_capacity(1 + lines); + let mut label_block = [0u8; 64]; + label_block[..label.len()].copy_from_slice(label); + aux.push(label_block); + for l in 0..lines { + let (side, factor, line) = line_address(l, h, w, k).expect("line index in range"); + aux.push(noise_line_material(side, factor, line)); + } + aux +} + +/// The engine's `(KEY_A, KEY_B)` word form for the two noise seeds: `KEY_A = seedA`, `KEY_B = seedB`. +/// The subkey compressions key off these, so binding them (as the engine's public inputs) to the +/// natively-recomputed [`crate::api::fp16::noise::noise_seeds`] is what makes the whole derivation +/// seed-bound. +pub fn noise_seed_key_words(seed_a: &Hash256, seed_b: &Hash256) -> ([u32; 8], [u32; 8]) { + (bytes32_to_words(seed_a), bytes32_to_words(seed_b)) +} + +/// The noise-BLAKE3 program's fixed jackpot key / lottery words (the engine requires one lottery +/// compression; the noise derivation does not use it, so it is pinned to a constant and its +/// `HASH_JACKPOT` is an inert public input). +pub const NOISE_BLAKE3_JACKPOT_KEY: Hash256 = [0u8; 32]; +/// The noise-BLAKE3 program's fixed lottery message words (all zero; see [`NOISE_BLAKE3_JACKPOT_KEY`]). +pub const NOISE_BLAKE3_LOTTERY_WORDS: [u32; 16] = [0u32; 16]; + +/// The noise-BLAKE3 table's 64 public inputs for seeds `(seed_a, seed_b)`: `KEY_A = seedA`, +/// `KEY_B = seedB` (the pinned seeds the verifier checks — the seed binding), `JACKPOT_KEY = +/// NOISE_BLAKE3_JACKPOT_KEY`, `HASH_JACKPOT` the inert lottery digest, every other slot zero (the +/// program binds no operand/routing/offsets hash). Deterministic, so [`crate::circuit::fp16::driver`] +/// can pin them in `verify` without reproving. +pub fn noise_blake3_public_inputs(seed_a: &Hash256, seed_b: &Hash256) -> Vec { + let mut pis = vec![F::ZERO; crate::circuit::fp16::blake3_fp16_stark::columns::NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS]; + let (ka, kb) = noise_seed_key_words(seed_a, seed_b); + for i in 0..8 { + pis[PI_KEY_A + i] = F::from_canonical_u32(ka[i]); + pis[PI_KEY_B + i] = F::from_canonical_u32(kb[i]); + } + // KEY space PI_JACKPOT_KEY (16..24): NOISE_BLAKE3_JACKPOT_KEY is all-zero, so those stay zero. + let lottery_bytes: Vec = NOISE_BLAKE3_LOTTERY_WORDS.iter().flat_map(|w| w.to_le_bytes()).collect(); + let jackpot = blake3_digest(&lottery_bytes, Some(NOISE_BLAKE3_JACKPOT_KEY)); + let jackpot_words = bytes32_to_words(&jackpot); + for i in 0..8 { + pis[PI_HASH_JACKPOT + i] = F::from_canonical_u32(jackpot_words[i]); + } + pis +} + +/// The on-ladder trace height (in degree bits) for the noise-BLAKE3 table of an `h x w` tile with +/// inner `k`: the smallest [`crate::circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS`] member whose +/// height covers the live rows (`8 * (num_lines + 3)` — two subkeys, the lines, the lottery). Snapping +/// to the ladder keeps the table on the consensus fold ladder (the universal-wrapper prerequisite). +pub fn noise_blake3_height_bits(h: usize, w: usize, k: usize) -> usize { + let live_rows = 8 * (num_lines(h, w, k) + 3); + crate::circuit::fp16::driver::FP16_REACHABLE_DEGREE_BITS + .iter() + .copied() + .filter(|&b| (1usize << b) >= live_rows) + .min() + .expect("noise-BLAKE3 live rows exceed the top ladder height") +} + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use starky::constraint_consumer::ConstraintConsumer; + use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; + use starky::stark::Stark; + + use super::*; + use crate::api::fp16::noise::{sample_line_xof_bytes, subkey}; + use crate::api::fp8::public_params::HashId; + use crate::circuit::fp16::blake3_fp16_stark::columns::{ + FP16_RAW_BLAKE3_COL_MAP, NUM_FP16_RAW_BLAKE3_COLUMNS, NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS, + }; + use crate::circuit::fp16::blake3_fp16_stark::{Fp16RawBlake3ColumnsView, Fp16RawBlake3Stark, Fp16RawBlake3TraceInputs}; + + const D: usize = 2; + type F = GoldilocksField; + type S = Fp16RawBlake3Stark; + + fn trace_inputs<'a>(aux: &'a [[u8; 64]], key_a: [u32; 8], key_b: [u32; 8]) -> Fp16RawBlake3TraceInputs<'a> { + Fp16RawBlake3TraceInputs { + a_values: &[], + a_scales: &[], + b_values: &[], + b_scales: &[], + routing_words: &[], + offsets_words: &[], + aux_msgs: aux, + aux_cvs: &[], + lottery_words: [0; 16], + key_a, + key_b, + jackpot_key: [0x5a5a_5a5au32; 8], + a_hash_id: HashId::Blake3Chunk1024, + b_hash_id: HashId::Blake3Chunk1024, + routing_hash_id: HashId::Blake3Chunk1024, + offsets_hash_id: HashId::Blake3Chunk1024, + } + } + + fn constraints_violated( + stark: &S, + rows: &[[F; NUM_FP16_RAW_BLAKE3_COLUMNS]], + pis: &[F; NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS], + ) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], pis); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().into_iter().any(|acc| acc != F::ZERO) + }) + } + + /// The row index of a compression's finalization row (row 7 of instruction `c`). + fn fin_row(c: usize) -> usize { + 8 * c + 7 + } + + /// Read a finalization row's `cv_out` as 32 LE bytes. + fn cv_out_bytes(row: &Fp16RawBlake3ColumnsView) -> [u8; 32] { + let mut out = [0u8; 32]; + for w in 0..8 { + let word = row.cv_out[w].to_canonical_u64() as u32; + out[4 * w..4 * w + 4].copy_from_slice(&word.to_le_bytes()); + } + out + } + + /// The in-circuit program reproduces, bit-for-bit, the plaintext noise derivation: each subkey's + /// `cv_out == subkey(LABEL_NOISE_LINE, seed)` and each line's egressed `cv_out == + /// sample_line_xof_bytes(seed, side, factor, line, 32)`; the whole forked AIR is satisfied. + #[test] + fn noise_blake3_is_bit_exact_vs_sample_line_xof() { + let seed_a: Hash256 = [0x3c; 32]; + let seed_b: Hash256 = [0xa7; 32]; + // A spread of tile shapes (small, on the wrapper envelope k >= 16 and asymmetric). + for (h, w, k) in [(1usize, 1usize, 16usize), (4, 4, 16), (2, 8, 32)] { + let program = noise_blake3_program(h, w, k, None); + let aux = noise_blake3_aux_msgs(h, w, k); + let (ka, kb) = noise_seed_key_words(&seed_a, &seed_b); + let data = trace_inputs(&aux, ka, kb); + let (rows, pis) = program.generate_trace::(&data); + + // (a) The two subkeys equal subkey(LABEL, seed). + let sub_a: &Fp16RawBlake3ColumnsView = rows[fin_row(SUBKEY_A_INSTR)].borrow(); + let sub_b: &Fp16RawBlake3ColumnsView = rows[fin_row(SUBKEY_B_INSTR)].borrow(); + assert_eq!(cv_out_bytes(sub_a), subkey(noise_line_label(), Some(&seed_a)), "subkey_A mismatch {h}x{w}x{k}"); + assert_eq!(cv_out_bytes(sub_b), subkey(noise_line_label(), Some(&seed_b)), "subkey_B mismatch {h}x{w}x{k}"); + + // (b) Every line's egressed cv_out equals sample_line_xof_bytes over the right seed. + for l in 0..num_lines(h, w, k) { + let (side, factor, line) = line_address(l, h, w, k).unwrap(); + let seed = if l < h { seed_a } else { seed_b }; + let row: &Fp16RawBlake3ColumnsView = rows[fin_row(line_instr(l))].borrow(); + // The egress flag and key base ride this row. + assert_eq!(row.is_egress_cv, F::ONE, "line {l} must egress"); + assert_eq!(row.ctl_key_base, F::from_canonical_u64(line_egress_base(l)), "line {l} egress key"); + // cv_out == the first r = 32 XOF bytes of the plaintext draw. + let want = sample_line_xof_bytes(&seed, side_copy(side), factor_copy(factor), line, 32); + assert_eq!(cv_out_bytes(row).as_slice(), want.as_slice(), "line {l} ({h}x{w}x{k}) XOF mismatch"); + // The egress limbs recompose to cv_out[w] (what the egress CTL exports). + for w2 in 0..8 { + let lo = row.cv_egress_limbs[2 * w2].to_canonical_u64(); + let hi = row.cv_egress_limbs[2 * w2 + 1].to_canonical_u64(); + assert_eq!((lo + (hi << 16)) as u32, row.cv_out[w2].to_canonical_u64() as u32, "limb recompose"); + } + } + + // (c) The whole forked AIR (keyed chain, message-word pins, egress) is satisfied. + assert!(!constraints_violated(&S::new(program), &rows, &pis), "forked AIR violated for {h}x{w}x{k}"); + } + } + + /// Grinding the noise is fail-closed: changing a line's material (the public address block) away + /// from its pinned constant breaks the engine's word-pin constraint, and changing the seed + /// changes every derived byte (so a prover cannot pick a favorable line that isn't the real + /// seed-derived one). + #[test] + fn material_pin_and_seed_are_load_bearing() { + let (h, w, k) = (2usize, 2usize, 16usize); + let seed_a: Hash256 = [0x11; 32]; + let seed_b: Hash256 = [0x22; 32]; + let program = noise_blake3_program(h, w, k, None); + let mut aux = noise_blake3_aux_msgs(h, w, k); + let (ka, kb) = noise_seed_key_words(&seed_a, &seed_b); + + // Honest trace passes. + let (rows, pis) = program.generate_trace::(&trace_inputs(&aux, ka, kb)); + assert!(!constraints_violated(&S::new(program.clone()), &rows, &pis), "honest must pass"); + + // Tamper line 0's material (aux idx 1) away from its pinned public constant: the pins still + // hold the honest words, so the ingested word != WORD_PIN and the pin constraint rejects. + aux[1][0] ^= 0xFF; + let (bad_rows, bad_pis) = program.generate_trace::(&trace_inputs(&aux, ka, kb)); + assert!( + constraints_violated(&S::new(program), &bad_rows, &bad_pis), + "a tampered (unpinned) material block must break the word-pin constraint" + ); + + // A different seed yields entirely different XOF bytes (grinding the seed is only possible by + // changing the committed roots, which the batch binds). + let other = sample_line_xof_bytes(&[0x33; 32], Side::A, NoiseFactor::E, 0, 32); + let honest = sample_line_xof_bytes(&seed_a, Side::A, NoiseFactor::E, 0, 32); + assert_ne!(other, honest, "distinct seeds must give distinct XOF bytes"); + } + + // `Side`/`NoiseFactor` are not `Copy`; rebuild them from the address for the second use. + fn side_copy(s: Side) -> Side { + match s as u8 { + 0 => Side::A, + _ => Side::B, + } + } + fn factor_copy(f: NoiseFactor) -> NoiseFactor { + match f as u8 { + 0 => NoiseFactor::E, + _ => NoiseFactor::F, + } + } +} diff --git a/zk-pow/src/circuit/fp16/noise_stark/columns.rs b/zk-pow/src/circuit/fp16/noise_stark/columns.rs new file mode 100644 index 000000000..6f5b4ba59 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noise_stark/columns.rs @@ -0,0 +1,259 @@ +//! Fixed trace layout for the FP16 noise-line normalization AIR. +//! +//! One row per noise entry (one raw XOF byte), plus trailing all-zero `IS_PAD = 1` rows that +//! pad the live `rank` rows to a power of two. The **line-level** scalars (the sum of squares, +//! the integer square root, and the BF16 scale derivation) are a pure function of the whole +//! line, so they are replicated identically on every row (pinned to the final prefix sum by the +//! last-row equality and the transition-equality of `TOTAL_SUMSQ`); each row then also proves +//! its **own** entry (`entry_i = fp16(bf16(x_i) * scale)`) from that shared scale. +//! +//! All fixed-point BF16 roundings are proved with round-to-nearest / ties-to-even *bracket* +//! gadgets (quarter-ulp integer comparisons, mirroring `circuit::fp8::scale_stark`'s sqrt +//! bracket), reusing only the shared `RANGE16` and `POW2D` committed LUTs — no new table is +//! added. See `stark.rs` for the per-group constraint derivations and the documented +//! soundness envelope. +//! +//! [`NoiseColumnsView`] is `#[repr(C)]`; declaration order is committed column order. + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one NoiseStark trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct NoiseColumnsView { + // ------------------------------------------------------------------------------------------ + // Class (a) ("known") columns: pure functions of the geometry `(h, w, k, rank)`, verifier- + // recomputed and checked against the trace openings (`starky`'s batch known columns). Must come + // first. The extended AIR lays `num_lines = h + w + 2k` rank-entry blocks end to end — in the + // order `E_A` (`h` lines), `F_A` (`k` lines), `E_B` (`w` lines), `F_B` (`k` lines), mirroring the + // noise-matmul operand index layout — each block a self-contained `normalize_line` derivation, + // followed by trailing padding. Exactly the multi-block structure of + // [`crate::circuit::fp16::row_scale_stark`]. + // ------------------------------------------------------------------------------------------ + /// 1 on the trailing padding rows (`num_lines * rank` live rows padded to the trace height). + pub is_pad: T, + /// 1 on the first row of each rank-entry block — the live blocks (`row % rank == 0`) and the + /// first padding row. Gates the per-block prefix-sum reset and the scalar jumps. + pub is_block_start: T, + /// 1 on the last row of each LIVE block (`row % rank == rank-1`, live). Pins `TOTAL_SUMSQ` to + /// that block's finished prefix sum. Padding carries 0. + pub is_block_final: T, + /// The global entry index `line * rank + entry` on live rows (= the live trace-row index, since + /// blocks are contiguous). The E/F-binding CTL key; held at the final live index on padding. + pub global_index: T, + /// The noise-matmul reuse multiplicity of this line's entries (`E_A`/`E_B` lines: `k`; `F_A` + /// lines: `h`; `F_B` lines: `w`). The E/F-binding looked side carries it so each proven entry + /// balances the matmul operand's per-cell reuse. Held at the final live value on padding (the CTL + /// filters padding out via `1 - IS_PAD`). + pub operand_mult: T, + /// **ZK noise binding (6e-3c).** 1 on the even live rows that open a two-byte XOF limb (`entry` + /// even and `entry + 1 < rank`): the filter of the egress-pair looked channel + /// ([`super::ctl::ctl_noise_egress_pair_looked`]) binding this line's XOF bytes to the + /// seed-derived keyed-BLAKE3 egress ([`crate::circuit::fp16::noise_blake3`]). Class (a). + pub is_egress_pair: T, + /// **ZK noise binding (6e-3c).** On an `IS_EGRESS_PAIR` row, the egress channel key + /// `line*16 + entry/2` (= `GLOBAL_INDEX / 2`), matching the noise-BLAKE3 line compression's egress + /// base `line*16` plus the limb index. 0 elsewhere. Class (a). + pub egress_key: T, + + // ------------------------------------------------------------------------------------------ + // Per-entry raw byte decode: `x_i = (1 - 2*SIGN_BIT) * MAGNITUDE`, + // `MAGNITUDE = MAG_MINUS_1 + 1 in [1, 128]`. `BYTE` is a witness input (CTL-bound to the + // keyed-BLAKE3 XOF in a later stage; decode alone pins `BYTE in [0, 255]`). + // ------------------------------------------------------------------------------------------ + /// The raw XOF byte. + pub byte: T, + /// Bit 7 of the byte (the sign). + pub sign_bit: T, + /// `BYTE & 0x7F` (the magnitude minus one), range `[0, 127]` (PAIR128). + pub mag_minus_1: T, + /// `(1 - IS_PAD) * (MAG_MINUS_1 + 1)` — the signed magnitude `|x_i|` (0 on pad rows). + pub magnitude: T, + + // ------------------------------------------------------------------------------------------ + // Line sum of squares and its integer square root. + // ------------------------------------------------------------------------------------------ + /// Prefix sum of `MAGNITUDE^2` through this row. + pub running_sumsq: T, + /// The full line sum of squares `S = sum_i x_i^2` (constant across all rows). + pub total_sumsq: T, + /// High 16-bit limb of `TOTAL_SUMSQ` (`S < 2^32`; low limb is the RC16'd remainder). + pub total_hi: T, + + /// `norm_scaled = isqrt(S * 1024)` — the fixed-point line norm (`INT_SQRT_PREC = 32`). + pub norm_scaled: T, + /// High 16-bit limb of `NORM_SCALED` (`q < 2^21`). + pub norm_scaled_hi: T, + /// Euclidean remainder `X - q^2` with `X = S*1024`, `q = NORM_SCALED` (`in [0, 2q]`). + pub isqrt_rem: T, + /// High 16-bit limb of `ISQRT_REM` (`< 2^22`). + pub isqrt_rem_hi: T, + /// Euclidean upper slack `2q - ISQRT_REM >= 0`. + pub isqrt_s2: T, + /// High 16-bit limb of `ISQRT_S2`. + pub isqrt_s2_hi: T, + + // ------------------------------------------------------------------------------------------ + // `denom = f32_to_bf16(norm_scaled)` — RNE of the integer `q` to a normal BF16 (group D). + // Value `= M_DEN * 2^(DENOM_EXP - 134)`, `M_DEN = 128 + DENOM_MANT`. + // ------------------------------------------------------------------------------------------ + /// BF16 exponent field of `denom` (`= E*(denom)`, structurally normal). + pub denom_exp: T, + /// BF16 mantissa field of `denom`, `in [0, 127]` (PAIR128). + pub denom_mant: T, + /// `2^(DENOM_EXP - 134)` (POW2D value; the key range proves `DENOM_EXP in [134, 153]`). + pub denom_pow: T, + /// `DENOM_MANT & 1` (ties-to-even parity; boolean). + pub denom_parity: T, + /// `(DENOM_MANT - DENOM_PARITY) / 2` (RC16; makes the parity split two-sided). + pub denom_half: T, + /// Binade-bottom flag `IS_BOTTOM = [DENOM_MANT == 0]` (value is a power of two): its lower + /// rounding boundary is `-ulp/4`, not `-ulp/2`. Boolean, pinned exactly by the is-zero + /// gadget (`denom_mant_inv`). `DENOM_EXP >= 2` is structural here (POW2D domain), so no + /// separate exponent witness is needed. + pub denom_bottom: T, + /// Inverse witness for the `[DENOM_MANT == 0]` is-zero gadget. + pub denom_mant_inv: T, + /// Lower quarter-ulp boundary product `(4*M_DEN - 2 + DENOM_BOTTOM) * DENOM_POW`. + pub denom_blo: T, + /// Upper quarter-ulp boundary product `(4*M_DEN + 2) * DENOM_POW`. + pub denom_bhi: T, + /// High 16-bit limb of the lower bracket slack. + pub denom_sl_hi: T, + /// High 16-bit limb of the upper bracket slack. + pub denom_su_hi: T, + + // ------------------------------------------------------------------------------------------ + // `scale = bf16_div(numer, denom)` — RNE of `NUMER_VAL / denom` to a normal BF16 (group V). + // `numer = f32_to_bf16(NOISE_TARGET_NORM * 32) = 8192 = 2^13` is a compile-time constant + // power of two, so the division bracket reduces to a single power-of-two `2^A` comparison + // against `(4*M_S +/- 2) * M_DEN`, with `A = 283 - DENOM_EXP - SCALE_EXP`. + // ------------------------------------------------------------------------------------------ + /// BF16 exponent field of `scale` (normal). + pub scale_exp: T, + /// BF16 mantissa field of `scale`, `in [0, 127]` (PAIR128); `M_S = 128 + SCALE_MANT`. + pub scale_mant: T, + /// `2^A`, `A = 283 - DENOM_EXP - SCALE_EXP` (POW2D value; key range proves `A in [0, 19]`). + pub div_pow: T, + /// `SCALE_MANT & 1` (parity; boolean). + pub scale_parity: T, + /// `(SCALE_MANT - SCALE_PARITY) / 2` (RC16). + pub scale_half: T, + /// Binade-bottom flag `IS_BOTTOM = [SCALE_MANT == 0]` (see `denom_bottom`). + pub scale_bottom: T, + /// Inverse witness for the `[SCALE_MANT == 0]` is-zero gadget. + pub scale_mant_inv: T, + /// Lower boundary product `(4*M_S - 2 + SCALE_BOTTOM) * M_DEN`. + pub div_blo: T, + /// Upper boundary product `(4*M_S + 2) * M_DEN`. + pub div_bhi: T, + /// High 16-bit limb of the lower division-bracket slack. + pub div_sl_hi: T, + /// High 16-bit limb of the upper division-bracket slack. + pub div_su_hi: T, + + // ------------------------------------------------------------------------------------------ + // Per-entry `entry_bf16 = bf16_mul(bf16(x_i), scale)` then `entry = f32_to_fp16(entry_bf16)` + // (group E). The exact pre-rounding product significand is the integer + // `P = MAGNITUDE * M_S < 2^16`; RNE to 8 bits gives `M_E = 128 + ENTRY_MANT` at shift `gm`. + // The BF16 -> FP16 cast is an exact widening (entries are always FP16-normal in the scheme; + // see the envelope note in `stark.rs`). All group-E columns are 0 on pad rows. + // ------------------------------------------------------------------------------------------ + /// BF16 mantissa field of `entry_bf16` (`M_E = 128 + ENTRY_MANT`); `in [0, 127]` (PAIR128). + pub entry_mant: T, + /// Rounding shift `gm = bitlen(P) - 8` (POW2D key; `in [0, 19]`). + pub entry_gm: T, + /// `2^gm` (POW2D value). + pub entry_pow: T, + /// `ENTRY_MANT & 1` (parity; boolean). + pub entry_parity: T, + /// `(ENTRY_MANT - ENTRY_PARITY) / 2` (RC16). + pub entry_half: T, + /// Binade-bottom flag `IS_BOTTOM = [ENTRY_MANT == 0]` (see `denom_bottom`); gated off on pad + /// rows (the is-zero gadget would otherwise force it to 1 on the zero-mantissa pads). + pub entry_bottom: T, + /// Inverse witness for the `[ENTRY_MANT == 0]` is-zero gadget (live rows only). + pub entry_mant_inv: T, + /// Exact product significand `P = MAGNITUDE * M_S`. + pub entry_prod: T, + /// Lower boundary product `(4*M_E - 2 + ENTRY_BOTTOM) * ENTRY_POW`. + pub entry_blo: T, + /// Upper boundary product `(4*M_E + 2) * ENTRY_POW`. + pub entry_bhi: T, + /// High 16-bit limb of the lower multiply-bracket slack. + pub entry_sl_hi: T, + /// High 16-bit limb of the upper multiply-bracket slack. + pub entry_su_hi: T, + /// FP16 biased exponent field of the entry (`= ENTRY_GM + SCALE_EXP - 112`, `in [1, 30]`). + pub entry_fp16_exp: T, + /// The output FP16 code: `SIGN_BIT*2^15 + ENTRY_FP16_EXP*2^10 + 8*ENTRY_MANT`. + pub entry_fp16: T, + /// **ZK noise binding (6e-3c).** On an `IS_EGRESS_PAIR` row, the little-endian 16-bit XOF limb + /// `BYTE + 2^8 * BYTE'` (this row's byte and the next row's byte), bound by the transition + /// constraint `IS_EGRESS_PAIR * (BYTE_PAIR - BYTE - 256*BYTE') = 0`. The egress-pair channel + /// exports it against the noise-BLAKE3 line compression's `cv_egress_limbs[entry/2]`, forcing the + /// normalized line's raw XOF bytes to equal the seed-derived keyed-XOF — so the noise is no longer + /// grindable. 0 (free, unconstrained) off egress-pair rows. Witness. + pub byte_pair: T, +} + +/// Total number of committed NoiseStark columns. +pub const NUM_NOISE_COLUMNS: usize = size_of::>(); + +// 7 class (a) columns (incl. the two egress-pair known columns) + 49 original main columns + 1 +// BYTE_PAIR witness (the egress-pair binding, 6e-3c). +const _: () = assert!(NUM_NOISE_COLUMNS == 57); + +/// The NoiseStark AIR has no public inputs: `rank` enters only through the known `IS_PAD` +/// column and the trace height. +pub const NUM_NOISE_PUBLIC_INPUTS: usize = 0; + +columns_view!(NoiseColumnsView, NUM_NOISE_COLUMNS, NOISE_COL_MAP); + +/// Number of leading class (a) ("known") columns: `IS_PAD`, `IS_BLOCK_START`, `IS_BLOCK_FINAL`, +/// `GLOBAL_INDEX`, `OPERAND_MULT`, and the egress-pair `IS_EGRESS_PAIR` / `EGRESS_KEY` (6e-3c) — pure +/// functions of the geometry re-checked by the batch verifier against the trace openings. +pub const NUM_NOISE_KNOWN_COLUMNS: usize = NOISE_COL_MAP.egress_key + 1; + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_NOISE_COLUMNS] = NOISE_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + // The class (a) columns come first (their indices feed `preprocessed_indices`). + assert_eq!(NOISE_COL_MAP.is_pad, 0); + assert_eq!(NOISE_COL_MAP.is_block_start, 1); + assert_eq!(NOISE_COL_MAP.is_block_final, 2); + assert_eq!(NOISE_COL_MAP.global_index, 3); + assert_eq!(NOISE_COL_MAP.operand_mult, 4); + assert_eq!(NOISE_COL_MAP.is_egress_pair, 5); + assert_eq!(NOISE_COL_MAP.egress_key, 6); + assert_eq!(NUM_NOISE_KNOWN_COLUMNS, 7); + // BYTE_PAIR (the egress-pair limb witness) is the trailing column; ENTRY_FP16 just precedes it. + assert_eq!(NOISE_COL_MAP.byte_pair, NUM_NOISE_COLUMNS - 1); + assert_eq!(NOISE_COL_MAP.entry_fp16, NUM_NOISE_COLUMNS - 2); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_NOISE_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: NoiseColumnsView = arr.into(); + assert_eq!(view.is_pad, 1); + assert_eq!(view.norm_scaled, NOISE_COL_MAP.norm_scaled as u64 * 3 + 1); + let back: [u64; NUM_NOISE_COLUMNS] = view.into(); + assert_eq!(back, arr); + + let borrowed: &NoiseColumnsView = arr.borrow(); + assert_eq!(borrowed.entry_fp16, arr[NOISE_COL_MAP.entry_fp16]); + } +} diff --git a/zk-pow/src/circuit/fp16/noise_stark/ctl.rs b/zk-pow/src/circuit/fp16/noise_stark/ctl.rs new file mode 100644 index 000000000..f6d670607 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noise_stark/ctl.rs @@ -0,0 +1,291 @@ +//! Cross-table-lookup declarations for the FP16 NoiseStark. +//! +//! Two kinds of channel: +//! +//! * The **raw-byte** channel ([`ctl_noise_bytes_looking`]) exposes each live row's `BYTE` so a +//! later stage can CTL-bind it to the keyed-BLAKE3 XOF table (that binding is NOT implemented +//! here — this AIR takes the bytes as witness inputs and proves everything downstream). The +//! builder takes the table's batch index explicitly, exactly like +//! [`crate::circuit::fp16::xor_fold_stark::ctl`], because NoiseStark is not registered in +//! [`crate::circuit::fp16::ctl`]. +//! * The committed-LUT inventory ([`noise_lut_lookups`]): the RC16 limb/slack range checks, the +//! PAIR128 7-bit mantissa checks, and the POW2D shift lookups that make the integer isqrt and +//! the three ties-to-even BF16/FP16 rounding brackets sound. No new table is introduced — all +//! facts target the shared `RANGE16`, `PAIR128` and `POW2D` tables. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::NOISE_COL_MAP; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// The live-row filter `1 - IS_PAD`. +fn live_filter() -> Filter { + Filter::from_column(Column::linear_combination_with_constant( + [(NOISE_COL_MAP.is_pad, -F::ONE)], + F::ONE, + )) +} + +/// NoiseStark's looking half of the **raw-byte** channel: `(BYTE)` on every live row, filter +/// `1 - IS_PAD`. The counterparty (the keyed-BLAKE3 XOF commitment) is a later integration step; +/// the `noise_bytes_table` index is supplied then. +pub fn ctl_noise_bytes_looking(noise_bytes_table: usize) -> TableWithColumns { + TableWithColumns::new( + TableIdx::from(noise_bytes_table), + vec![Column::single(NOISE_COL_MAP.byte)], + live_filter(), + ) +} + +/// NoiseStark's **looked** half of the E/F-operand binding channel (increment 6e-2): per live row, +/// the tuple `(GLOBAL_INDEX, ENTRY_FP16)` — the global entry index `line * rank + entry` and the +/// proven normalized FP16 entry. The filter `OPERAND_MULT * (1 - IS_PAD)` supplies each entry with +/// the noise matmul's per-cell reuse multiplicity (an `E` entry is reused in `k` cells, an `F` entry +/// in `h`/`w`), so the looking side (the noise matmuls' operand codes, keyed `base + lane (+ offset)` +/// = `GLOBAL_INDEX`) multiset-balances. This makes the noise matmuls' `E`/`F` operands provably the +/// normalized noise lines this AIR derives — no longer free witness. +pub fn ctl_noise_operands_looked(table: usize) -> TableWithColumns { + let m = &NOISE_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + vec![Column::single(m.global_index), Column::single(m.entry_fp16)], + Filter::new( + vec![( + Column::single(m.operand_mult), + Column::linear_combination_with_constant([(m.is_pad, -F::ONE)], F::ONE), + )], + vec![], + ), + ) +} + +/// NoiseStark's **looked** half of the egress-pair channel (increment 6e-3c): per `IS_EGRESS_PAIR` +/// row, the tuple `(EGRESS_KEY, BYTE_PAIR)` — the little-endian 16-bit XOF limb keyed by +/// `line*16 + entry/2`. The looking side is the noise-BLAKE3 engine's output egress +/// ([`crate::circuit::fp16::blake3_fp16_stark::ctl::ctl_cv_egress_looking_blake3`]), whose line +/// compression `L` exports `cv_out` as 16 limbs on keys `L*16 .. L*16 + 16`. The multiset balance +/// forces NoiseStark's normalized line's raw XOF bytes to equal the seed-derived keyed-BLAKE3 XOF, so +/// the noise is no longer grindable through those bytes. +pub fn ctl_noise_egress_pair_looked(table: usize) -> TableWithColumns { + let m = &NOISE_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + vec![Column::single(m.egress_key), Column::single(m.byte_pair)], + Filter::from_column(Column::single(m.is_egress_pair)), + ) +} + +/// `x - 2^16 * hi` — the low 16-bit limb of a two-limb value (RC16 key). +fn low_limb(x: usize, hi: usize) -> Column { + Column::linear_combination([(x, F::ONE), (hi, -F::from_canonical_u64(1 << 16))]) +} + +/// NoiseStark's per-row committed-LUT inventory. +/// +/// * **RANGE16**: the sum/isqrt limbs and their canonicity caps, the three brackets' lower/upper +/// slacks (each proved `>= 0` by a two-limb RC16 split), the parity halves, and the FP16 +/// exponent window. +/// * **PAIR128**: the four 7-bit mantissa fields, paired two-per-lookup. +/// * **POW2D**: the `denom` shift `2^(DENOM_EXP - 134)`, the division shift +/// `2^(283 - DENOM_EXP - SCALE_EXP)`, and the per-entry multiply shift `2^gm`; each key domain +/// `[0, 19]` also proves the shift is in range. +pub fn noise_lut_lookups() -> Vec> { + let m = &NOISE_COL_MAP; + let one = F::ONE; + let neg = -F::ONE; + let two16 = F::from_canonical_u64(1 << 16); + let neg16 = -two16; + let live = live_filter::(); + let mut lu: Vec> = Vec::new(); + + // ---- S: sum-of-squares and isqrt limbs. ---- + // TOTAL_SUMSQ < 2^32. + lu.push(LutLookup::rc16(low_limb(m.total_sumsq, m.total_hi))); + lu.push(LutLookup::rc16(Column::single(m.total_hi))); + // NORM_SCALED (q) < 2^21: low limb, high limb, and the 2^11-scaled cap (high limb < 2^5). + lu.push(LutLookup::rc16(low_limb(m.norm_scaled, m.norm_scaled_hi))); + lu.push(LutLookup::rc16(Column::single(m.norm_scaled_hi))); + lu.push(LutLookup::rc16(Column::linear_combination([( + m.norm_scaled_hi, + F::from_canonical_u64(1 << 11), + )]))); + // ISQRT_REM, ISQRT_S2 < 2^22 (high limb < 2^6 via the 2^10-scaled cap). + for (val, hi) in [(m.isqrt_rem, m.isqrt_rem_hi), (m.isqrt_s2, m.isqrt_s2_hi)] { + lu.push(LutLookup::rc16(low_limb(val, hi))); + lu.push(LutLookup::rc16(Column::single(hi))); + lu.push(LutLookup::rc16(Column::linear_combination([(hi, F::from_canonical_u64(1 << 10))]))); + } + + // ---- D: denom bracket. Lower slack 4q - DENOM_BLO - DENOM_PARITY >= 0; upper slack + // DENOM_BHI - 4q - DENOM_PARITY >= 0 (each a two-limb RC16 split). ---- + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.norm_scaled, F::from_canonical_u64(4)), + (m.denom_blo, neg), + (m.denom_parity, neg), + (m.denom_sl_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.denom_sl_hi))); + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.denom_bhi, one), + (m.norm_scaled, -F::from_canonical_u64(4)), + (m.denom_parity, neg), + (m.denom_su_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.denom_su_hi))); + + // ---- V: division bracket. Lower slack DIV_POW - DIV_BLO - SCALE_PARITY >= 0; upper slack + // DIV_BHI - DIV_POW - SCALE_PARITY >= 0. ---- + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.div_pow, one), + (m.div_blo, neg), + (m.scale_parity, neg), + (m.div_sl_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.div_sl_hi))); + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.div_bhi, one), + (m.div_pow, neg), + (m.scale_parity, neg), + (m.div_su_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.div_su_hi))); + + // ---- E: multiply bracket. Lower slack 4P - ENTRY_BLO - ENTRY_PARITY >= 0; upper slack + // ENTRY_BHI - 4P - ENTRY_PARITY >= 0 (0 on pad rows -> in domain unfiltered). ---- + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.entry_prod, F::from_canonical_u64(4)), + (m.entry_blo, neg), + (m.entry_parity, neg), + (m.entry_sl_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.entry_sl_hi))); + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.entry_bhi, one), + (m.entry_prod, -F::from_canonical_u64(4)), + (m.entry_parity, neg), + (m.entry_su_hi, neg16), + ]))); + lu.push(LutLookup::rc16(Column::single(m.entry_su_hi))); + + // ---- Parity halves (two-sided parity splits). ---- + lu.push(LutLookup::rc16(Column::single(m.denom_half))); + lu.push(LutLookup::rc16(Column::single(m.scale_half))); + lu.push(LutLookup::rc16(Column::single(m.entry_half))); + + // ---- E: FP16 exponent window [1, 30] (filtered live; pad rows carry 0). ---- + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant([(m.entry_fp16_exp, one)], neg), + live.clone(), + )); + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant([(m.entry_fp16_exp, neg)], F::from_canonical_u64(30)), + live.clone(), + )); + + // ---- RANGE16 (7-bit mantissa pins): the four BF16 mantissa fields `< 128`, proved by the + // `col * 2^9 < 2^16` scaled range check (the FP16 batch commits no PAIR128 table; RANGE16 scaled + // by 9 is the exact 7-bit pin `circuit::fp16::row_scale_stark` uses). 0 on padding -> in domain. ---- + let scaled9 = |col: usize| Column::linear_combination([(col, F::from_canonical_u64(1 << 9))]); + lu.push(LutLookup::rc16(scaled9(m.mag_minus_1))); + lu.push(LutLookup::rc16(scaled9(m.denom_mant))); + lu.push(LutLookup::rc16(scaled9(m.scale_mant))); + lu.push(LutLookup::rc16(scaled9(m.entry_mant))); + + // ---- FP16POW2: the three shift lookups (the FP16 batch commits FP16POW2, value `2^min(key,26)`; + // every noise shift key is in `[0, 19] < 26`, so the value is exactly `2^key`). All live-filtered: + // on the trailing all-zero padding block the keys would be out of range (e.g. denom key `0-134`). ---- + // denom: key gd = DENOM_EXP - 134, value DENOM_POW. + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::linear_combination_with_constant( + [(m.denom_exp, one)], + -F::from_canonical_u64(134), + )], + values: vec![Column::single(m.denom_pow)], + filter: live.clone(), + }); + // division: key A = 283 - DENOM_EXP - SCALE_EXP, value DIV_POW. + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::linear_combination_with_constant( + [(m.denom_exp, neg), (m.scale_exp, neg)], + F::from_canonical_u64(283), + )], + values: vec![Column::single(m.div_pow)], + filter: live.clone(), + }); + // multiply: key gm = ENTRY_GM, value ENTRY_POW (filtered live). + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.entry_gm)], + values: vec![Column::single(m.entry_pow)], + filter: live, + }); + + lu +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::PrimeField64; + use starky::util::trace_rows_to_poly_values; + + use super::super::stark::NoiseProgram; + use super::*; + + type F = GoldilocksField; + + #[test] + fn noise_ctl_halves_are_well_formed() { + // The table index is supplied at batch-integration time; any placeholder is fine here. + ctl_noise_bytes_looking::(9); + } + + #[test] + fn noise_lut_inventory_matches_documented_counts() { + let lu = noise_lut_lookups::(); + let count = |t: LutTable| lu.iter().filter(|l| l.table == t).count(); + // The FP16 batch commits RANGE16 + FP16POW2 (no PAIR128/POW2D): RC16 x32 (incl. 4 scaled 7-bit + // mantissa pins), FP16POW2 x3. + assert_eq!(count(LutTable::Range16), 32); + assert_eq!(count(LutTable::Fp16Pow2), 3); + assert_eq!(count(LutTable::Pair128), 0); + assert_eq!(count(LutTable::Pow2D), 0); + assert_eq!(lu.len(), 35); + } + + /// Every committed-LUT key the honest trace presents lands in its table's domain (RANGE16 keys + /// `< 2^16`, FP16POW2 keys `in [0, 19]` with `value = 2^key`). Checked on the live rows (filtered + /// lookups are inactive on the padding rows). + #[test] + fn honest_lut_keys_are_in_domain() { + for (rank, _seed) in [(16usize, 2u64), (32, 8), (48, 44), (64, 70)] { + let program = NoiseProgram::new(rank); + let bytes: Vec = (0..rank).map(|i| ((i as u64 * 2654435761) >> 29) as u8 | 1).collect(); + let rows = program.generate_trace::(&bytes); + let polys = trace_rows_to_poly_values(rows.clone()); + let lu = noise_lut_lookups::(); + for lookup in &lu { + for r in 0..rank { + match lookup.table { + LutTable::Range16 => { + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k < 1 << 16, "RC16 key {k} out of range at row {r}"); + } + LutTable::Fp16Pow2 => { + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + let v = lookup.values[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k <= 19, "FP16POW2 key {k} out of range at row {r}"); + assert_eq!(v, 1 << k, "FP16POW2 value {v} != 2^{k} at row {r}"); + } + other => panic!("unexpected table {other:?}"), + } + } + } + } + } +} diff --git a/zk-pow/src/circuit/fp16/noise_stark/mod.rs b/zk-pow/src/circuit/fp16/noise_stark/mod.rs new file mode 100644 index 000000000..6f652f8d8 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noise_stark/mod.rs @@ -0,0 +1,23 @@ +//! FP16 noise-line normalization AIR: proves, in-AIR, the per-line normalization arithmetic that +//! the plaintext ground truth [`crate::api::fp16::noise`]'s `normalize_line` performs — the +//! signed byte decode, the sum of squares, the integer `isqrt`, the BF16 scale derivation +//! (`f32_to_bf16` of the integer norm, then `bf16_div` of the fixed `8192` numerator), and the +//! per-entry `bf16_mul` + FP16 cast. +//! +//! The `rank` raw XOF bytes enter as witness **input** columns; binding them to the +//! keyed-BLAKE3 XOF is a separate later stage (the [`ctl`]'s byte channel is the hook). All BF16 +//! roundings are proved with ties-to-even quarter-ulp *bracket* gadgets over the shared +//! `RANGE16`/`PAIR128`/`POW2D` committed LUTs — no new table is added. See [`stark`] for the +//! constraint groups and the documented soundness envelope. +//! +//! The FP16 analogue of the BF16-scale half of [`crate::circuit::fp8::scale_stark`], scoped to a +//! single noise line. Status: the AIR and its constraint/LUT tests are complete; wiring the byte +//! and LUT channels into the batch driver is a later increment (NoiseStark is a CTL party — +//! `requires_ctls` — so the batch driver is the only supported proving path). + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{NUM_NOISE_COLUMNS, NUM_NOISE_PUBLIC_INPUTS, NOISE_COL_MAP, NoiseColumnsView}; +pub use stark::{NoiseProgram, NoiseStark}; diff --git a/zk-pow/src/circuit/fp16/noise_stark/stark.rs b/zk-pow/src/circuit/fp16/noise_stark/stark.rs new file mode 100644 index 000000000..54c10d022 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noise_stark/stark.rs @@ -0,0 +1,998 @@ +//! Proves the FP16 noise-line **normalization** arithmetic of the plaintext ground truth +//! [`crate::api::fp16::noise`]'s `normalize_line`: given the `rank` raw XOF bytes of one line +//! (witness inputs — their binding to the keyed-BLAKE3 XOF is a separate later stage, to be +//! CTL-bound to the Blake3 table through [`super::ctl`]'s byte column), it proves +//! +//! ```text +//! x_i = (1 - 2*sign(b_i)) * ((b_i & 0x7F) + 1) // signed decode, |x_i| in [1,128] +//! S = sum_i x_i^2 +//! q = isqrt(S * INT_SQRT_PREC^2) // INT_SQRT_PREC = 32 +//! denom = f32_to_bf16(q) +//! numer = f32_to_bf16(NOISE_TARGET_NORM * 32) = 8192 // compile-time constant (2^13) +//! scale = bf16_div(numer, denom) +//! entry_i = f32_to_fp16(bf16_to_f32(bf16_mul(f32_to_bf16(x_i), scale))) +//! ``` +//! +//! # Constraint groups +//! +//! * **B** (decode): `SIGN_BIT` boolean, `BYTE = 128*SIGN_BIT + MAG_MINUS_1`, +//! `MAGNITUDE = (1 - IS_PAD)*(MAG_MINUS_1 + 1)`. +//! * **S** (sum of squares + isqrt): the prefix sum of `MAGNITUDE^2` chained into +//! `TOTAL_SUMSQ`, and the Euclidean square-root witness `q^2 + REM = 1024*S`, +//! `REM + S2 = 2q` (with `REM, S2 >= 0` delegated to the RC16 inventory), which pins +//! `q = isqrt(1024*S)`. +//! * **D** (`denom`): the boundary products `(4*M_DEN -/+ 2) * 2^gd` of the ties-to-even +//! round of the integer `q` to a normal BF16. The bracket inequalities themselves +//! (`B_LO*2^gd + odd <= 4q <= B_HI*2^gd - odd`) are the RC16 range facts on the two slacks, +//! and `2^gd` is a POW2D value — all declared in [`super::ctl`]. +//! * **V** (`scale`): the division bracket. Because `numer = 8192 = 2^13` is a constant power +//! of two, `scale = RNE(2^13 / denom)` reduces to the single power-of-two comparison +//! `(4*M_S - 2)*M_DEN + odd <= 2^A <= (4*M_S + 2)*M_DEN - odd` with `A = 283 - DENOM_EXP +//! - SCALE_EXP` (`283 = 2 + 13 + 2*134`). The AIR materializes the boundary products; the +//! inequalities are RC16 slacks and `2^A` is a POW2D value. +//! * **E** (per-entry multiply + FP16 cast): the exact product significand +//! `P = MAGNITUDE * M_S`, the ties-to-even round `(4*M_E -/+ 2)*2^gm` bracketing `4P`, and +//! the exact BF16 -> FP16 widening `entry = SIGN<<15 | (gm + SCALE_EXP - 112)<<10 | +//! 8*ENTRY_MANT`. +//! +//! The line-level groups S/D/V are replicated identically on every row (`TOTAL_SUMSQ` is held +//! constant by a transition constraint and pinned to the final prefix sum on the last row), so +//! every row re-proves the shared scale; group E is per-row and gated off on the padding rows. +//! +//! # Soundness envelope (documented, not proved here) +//! +//! * `norm_scaled >= 128` (equivalently the line has `rank >= 16`, so `1024*S >= 2^14`): the +//! `denom` round then has a nonnegative shift `gd = DENOM_EXP - 134 >= 0`, inside POW2D's +//! `[0, 19]` key domain. Every protocol line satisfies this (the peel rank is at least 16). +//! * Each `entry_i` is a **normal** FP16 value (biased exponent in `[1, 30]`), so the final +//! `bf16_to_f32 -> f32_to_fp16` cast is an exact widening (FP16's 10 mantissa bits subsume +//! BF16's 7). This holds for every in-scheme line (entry magnitudes stay in `[2^-7, 2^8]`). +//! The AIR enforces the exactness and the `[1, 30]` range; a line violating the envelope is +//! simply unprovable (and never traced, exactly as the sqrt/scale brackets of +//! [`crate::circuit::fp8::scale_stark`] treat their own rejected boundaries). +//! All three RNE brackets carry the full ties-to-even machinery — the mantissa parity split +//! *and* the binade-bottom (`IS_BOTTOM`) correction `+ bottom` on the lower boundary (mirroring +//! `circuit::fp8::scale_stark`'s sqrt bracket) — so each rounded mantissa is pinned to the +//! **unique** RNE result with no residual grinding freedom, including at power-of-two roundings. +//! Because every bracket's effective exponent is structurally `>= 2` (its POW2D / FP16-exp key +//! domain), the `IS_BOTTOM` flag is just `[mantissa == 0]` (an is-zero gadget), with no separate +//! `EXP >= 2` witness. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{NUM_NOISE_COLUMNS, NUM_NOISE_PUBLIC_INPUTS, NoiseColumnsView}; +use crate::api::fp16::dtype::f32_to_fp16; +use crate::api::fp8::compute::{bf16_div, bf16_mul}; +use crate::api::fp8::dtype::{bf16_to_f32, f32_to_bf16}; +use crate::api::fp8::quantization::NOISE_TARGET_NORM; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// The fixed-point precision factor carried through the integer isqrt (`INT_SQRT_PREC = 32`, +/// matching `crate::api::fp16::noise`). Its square `1024` scales the sum of squares. +const INT_SQRT_PREC_SQ: u64 = 32 * 32; + +/// BF16 unit offset: a finite BF16 is `M * 2^(E* - 134)` with `M = 128 + mantissa` for normals. +const BF16_EXP_UNIT: u64 = 134; + +/// The division-bracket key base `A = DIV_KEY_BASE - DENOM_EXP - SCALE_EXP`, where +/// `DIV_KEY_BASE = 2 + log2(numer) + 2*134 = 2 + 13 + 268 = 283`. Valid only because +/// `numer = 8192 = 2^13` is a power of two (asserted in [`NoiseProgram::new`]). +const DIV_KEY_BASE: u64 = 2 + 13 + 2 * BF16_EXP_UNIT; + +/// FP16 cast offset: the FP16 biased exponent of a normal entry is `E*(entry_bf16) - 112` +/// (`112 = 134 - 15 - 7`: BF16 unit, FP16 bias, FP16-minus-BF16 mantissa width). +const FP16_EXP_OFFSET: u64 = 112; + +/// Field inverse of a small integer, or zero when it is zero (the is-zero gadget's witness). +fn inv_f(x: u64) -> F { + if x == 0 { + F::ZERO + } else { + F::from_canonical_u64(x).inverse() + } +} + +/// The compile-time BF16 code of `numer = f32_to_bf16(NOISE_TARGET_NORM * INT_SQRT_PREC)`. +fn numer_code() -> u16 { + f32_to_bf16((NOISE_TARGET_NORM * 32.0) as f32).expect("8192 is representable in bf16") +} + +/// The committed noise geometry: the per-line `rank` (entries per line), the per-line reuse +/// multiplicities (one per line; their length is the line count), and the trace height (a power of +/// two covering `num_lines * rank`). The normalization identity is otherwise program-independent; +/// the multi-line structure (blocks laid end to end, mirroring +/// [`crate::circuit::fp16::row_scale_stark`]) lets one NoiseStark instance prove every noise line of +/// a tile — `E_A`, `F_A`, `E_B`, `F_B`. +#[derive(Clone, Debug)] +pub struct NoiseProgram { + /// Number of entries (raw XOF bytes) in each line (the noise rank `r`). + pub rank: usize, + /// Per-line noise-matmul reuse multiplicity (the `OPERAND_MULT` known column), one per line. Its + /// length is the line count. A standalone single-line program uses `[0]` (no CTL). + pub mults: Vec, + /// Trace height (a power of two `>= num_lines * rank`). + pub num_rows: usize, +} + +impl NoiseProgram { + /// Builds a single-line program padded to the next power of two (standalone / unit-test path). + /// The batch uses [`Self::with_lines`] to pin an on-ladder height and the real line layout. + pub fn new(rank: usize) -> Self { + Self::with_lines(rank, vec![0], rank.next_power_of_two().max(2)) + } + + /// Builds a multi-line program: `mults.len()` lines of `rank` entries each, at an explicit + /// `num_rows` height. Asserts the compile-time facts the AIR's constants bake in (`numer` is + /// `8192 = 2^13`, a power of two; `rank >= 1`). + pub fn with_lines(rank: usize, mults: Vec, num_rows: usize) -> Self { + assert!(rank >= 1, "a noise line has at least one entry"); + assert!(!mults.is_empty(), "at least one line"); + assert!(num_rows.is_power_of_two(), "trace height must be a power of two"); + assert!(num_rows >= mults.len() * rank, "trace height must cover every live block"); + let numer = numer_code(); + assert_eq!(numer, 0x4600, "numer is f32_to_bf16(8192)"); + assert_eq!(numer & 0x7F, 0, "numer must be a power of two for the division bracket"); + assert_eq!(u64::from(numer >> 7), 13 + 127, "numer exponent field is 140 (value 2^13)"); + Self { rank, mults, num_rows } + } + + /// Number of noise lines this program proves. + pub fn num_lines(&self) -> usize { + self.mults.len() + } + + /// Live rows: one per entry of every line. + pub fn live_rows(&self) -> usize { + self.num_lines() * self.rank + } + + /// Trace height. + pub fn num_rows(&self) -> usize { + self.num_rows + } + + /// The live-row -> `(is_pad, line, is_block_start, is_block_final)` schedule (a pure function of + /// the geometry; the trailing padding forms one block starting at the first padding row). + fn block_schedule(&self, i: usize) -> (bool, usize, bool, bool) { + let live = self.live_rows(); + let is_pad = i >= live; + let line = if is_pad { self.num_lines() - 1 } else { i / self.rank }; + let is_block_start = (!is_pad && i % self.rank == 0) || (is_pad && i == live); + let is_block_final = !is_pad && i % self.rank == self.rank - 1; + (is_pad, line, is_block_start, is_block_final) + } + + /// The class (a) ("known") columns (`IS_PAD`, `IS_BLOCK_START`, `IS_BLOCK_FINAL`, + /// `GLOBAL_INDEX`, `OPERAND_MULT`), pure functions of the geometry; bit-exact with + /// [`Self::generate_trace`]'s fill. + pub fn known_values(&self) -> Vec> { + let num_rows = self.num_rows(); + let live = self.live_rows(); + let rank = self.rank; + let (mut is_pad, mut bstart, mut bfinal, mut gidx, mut omult) = ( + Vec::with_capacity(num_rows), + Vec::with_capacity(num_rows), + Vec::with_capacity(num_rows), + Vec::with_capacity(num_rows), + Vec::with_capacity(num_rows), + ); + // ZK noise binding (6e-3c): the egress-pair filter/key. A pair opens on each even live entry + // whose successor is still in the line (`e+1 < rank`); its key is `GLOBAL_INDEX / 2 = + // line*16 + e/2`, matching the noise-BLAKE3 line compression's egress base `line*16`. + let (mut is_egress_pair, mut egress_key) = (Vec::with_capacity(num_rows), Vec::with_capacity(num_rows)); + for i in 0..num_rows { + let (p, line, bs, bf) = self.block_schedule(i); + is_pad.push(F::from_bool(p)); + bstart.push(F::from_bool(bs)); + bfinal.push(F::from_bool(bf)); + gidx.push(F::from_canonical_usize(if p { live - 1 } else { i })); + omult.push(F::from_canonical_u64(self.mults[line])); + let e = i % rank; + let pair = !p && e % 2 == 0 && e + 1 < rank; + is_egress_pair.push(F::from_bool(pair)); + egress_key.push(if pair { F::from_canonical_usize(i / 2) } else { F::ZERO }); + } + vec![ + PolynomialValues::new(is_pad), + PolynomialValues::new(bstart), + PolynomialValues::new(bfinal), + PolynomialValues::new(gidx), + PolynomialValues::new(omult), + PolynomialValues::new(is_egress_pair), + PolynomialValues::new(egress_key), + ] + } + + /// Generates the trace from `num_lines * rank` raw XOF bytes (the lines concatenated in order), + /// bit-exact with `crate::api::fp16::noise`'s `normalize_line` applied to each line. + pub fn generate_trace(&self, bytes: &[u8]) -> Vec<[F; NUM_NOISE_COLUMNS]> { + assert_eq!(bytes.len(), self.live_rows(), "one byte per live line entry"); + let num_rows = self.num_rows(); + let live = self.live_rows(); + let rank = self.rank; + + let mut rows: Vec<[F; NUM_NOISE_COLUMNS]> = Vec::with_capacity(num_rows); + rows.resize(num_rows, [F::ZERO; NUM_NOISE_COLUMNS]); + + for line in 0..self.num_lines() { + let line_bytes = &bytes[line * rank..(line + 1) * rank]; + let (scalars, scale_code, scale_exp, scale_mant) = line_scalars::(line_bytes); + let mut running: u64 = 0; + for e in 0..rank { + let i = line * rank + e; + let mut v = scalars; + let (_, _, bs, bf) = self.block_schedule(i); + v.is_pad = F::ZERO; + v.is_block_start = F::from_bool(bs); + v.is_block_final = F::from_bool(bf); + v.global_index = F::from_canonical_usize(i); + v.operand_mult = F::from_canonical_u64(self.mults[line]); + // ZK noise binding (6e-3c): open a two-byte XOF limb on even entries (successor in line). + if e % 2 == 0 && e + 1 < rank { + v.is_egress_pair = F::ONE; + v.egress_key = F::from_canonical_usize(i / 2); + v.byte_pair = F::from_canonical_u64(u64::from(line_bytes[e]) + 256 * u64::from(line_bytes[e + 1])); + } + fill_entry::(&mut v, line_bytes[e], scale_code, scale_exp, scale_mant); + let mag = u64::from(line_bytes[e] & 0x7F) + 1; + running += mag * mag; + v.running_sumsq = F::from_canonical_u64(running); + rows[i] = v.into(); + } + } + + // ---- Trailing padding: one block of all-zero rows, IS_PAD = 1. ---- + for i in live..num_rows { + let (_, _, bs, _) = self.block_schedule(i); + let mut v = NoiseColumnsView::::default(); + v.is_pad = F::ONE; + v.is_block_start = F::from_bool(bs); + v.global_index = F::from_canonical_usize(live - 1); + v.operand_mult = F::from_canonical_u64(*self.mults.last().unwrap()); + rows[i] = v.into(); + } + rows + } +} + +/// The line-level scalars (sum of squares, integer isqrt, and the BF16 scale derivation) of one +/// `rank`-byte noise line, as a partially-filled view with every scalar column set (the per-entry +/// decode/multiply columns are filled per row by [`fill_entry`]). Bit-exact with `normalize_line`. +fn line_scalars(bytes: &[u8]) -> (NoiseColumnsView, u16, u64, u64) { + let mut total: u64 = 0; + for &b in bytes { + let mag = u64::from(b & 0x7F) + 1; + total += mag * mag; + } + let x = total * INT_SQRT_PREC_SQ; + let q = x.isqrt(); + assert!(q >= 128, "envelope: norm_scaled >= 128 (rank >= 16); line out of provable scope"); + let rem = x - q * q; + let s2 = 2 * q - rem; + assert!(q < (1 << 21) && total < (1 << 32), "line magnitude out of range"); + + let denom_code = f32_to_bf16(q as f32).expect("q < 2^24 is representable in bf16"); + let scale_code = bf16_div(numer_code(), denom_code).expect("noise-line scale is finite"); + + let denom_exp = u64::from(denom_code >> 7); + let denom_mant = u64::from(denom_code & 0x7F); + let gd = denom_exp as i64 - BF16_EXP_UNIT as i64; + assert!((0..=19).contains(&gd), "denom shift gd out of POW2D domain"); + let denom_pow = 1u64 << gd; + let m_den = 128 + denom_mant; + let denom_bottom = u64::from(denom_mant == 0); + let denom_blo = (4 * m_den - 2 + denom_bottom) * denom_pow; + let denom_bhi = (4 * m_den + 2) * denom_pow; + let denom_parity = denom_mant & 1; + let denom_half = (denom_mant - denom_parity) / 2; + let denom_sl = 4 * q - denom_blo - denom_parity; + let denom_su = denom_bhi - (4 * q) - denom_parity; + + let scale_exp = u64::from(scale_code >> 7); + let scale_mant = u64::from(scale_code & 0x7F); + let a = DIV_KEY_BASE as i64 - denom_exp as i64 - scale_exp as i64; + assert!((0..=19).contains(&a), "division shift A out of POW2D domain"); + let div_pow = 1u64 << a; + let m_s = 128 + scale_mant; + let scale_bottom = u64::from(scale_mant == 0); + let div_blo = (4 * m_s - 2 + scale_bottom) * m_den; + let div_bhi = (4 * m_s + 2) * m_den; + let scale_parity = scale_mant & 1; + let scale_half = (scale_mant - scale_parity) / 2; + let div_sl = div_pow - div_blo - scale_parity; + let div_su = div_bhi - div_pow - scale_parity; + + let mut v = NoiseColumnsView::::default(); + v.total_sumsq = F::from_canonical_u64(total); + v.total_hi = F::from_canonical_u64(total >> 16); + v.norm_scaled = F::from_canonical_u64(q); + v.norm_scaled_hi = F::from_canonical_u64(q >> 16); + v.isqrt_rem = F::from_canonical_u64(rem); + v.isqrt_rem_hi = F::from_canonical_u64(rem >> 16); + v.isqrt_s2 = F::from_canonical_u64(s2); + v.isqrt_s2_hi = F::from_canonical_u64(s2 >> 16); + + v.denom_exp = F::from_canonical_u64(denom_exp); + v.denom_mant = F::from_canonical_u64(denom_mant); + v.denom_pow = F::from_canonical_u64(denom_pow); + v.denom_parity = F::from_canonical_u64(denom_parity); + v.denom_half = F::from_canonical_u64(denom_half); + v.denom_bottom = F::from_canonical_u64(denom_bottom); + v.denom_mant_inv = inv_f::(denom_mant); + v.denom_blo = F::from_canonical_u64(denom_blo); + v.denom_bhi = F::from_canonical_u64(denom_bhi); + v.denom_sl_hi = F::from_canonical_u64(denom_sl >> 16); + v.denom_su_hi = F::from_canonical_u64(denom_su >> 16); + + v.scale_exp = F::from_canonical_u64(scale_exp); + v.scale_mant = F::from_canonical_u64(scale_mant); + v.div_pow = F::from_canonical_u64(div_pow); + v.scale_parity = F::from_canonical_u64(scale_parity); + v.scale_half = F::from_canonical_u64(scale_half); + v.scale_bottom = F::from_canonical_u64(scale_bottom); + v.scale_mant_inv = inv_f::(scale_mant); + v.div_blo = F::from_canonical_u64(div_blo); + v.div_bhi = F::from_canonical_u64(div_bhi); + v.div_sl_hi = F::from_canonical_u64(div_sl >> 16); + v.div_su_hi = F::from_canonical_u64(div_su >> 16); + (v, scale_code, scale_exp, scale_mant) +} + +/// Fills the per-entry decode / multiply / FP16-cast columns of one live row from its raw byte and +/// the (already-derived) line scale. Bit-exact with `normalize_line`'s per-entry arithmetic. +fn fill_entry(v: &mut NoiseColumnsView, b: u8, scale_code: u16, scale_exp: u64, scale_mant: u64) { + let sign_bit = u64::from(b >> 7); + let mag_minus_1 = u64::from(b & 0x7F); + let mag = mag_minus_1 + 1; + v.byte = F::from_canonical_u64(u64::from(b)); + v.sign_bit = F::from_canonical_u64(sign_bit); + v.mag_minus_1 = F::from_canonical_u64(mag_minus_1); + v.magnitude = F::from_canonical_u64(mag); + + let m_s = 128 + scale_mant; + let x_i = (1 - 2 * sign_bit as i64) * mag as i64; + let xb = f32_to_bf16(x_i as f32).expect("|x_i| <= 128 is representable"); + let entry_bf16 = bf16_mul(xb, scale_code).expect("noise entry is finite"); + let entry_fp16 = f32_to_fp16(bf16_to_f32(entry_bf16)).expect("entry representable in FP16"); + + let entry_mant = u64::from(entry_bf16 & 0x7F); + let entry_exp_field = u64::from((entry_bf16 >> 7) & 0xFF); + assert!((1..=254).contains(&entry_exp_field), "entry_bf16 must be normal"); + let m_e = 128 + entry_mant; + let gm = entry_exp_field as i64 - scale_exp as i64; + assert!((0..=19).contains(&gm), "entry shift gm out of POW2D domain"); + let entry_pow = 1u64 << gm; + let prod = mag * m_s; + let entry_bottom = u64::from(entry_mant == 0); + let entry_blo = (4 * m_e - 2 + entry_bottom) * entry_pow; + let entry_bhi = (4 * m_e + 2) * entry_pow; + let entry_parity = entry_mant & 1; + let entry_half = (entry_mant - entry_parity) / 2; + let entry_sl = 4 * prod - entry_blo - entry_parity; + let entry_su = entry_bhi - 4 * prod - entry_parity; + + let fp16_exp = u64::from((entry_fp16 >> 10) & 0x1F); + assert_eq!(fp16_exp, entry_exp_field - FP16_EXP_OFFSET, "FP16 cast exponent relation (entry is FP16-normal)"); + assert_eq!( + u64::from(entry_fp16), + (sign_bit << 15) | (fp16_exp << 10) | (8 * entry_mant), + "FP16 cast is an exact widening" + ); + + v.entry_mant = F::from_canonical_u64(entry_mant); + v.entry_gm = F::from_canonical_u64(gm as u64); + v.entry_pow = F::from_canonical_u64(entry_pow); + v.entry_parity = F::from_canonical_u64(entry_parity); + v.entry_half = F::from_canonical_u64(entry_half); + v.entry_bottom = F::from_canonical_u64(entry_bottom); + v.entry_mant_inv = inv_f::(entry_mant); + v.entry_prod = F::from_canonical_u64(prod); + v.entry_blo = F::from_canonical_u64(entry_blo); + v.entry_bhi = F::from_canonical_u64(entry_bhi); + v.entry_sl_hi = F::from_canonical_u64(entry_sl >> 16); + v.entry_su_hi = F::from_canonical_u64(entry_su >> 16); + v.entry_fp16_exp = F::from_canonical_u64(fp16_exp); + v.entry_fp16 = F::from_canonical_u64(u64::from(entry_fp16)); +} + +/// Evaluates the B/S/D/V/E constraint groups (module docs). All range facts (the RC16 limb +/// inventory, the bracket slacks, the POW2D shifts, the PAIR128 mantissa checks) are declared in +/// [`super::ctl`], not here. +pub(crate) fn eval_noise_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv_arr: &[V; NUM_NOISE_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &NoiseColumnsView = lv_arr.borrow(); + let nv_arr: &[V; NUM_NOISE_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let nv: &NoiseColumnsView = nv_arr.borrow(); + + let one = eval.u64(1); + let two = eval.u64(2); + let c128 = eval.u64(128); + let live = eval.sub(one, lv.is_pad); + + // ---- B: signed byte decode. ---- + eval.constraint_bool(lv.sign_bit); + let s128 = eval.mul(c128, lv.sign_bit); + let byte_expr = eval.add(s128, lv.mag_minus_1); + eval.constraint_eq(lv.byte, byte_expr); + let mag_p1 = eval.add(lv.mag_minus_1, one); + let mag_expr = eval.mul(live, mag_p1); + eval.constraint_eq(lv.magnitude, mag_expr); + + // ---- Multi-block structure (mirrors row_scale_stark): every noise line is a `rank`-row block + // laid end to end, the final block being trailing all-zero padding. ---- + eval.constraint_bool(lv.is_block_start); + eval.constraint_bool(lv.is_block_final); + let not_bs_next = eval.sub(one, nv.is_block_start); + + // ---- S: prefix sum of MAGNITUDE^2 and the Euclidean isqrt, PER BLOCK. ---- + // Reset at each block start: running = x_0^2. + let sq0 = eval.mul(lv.magnitude, lv.magnitude); + let reset = eval.sub(lv.running_sumsq, sq0); + let c = eval.mul(lv.is_block_start, reset); + eval.constraint(c); + // Within-block step (nv NOT a block start): running_{i+1} = running_i + x_{i+1}^2. + let sqn = eval.mul(nv.magnitude, nv.magnitude); + let step = eval.sub(nv.running_sumsq, lv.running_sumsq); + let step = eval.sub(step, sqn); + let c = eval.mul(not_bs_next, step); + eval.constraint_transition(c); + // On each LIVE block's final row, running = that block's TOTAL_SUMSQ. + let last = eval.sub(lv.running_sumsq, lv.total_sumsq); + let c = eval.mul(lv.is_block_final, last); + eval.constraint(c); + // Line scalars (TOTAL_SUMSQ .. DIV_SU_HI) are constant within a block (may jump at a block start). + { + let scalar_start = super::columns::NOISE_COL_MAP.total_sumsq; + let scalar_end = super::columns::NOISE_COL_MAP.div_su_hi; + for i in scalar_start..=scalar_end { + let d = eval.sub(nv_arr[i], lv_arr[i]); + let c = eval.mul(not_bs_next, d); + eval.constraint_transition(c); + } + } + // q^2 + REM = 1024 * S. + let q2 = eval.mul(lv.norm_scaled, lv.norm_scaled); + let lhs = eval.add(q2, lv.isqrt_rem); + let sqprec = eval.u64(INT_SQRT_PREC_SQ); + let x = eval.mul(sqprec, lv.total_sumsq); + eval.constraint_eq(lhs, x); + // REM + S2 = 2q. + let rem_s2 = eval.add(lv.isqrt_rem, lv.isqrt_s2); + let two_q = eval.mul(two, lv.norm_scaled); + eval.constraint_eq(rem_s2, two_q); + + // ---- D: denom boundary products, parity split, and binade-bottom flag. The bracket uses + // DENOM_POW as its factor (0 on pad rows -> products vanish), so it needs no live gate; the + // is-zero gadget is gated off on pad rows (zero mantissa + zero inverse would otherwise fail). ---- + bracket_boundary_affine(eval, lv.denom_mant, lv.denom_bottom, lv.denom_pow, lv.denom_blo, lv.denom_bhi); + parity_split(eval, lv.denom_mant, lv.denom_half, lv.denom_parity); + is_zero_flag(eval, lv.denom_mant, lv.denom_mant_inv, lv.denom_bottom, live); + + // ---- V: division boundary products ((4*M_S -/+ 2 + bottom) * M_DEN), parity, bottom. The + // factor M_DEN = 128 + DENOM_MANT is >= 128 even on pad rows, so the bracket equalities are live- + // gated (DIV_BLO/DIV_BHI are 0 on pad rows). ---- + let m_den = eval.add(c128, lv.denom_mant); + bracket_boundary_affine_gated(eval, lv.scale_mant, lv.scale_bottom, m_den, lv.div_blo, lv.div_bhi, live); + parity_split(eval, lv.scale_mant, lv.scale_half, lv.scale_parity); + is_zero_flag(eval, lv.scale_mant, lv.scale_mant_inv, lv.scale_bottom, live); + + // ---- E: per-entry exact product, multiply bracket, FP16 cast. ---- + // Exact product significand P = MAGNITUDE * M_S (0 on pad rows: MAGNITUDE = 0). + let m_s = eval.add(c128, lv.scale_mant); + let prod = eval.mul(lv.magnitude, m_s); + eval.constraint_eq(lv.entry_prod, prod); + bracket_boundary_affine(eval, lv.entry_mant, lv.entry_bottom, lv.entry_pow, lv.entry_blo, lv.entry_bhi); + parity_split(eval, lv.entry_mant, lv.entry_half, lv.entry_parity); + // The entry binade-bottom is-zero gadget is gated off on pad rows (zero mantissa there). + is_zero_flag(eval, lv.entry_mant, lv.entry_mant_inv, lv.entry_bottom, live); + // FP16 biased exponent = gm + SCALE_EXP - 112 (gated: pad rows carry 0). + let fp_exp_sum = eval.add(lv.entry_gm, lv.scale_exp); + let offset = eval.u64(FP16_EXP_OFFSET); + let fp_exp = eval.sub(fp_exp_sum, offset); + let fp_exp_diff = eval.sub(lv.entry_fp16_exp, fp_exp); + let fp_exp_gated = eval.mul(live, fp_exp_diff); + eval.constraint(fp_exp_gated); + // FP16 code = SIGN<<15 | FP16_EXP<<10 | 8*ENTRY_MANT (pad rows: all zero -> 0). + let c_sign = eval.u64(1 << 15); + let c_exp = eval.u64(1 << 10); + let c_eight = eval.u64(8); + let sign_hi = eval.mul(c_sign, lv.sign_bit); + let exp_hi = eval.mul(c_exp, lv.entry_fp16_exp); + let mant8 = eval.mul(c_eight, lv.entry_mant); + let fp16 = eval.add(sign_hi, exp_hi); + let fp16 = eval.add(fp16, mant8); + eval.constraint_eq(lv.entry_fp16, fp16); + + // ---- ZK noise binding (6e-3c): the egress-pair limb. On IS_EGRESS_PAIR rows (even live entries), + // BYTE_PAIR = BYTE + 2^8 * BYTE' (this row's byte and the next row's byte), so the egress-pair + // channel can export the little-endian 16-bit XOF limb against the noise-BLAKE3 cv_out limbs. Degree + // 2 (flag * linear); off egress-pair rows the flag is 0 and BYTE_PAIR is free (unconstrained, and + // unread by the channel). Transition form: IS_EGRESS_PAIR is 0 on the trailing padding, so the + // last-row wrap never activates it. ---- + let c256 = eval.u64(256); + let hi_byte = eval.mul(c256, nv.byte); + let pair_expr = eval.add(lv.byte, hi_byte); + let pair_diff = eval.sub(lv.byte_pair, pair_expr); + let pair_c = eval.mul(lv.is_egress_pair, pair_diff); + eval.constraint_transition(pair_c); +} + +/// Materializes the ties-to-even quarter-ulp boundary products for a round whose scale factor is +/// a committed power of two `pow`: `blo = (4*(128 + mant) - 2 + bottom)*pow`, `bhi = (4*(128 + +/// mant) + 2)*pow`. (`4*(128 + mant) = 512 + 4*mant`, so `blo` uses `510 + 4*mant + bottom` and +/// `bhi` `514 + 4*mant`.) The `+ bottom` term is the binade-bottom (`IS_BOTTOM`) correction: +/// at a power of two (`mant = 0`) the predecessor sits one quarter ulp below, so the lower +/// acceptance boundary is `-ulp/4`, not `-ulp/2` — this is what pins each rounded mantissa to +/// the UNIQUE ties-to-even result (mirrors `circuit::fp8::scale_stark`'s sqrt bracket). +fn bracket_boundary_affine(eval: &mut E, mant: V, bottom: V, pow: V, blo: V, bhi: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let c4 = eval.u64(4); + let c510 = eval.u64(510); + let c514 = eval.u64(514); + let four_mant = eval.mul(c4, mant); + let coef_lo_base = eval.add(c510, four_mant); + let coef_lo = eval.add(coef_lo_base, bottom); + let coef_hi = eval.add(c514, four_mant); + let blo_e = eval.mul(coef_lo, pow); + let bhi_e = eval.mul(coef_hi, pow); + eval.constraint_eq(blo, blo_e); + eval.constraint_eq(bhi, bhi_e); +} + +/// Like [`bracket_boundary_affine`] but multiplies both boundary equalities by `gate` (used by the +/// division bracket, whose factor `M_DEN >= 128` stays nonzero on pad rows, so the boundary products +/// must be switched off there rather than vanishing through a zero factor). +fn bracket_boundary_affine_gated(eval: &mut E, mant: V, bottom: V, factor: V, blo: V, bhi: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let c4 = eval.u64(4); + let c510 = eval.u64(510); + let c514 = eval.u64(514); + let four_mant = eval.mul(c4, mant); + let coef_lo_base = eval.add(c510, four_mant); + let coef_lo = eval.add(coef_lo_base, bottom); + let coef_hi = eval.add(c514, four_mant); + let blo_e = eval.mul(coef_lo, factor); + let bhi_e = eval.mul(coef_hi, factor); + let d_lo = eval.sub(blo, blo_e); + let c = eval.mul(gate, d_lo); + eval.constraint(c); + let d_hi = eval.sub(bhi, bhi_e); + let c = eval.mul(gate, d_hi); + eval.constraint(c); +} + +/// Pins `flag = [mant == 0]` (the binade-bottom flag): `flag` boolean, `flag*mant = 0` (so +/// `flag = 1 => mant = 0`), and `mant*mant_inv = 1 - flag` (so `mant != 0 => flag = 0`, and +/// `mant = 0 => flag = 1`). The effective exponent is `>= 2` throughout (POW2D/FP16-exp +/// domains), so no separate `EXP >= 2` witness is needed — unlike `scale_stark`, whose sqrt +/// claim may be subnormal. `gate` multiplies every constraint (pass `one` to leave it on, or the +/// live filter to switch it off on pad rows). +fn is_zero_flag(eval: &mut E, mant: V, mant_inv: V, flag: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + let f2 = eval.mul(flag, flag); + let fb = eval.sub(f2, flag); + let c = eval.mul(gate, fb); + eval.constraint(c); + let fm = eval.mul(flag, mant); + let c = eval.mul(gate, fm); + eval.constraint(c); + let mi = eval.mul(mant, mant_inv); + let omf = eval.sub(one, flag); + let d = eval.sub(mi, omf); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `mant = 2*half + parity` with `parity` boolean (the ties-to-even parity split; `half` is +/// RC16'd in `ctl.rs` so the split is two-sided). +fn parity_split(eval: &mut E, mant: V, half: V, parity: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + eval.constraint_bool(parity); + let c2 = eval.u64(2); + let two_half = eval.mul(c2, half); + let recomposed = eval.add(two_half, parity); + eval.constraint_eq(mant, recomposed); +} + +/// FP16 NoiseStark. A CTL party of the FP16 batch (`requires_ctls()`): the byte column is +/// CTL-bound to the keyed-BLAKE3 XOF table and the range/shift facts to the committed LUTs +/// (declared in [`super::ctl`]), so the batch driver is the only supported proving path. +#[derive(Clone, Debug)] +pub struct NoiseStark, const D: usize> { + pub program: NoiseProgram, + _phantom: PhantomData, +} + +impl, const D: usize> NoiseStark { + pub fn new(program: NoiseProgram) -> Self { + Self { + program, + _phantom: PhantomData, + } + } +} + +impl, const D: usize> Stark for NoiseStark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_NOISE_COLUMNS, NUM_NOISE_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_noise_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_noise_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + + use super::super::columns::NOISE_COL_MAP; + use super::*; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type Stk = NoiseStark; + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + /// A deterministic pseudo-random byte line (never all-tiny, so `norm_scaled >= 128`). + fn sample_bytes(rank: usize, seed: u64) -> Vec { + let mut s = seed.wrapping_add(0x9E3779B97F4A7C15); + (0..rank) + .map(|_| { + s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + (s >> 33) as u8 + }) + .collect() + } + + fn trace(rank: usize, seed: u64) -> (NoiseProgram, Vec<[F; NUM_NOISE_COLUMNS]>, Vec) { + let program = NoiseProgram::new(rank); + let bytes = sample_bytes(rank, seed); + let rows = program.generate_trace::(&bytes); + (program, rows, bytes) + } + + fn constraints_violated(stark: &Stk, rows: &[[F; NUM_NOISE_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().iter().any(|&acc| acc != F::ZERO) + }) + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + for (rank, seed) in [(16usize, 1u64), (32, 7), (48, 99), (64, 123)] { + let (program, rows, _) = trace(rank, seed); + assert_eq!(rows.len(), rank.next_power_of_two().max(2)); + // Known columns are bit-exact with the trace fill. + let known = program.known_values::(); + assert_eq!(known.len(), 7); + for (r, row) in rows.iter().enumerate() { + assert_eq!(known[0].values[r], row[NOISE_COL_MAP.is_pad], "is_pad row {r}"); + assert_eq!(known[1].values[r], row[NOISE_COL_MAP.is_block_start], "is_block_start row {r}"); + assert_eq!(known[2].values[r], row[NOISE_COL_MAP.is_block_final], "is_block_final row {r}"); + assert_eq!(known[3].values[r], row[NOISE_COL_MAP.global_index], "global_index row {r}"); + assert_eq!(known[4].values[r], row[NOISE_COL_MAP.operand_mult], "operand_mult row {r}"); + assert_eq!(known[5].values[r], row[NOISE_COL_MAP.is_egress_pair], "is_egress_pair row {r}"); + assert_eq!(known[6].values[r], row[NOISE_COL_MAP.egress_key], "egress_key row {r}"); + } + assert!( + !constraints_violated(&Stk::new(program), &rows), + "rank {rank} seed {seed} honest trace violated a constraint" + ); + } + } + + /// Bit-exact against the real `normalize_line` (reached through the pub(crate) + /// `sample_line`): reconstruct the same keyed-BLAKE3 XOF bytes the reference consumes, feed + /// them to `generate_trace`, and compare the per-entry FP16 output to the reference line. + #[test] + fn trace_is_bit_exact_vs_normalize_line() { + use crate::api::fp16::noise::{NoiseFactor, Side, sample_line, subkey}; + + const LABEL_NOISE_LINE: &[u8] = b"pearl/v4/FP16/noise-line"; + for (rank, seed_byte) in [(16u16, 4u8), (32, 3), (48, 17), (64, 200)] { + let seed = [seed_byte; 32]; + let line = 5u32; + let reference = sample_line(&seed, Side::A, NoiseFactor::E, line, rank); + + // Reconstruct the raw XOF bytes `normalize_line` was applied to. + let key = subkey(LABEL_NOISE_LINE, Some(&seed)); + let mut material = vec![Side::A as u8, NoiseFactor::E as u8]; + material.extend_from_slice(&line.to_le_bytes()); + material.resize(64, 0); + let mut bytes = vec![0u8; usize::from(rank)]; + let mut hasher = blake3::Hasher::new_keyed(&key); + hasher.update(&material); + hasher.finalize_xof().fill(&mut bytes); + + let program = NoiseProgram::new(usize::from(rank)); + let rows = program.generate_trace::(&bytes); + let mine: Vec = rows + .iter() + .take(usize::from(rank)) + .map(|row| { + let v: &NoiseColumnsView = row.borrow(); + to_u64(v.entry_fp16) as u16 + }) + .collect(); + assert_eq!(mine, reference, "FP16 line mismatch at rank {rank}"); + } + } + + /// Multi-line: a NoiseStark instance proving several lines end to end is bit-exact with + /// `sample_line` per line, its known columns match the fill, and the whole trace satisfies every + /// constraint (per-block prefix-sum reset, scalar constancy, trailing padding). + #[test] + fn multi_line_trace_is_bit_exact_and_satisfies_constraints() { + use crate::api::fp16::noise::{NoiseFactor, Side, sample_line, subkey}; + const LABEL_NOISE_LINE: &[u8] = b"pearl/v4/FP16/noise-line"; + let rank = 32u16; + let seed = [0x5au8; 32]; + + // Reconstruct the raw XOF bytes of one line (the free-witness bytes NoiseStark consumes). + let xof = |side: Side, factor: NoiseFactor, line: u32| -> Vec { + let key = subkey(LABEL_NOISE_LINE, Some(&seed)); + let mut material = vec![side as u8, factor as u8]; + material.extend_from_slice(&line.to_le_bytes()); + material.resize(64, 0); + let mut bytes = vec![0u8; usize::from(rank)]; + let mut hasher = blake3::Hasher::new_keyed(&key); + hasher.update(&material); + hasher.finalize_xof().fill(&mut bytes); + bytes + }; + + // Four lines with distinct addresses, each with its own multiplicity. `Side`/`NoiseFactor` + // are not `Copy`, so a fresh pair is built per line from the byte discriminants. + let addr = |which: u8| -> (Side, NoiseFactor) { + match which { + 0 => (Side::A, NoiseFactor::E), + 1 => (Side::A, NoiseFactor::F), + 2 => (Side::B, NoiseFactor::E), + _ => (Side::B, NoiseFactor::F), + } + }; + let specs = [(0u8, 0u32, 3u64), (1, 1, 2), (2, 2, 3), (3, 0, 4)]; + let mut bytes: Vec = Vec::new(); + let mut refs: Vec> = Vec::new(); + let mut mults: Vec = Vec::new(); + for &(which, line, mult) in &specs { + let (s, f) = addr(which); + bytes.extend_from_slice(&xof(s, f, line)); + let (s, f) = addr(which); + refs.push(sample_line(&seed, s, f, line, rank)); + mults.push(mult); + } + // Height padded off the live rows (4 lines * 32 = 128 -> 256 here for a padding block). + let num_rows = 256usize; + let program = NoiseProgram::with_lines(usize::from(rank), mults.clone(), num_rows); + let rows = program.generate_trace::(&bytes); + assert_eq!(rows.len(), num_rows); + + // Per-line bit-exactness. + for (l, reference) in refs.iter().enumerate() { + let mine: Vec = (0..rank as usize) + .map(|e| { + let v: &NoiseColumnsView = rows[l * rank as usize + e].borrow(); + to_u64(v.entry_fp16) as u16 + }) + .collect(); + assert_eq!(&mine, reference, "line {l} mismatch"); + } + + // Known columns match the fill (incl. GLOBAL_INDEX and OPERAND_MULT). + let known = program.known_values::(); + for (r, row) in rows.iter().enumerate() { + assert_eq!(known[3].values[r], row[NOISE_COL_MAP.global_index], "global_index row {r}"); + assert_eq!(known[4].values[r], row[NOISE_COL_MAP.operand_mult], "operand_mult row {r}"); + } + // GLOBAL_INDEX is the live row index; OPERAND_MULT is the line's multiplicity. + for (l, &mult) in mults.iter().enumerate() { + let v: &NoiseColumnsView = rows[l * rank as usize].borrow(); + assert_eq!(to_u64(v.global_index), (l * rank as usize) as u64); + assert_eq!(to_u64(v.operand_mult), mult); + } + + assert!(!constraints_violated(&Stk::new(program), &rows), "multi-line honest trace violated a constraint"); + } + + #[test] + fn padded_trace_known_column_matches_fill() { + // A non-power-of-two rank (48 -> 64): pad rows carry IS_PAD = 1 and zero entry columns. + let (program, rows, _) = trace(48, 321); + assert_eq!(rows.len(), 64); + for (r, row) in rows.iter().enumerate() { + let v: &NoiseColumnsView = row.borrow(); + if r >= 48 { + assert_eq!(v.is_pad, F::ONE); + assert_eq!(v.entry_fp16, F::ZERO, "pad entry {r}"); + assert_eq!(v.magnitude, F::ZERO, "pad magnitude {r}"); + } else { + assert_eq!(v.is_pad, F::ZERO); + } + } + assert!(!constraints_violated(&Stk::new(program), &rows)); + } + + #[test] + fn tampered_traces_fail() { + let (program, rows, _) = trace(32, 55); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "baseline honest trace must pass"); + let cases = [ + ("byte", NOISE_COL_MAP.byte), + ("sign_bit", NOISE_COL_MAP.sign_bit), + ("magnitude", NOISE_COL_MAP.magnitude), + ("running_sumsq", NOISE_COL_MAP.running_sumsq), + ("total_sumsq", NOISE_COL_MAP.total_sumsq), + ("norm_scaled", NOISE_COL_MAP.norm_scaled), + ("isqrt_rem", NOISE_COL_MAP.isqrt_rem), + ("denom_blo", NOISE_COL_MAP.denom_blo), + ("div_blo", NOISE_COL_MAP.div_blo), + ("entry_prod", NOISE_COL_MAP.entry_prod), + ("entry_blo", NOISE_COL_MAP.entry_blo), + ("entry_fp16_exp", NOISE_COL_MAP.entry_fp16_exp), + ("entry_fp16", NOISE_COL_MAP.entry_fp16), + ]; + for (name, col) in cases { + let mut forged = rows.clone(); + // Row 0 is a live row with nonzero entry; tamper there. + forged[0][col] += F::ONE; + assert!(constraints_violated(&stark, &forged), "{name} tamper undetected"); + } + } + + /// Binade-bottom uniqueness: at a power-of-two rounding the former (relaxed) witness — the one + /// using the half-ulp lower boundary `(4*M - 2)*factor` without the `+IS_BOTTOM` correction, + /// i.e. differing from the true boundary by exactly the former quarter-ulp slack — must now be + /// REJECTED by the AIR, while the honest (corrected) trace still passes. + /// + /// The line `byte = 31` (magnitude 32, `rank = 1`) makes `q = 1024`, so `denom = 1024`, + /// `scale = 8`, and every `entry = 256` are all exact powers of two: all three brackets hit + /// their binade bottom at once (`*_BOTTOM = 1`, `*_MANT = 0`). + #[test] + fn binade_bottom_correction_pins_the_rounding() { + let program = NoiseProgram::new(1); + let bytes = vec![31u8]; + let rows = program.generate_trace::(&bytes); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "honest power-of-two trace must pass"); + + // Test premise: row 0 is at the binade bottom of all three brackets. + let v: &NoiseColumnsView = rows[0].borrow(); + assert_eq!(v.denom_bottom, F::ONE, "denom is a power of two"); + assert_eq!(v.scale_bottom, F::ONE, "scale is a power of two"); + assert_eq!(v.entry_bottom, F::ONE, "entry is a power of two"); + + // (a) Reverting each lower boundary product to the uncorrected `(4*M - 2)*factor` value + // (subtract one `factor`, since corrected = uncorrected + 1*factor at the bottom) is the + // "former quarter-ulp" witness; the AIR's `blo = (... + bottom)*factor` now rejects it. + let denom_factor = v.denom_pow; // denom bracket factor = 2^gd + let div_factor = F::from_canonical_u64(128) + v.denom_mant; // division factor = M_DEN + let entry_factor = v.entry_pow; // multiply bracket factor = 2^gm + for (name, blo_col, factor) in [ + ("denom_blo", NOISE_COL_MAP.denom_blo, denom_factor), + ("div_blo", NOISE_COL_MAP.div_blo, div_factor), + ("entry_blo", NOISE_COL_MAP.entry_blo, entry_factor), + ] { + let mut forged = rows.clone(); + forged[0][blo_col] -= factor; + assert!( + constraints_violated(&stark, &forged), + "{name}: uncorrected (half-ulp) lower boundary must be rejected" + ); + } + + // (b) The correction flag itself is pinned: clearing any `*_BOTTOM` at a power of two + // violates the is-zero gadget (mant = 0 forces the flag to 1). + for (name, flag_col) in [ + ("denom_bottom", NOISE_COL_MAP.denom_bottom), + ("scale_bottom", NOISE_COL_MAP.scale_bottom), + ("entry_bottom", NOISE_COL_MAP.entry_bottom), + ] { + let mut forged = rows.clone(); + forged[0][flag_col] = F::ZERO; + assert!(constraints_violated(&stark, &forged), "{name}: flag must stay pinned to 1"); + } + } + + #[test] + fn degree_is_at_most_three() { + let (program, _, _) = trace(32, 1); + test_stark_low_degree::(Stk::new(program)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + let (program, _, _) = trace(32, 1); + test_stark_circuit_constraints::(Stk::new(program)).unwrap(); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/columns.rs b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/columns.rs new file mode 100644 index 000000000..aab1c0de1 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/columns.rs @@ -0,0 +1,280 @@ +//! Fixed trace layout for the FP16 single-rounding FMA AIR (group G2 of the fused noisy +//! quantization). +//! +//! One row per operand element `(i, j)`. The AIR proves `noised = fma(af, X, t)` bit-exact vs the +//! Rust `af.mul_add(fp16_to_f32(raw), t)`, where `af = bf16_to_f32(alpha)`, `X = fp16_to_f32(raw)`, +//! and `t` is group G1's output (`t = RNE_f32(bf*N)`, carried in as `(T_SIGN, T_MANT, T_EXP)`). It +//! is a signed, arbitrarily-aligned add of the exact product `af*X` and `t` with a SINGLE f32 +//! round-to-nearest-ties-to-even, including cancellation. The result `noised` is produced as an +//! f32 and exposed (two limbs + decoded fields) to bind to the cast stage (group G3) and the FMA +//! hook of [`crate::circuit::fp16::noisy_quant_stark`]. +//! +//! The windowing mirrors the A100 accumulation AIR +//! ([`crate::circuit::fp16::matmul_a100_stark`]): both addends are normalized to 24-bit +//! significands, aligned onto a common `2^(eta-26)` grid (`eta` = the max value-MSB, FP16POW2 +//! shifts, Euclidean floors with a far-gap sticky), summed with sign, then renormalized into +//! `[2^23, 2^24)` (WIDTH32) and rounded once (RNE) with the exact quarter-ulp bracket / IS_BOTTOM +//! / is-zero technique. See [`super::stark`] for the constraint groups and the soundness envelope. +//! +//! [`FmaColumnsView`] is `#[repr(C)]`; declaration order is committed column order. + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one `NoisyQuantFmaStark` trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct FmaColumnsView { + // ------------------------------------------------------------------------------------------ + // Class (a) ("known"). + // ------------------------------------------------------------------------------------------ + /// 1 on trailing padding rows. + pub is_pad: T, + + // ------------------------------------------------------------------------------------------ + // Inputs (CTL-bound to upstream stages later; decoded here). + // ------------------------------------------------------------------------------------------ + /// The clean-operand scale `alpha` (BF16 code). + pub alpha: T, + /// BF16 exponent field of `alpha`. + pub alpha_exp: T, + /// BF16 mantissa field of `alpha` (`M_a = 128 + ALPHA_MANT`). + pub alpha_mant: T, + /// The clean FP16 operand code `X`. + pub raw: T, + /// FP16DECODE value 0: integer significand `M_x in [0, 2047]`. + pub x_sig: T, + /// FP16DECODE value 1: raw sign bit of `X`. + pub x_sign: T, + /// FP16DECODE value 2: biased stored exponent `eps + 15 in [1, 30]`. + pub x_eps_biased: T, + /// FP16DECODE value 3: `[M_x == 0]`. + pub x_is_zero: T, + /// `t` sign bit (from G1: `= NOISE_SIGN`). + pub t_sign: T, + /// `t` significand `M_t in [2^23, 2^24)` (from G1), or 0 when `t = 0`. + pub t_mant: T, + /// `t` f32 exponent field (from G1). + pub t_exp: T, + /// `[M_t == 0]` (t is zero). + pub t_is_zero: T, + /// Inverse witness for the `[M_t == 0]` is-zero gadget. + pub t_mant_inv: T, + + // ------------------------------------------------------------------------------------------ + // Exact product P = af*X significand + 24-bit normalization. + // ------------------------------------------------------------------------------------------ + /// `P_IS_ZERO = X_IS_ZERO` (the product is zero iff `X` is zero; `af` is always nonzero). + pub p_is_zero: T, + /// Exact product significand `Mp = M_a * M_x < 2^19`. + pub mp: T, + /// Bit-width `b_p = bitlen(Mp) in [1, 19]` (WIDTH32 key; filtered to nonzero-P rows). + pub bp: T, + /// WIDTH32 value `2^max(b_p-24, 0) = 1`. + pub trunc_p: T, + /// WIDTH32 value `2^max(24-b_p, 0) = 2^(24-b_p)`. + pub lift_p: T, + /// Normalized product significand `Mp_norm = Mp * 2^(24-b_p) in [2^23, 2^24)` (0 when P zero). + pub mp_norm: T, + /// Low 16-bit limb of `Mp_norm`. + pub mp_norm_lo: T, + /// High limb of `Mp_norm` in `[128, 256)`. + pub mp_norm_hi: T, + + // ------------------------------------------------------------------------------------------ + // Window anchor eta (biased value-MSB max) and per-term relative shifts. + // ------------------------------------------------------------------------------------------ + /// The window anchor `eta` = max biased value-MSB over nonzero terms (0 when both zero). + pub eta: T, + /// `rel_p = eta - EFF_P` (`EFF_P = (1 - P_IS_ZERO)*P_MSB_BIASED`), `>= 0` (RANGE16). + pub rel_p: T, + /// `rel_t = eta - EFF_T`, `>= 0` (RANGE16). + pub rel_t: T, + /// Far flag `[rel_p >= 27]` (the P term lies entirely below the window -> aligned 0, sticky). + pub far_p: T, + /// Two-sided slack pinning `far_p`: `far_p*(rel_p-27) + (1-far_p)*(26-rel_p) >= 0`. + pub far_p_slack: T, + /// Far flag `[rel_t >= 27]`. + pub far_t: T, + /// Two-sided slack pinning `far_t`. + pub far_t_slack: T, + /// `ACTIVE_P = (1 - far_p)*(1 - P_IS_ZERO)` — the P term aligns with a real FP16POW2 shift. + pub active_p: T, + /// `ACTIVE_T = (1 - far_t)*(1 - T_IS_ZERO)`. + pub active_t: T, + + // ------------------------------------------------------------------------------------------ + // Alignment onto the 2^(eta-26) grid (GUARD = 3 extra low bits). + // ------------------------------------------------------------------------------------------ + /// `2^rel_p` (FP16POW2, filtered to ACTIVE_P; 1 otherwise). + pub pow_p: T, + /// Aligned P magnitude `floor(Mp_norm * 8 / 2^rel_p) < 2^27` (0 when not ACTIVE_P). + pub aligned_p: T, + /// Low 16-bit limb of `aligned_p`. + pub aligned_p_lo: T, + /// High limb of `aligned_p` (`< 2^11`). + pub aligned_p_hi: T, + /// Alignment remainder `Mp_norm*8 - aligned_p*2^rel_p` (`< 2^rel_p <= 2^26`; 2-limb RANGE16). + pub rem_p: T, + pub rem_p_lo: T, + pub rem_p_hi: T, + /// Two-sided bound `2^rel_p - 1 - rem_p >= 0` (`< 2^26`; 2-limb RANGE16). + pub rem_p_bound: T, + pub rem_p_bound_lo: T, + pub rem_p_bound_hi: T, + /// `2^rel_t` (FP16POW2, filtered to ACTIVE_T; 1 otherwise). + pub pow_t: T, + /// Aligned t magnitude `floor(M_t * 8 / 2^rel_t) < 2^27`. + pub aligned_t: T, + pub aligned_t_lo: T, + pub aligned_t_hi: T, + pub rem_t: T, + pub rem_t_lo: T, + pub rem_t_hi: T, + pub rem_t_bound: T, + pub rem_t_bound_lo: T, + pub rem_t_bound_hi: T, + + // ------------------------------------------------------------------------------------------ + // Sticky bits (dropped below the window). + // ------------------------------------------------------------------------------------------ + /// `[rem_p != 0]`. + pub rem_p_nz: T, + pub rem_p_nz_inv: T, + /// `[rem_t != 0]`. + pub rem_t_nz: T, + pub rem_t_nz_inv: T, + /// `far_p OR [rem_p != 0]`. + pub or_p: T, + /// `far_t OR [rem_t != 0]`. + pub or_t: T, + /// P sticky `(1 - P_IS_ZERO)*OR_P`. + pub sticky_p: T, + /// t sticky `(1 - T_IS_ZERO)*OR_T`. + pub sticky_t: T, + /// `STICKY_P OR STICKY_T` — any bit dropped below the window. + pub far_sticky: T, + /// Sign-aware sticky: 1 iff the (single) sub-window sticky term has the SAME sign as the window + /// result `W`, i.e. the dropped bits ADD to `|W|` (so a round-to-nearest tie rounds up). When the + /// sticky term has the OPPOSITE sign (a subtraction/cancellation), the dropped bits make `|W|` + /// slightly SMALLER, so the tie must round DOWN — the bug the plain `far_sticky` tie-break had. + /// Only the non-dominant term (`rel > 0`) can carry a remainder, so at most one term is sticky. + pub sticky_up: T, + + // ------------------------------------------------------------------------------------------ + // Signed window sum. + // ------------------------------------------------------------------------------------------ + /// Sign of the signed window sum (boolean). + pub w_sign: T, + /// Magnitude `|W| < 2^28` of the signed window sum. + pub w_abs: T, + /// Low 16-bit limb of `|W|`. + pub w_abs_lo: T, + /// High limb of `|W|` (`< 2^12`). + pub w_abs_hi: T, + /// `[W == 0]` (zero result: both terms zero, or exact cancellation). + pub w_is_zero: T, + /// Inverse witness for the `[W == 0]` is-zero gadget. + pub w_abs_inv: T, + + // ------------------------------------------------------------------------------------------ + // Renormalize |W| to a 24-bit significand (WIDTH32) + single RNE round. + // ------------------------------------------------------------------------------------------ + /// Bit-width `w = bitlen(|W|) in [1, 28]` (WIDTH32 key; filtered to nonzero-W rows). + pub ww: T, + /// WIDTH32 value `2^max(w-24, 0)`. + pub trunc_w: T, + /// WIDTH32 value `2^max(24-w, 0)`. + pub lift_w: T, + /// Round-toward-zero significand `M_rz = floor(|W|*lift_w / trunc_w) in [2^23, 2^24)`. + pub m_rz: T, + /// Low 16-bit limb of `M_rz`. + pub m_rz_lo: T, + /// High limb of `M_rz` in `[128, 256)`. + pub m_rz_hi: T, + /// RZ remainder `|W|*lift_w - M_rz*trunc_w` (`< trunc_w`). + pub rz_rem: T, + /// Two-sided bound `trunc_w - 1 - rz_rem >= 0`. + pub rz_rem_bound: T, + /// `M_rz & 1` parity (rides the low limb, RANGE16). + pub rz_parity: T, + /// `(M_rz_lo - RZ_PARITY)/2` (RANGE16). + pub rz_half: T, + /// `[2*rz_rem > trunc_w]` (strict round-up). + pub gt: T, + /// Two-sided slack pinning `gt`: `gt*(2*rz_rem - trunc_w - 1) + (1-gt)*(trunc_w - 2*rz_rem) >= 0`. + pub gt_slack: T, + /// `[2*rz_rem == trunc_w]` (exact half -> ties-to-even). + pub eq: T, + /// Inverse witness for the `[trunc_w - 2*rz_rem == 0]` is-zero gadget. + pub eq_inv: T, + /// The tie-break predicate `STICKY_UP + (1 - FAR_STICKY)*RZ_PARITY` (boolean): round up at a tie + /// iff a same-sign sub-window remainder pushes `|W|` above the tie, or (no sub-window remainder) + /// the kept significand is odd (ties-to-even). + pub or_rs: T, + /// RNE round-up bit `gt + eq*OR_RS` (boolean). + pub round_up: T, + /// Mantissa-overflow carry `[M_rz + round_up == 2^24]`. + pub carry: T, + /// Inverse witness for the `[2^24 - M_rz - round_up == 0]` is-zero gadget. + pub carry_inv: T, + + // ------------------------------------------------------------------------------------------ + // Result f32 `noised`. + // ------------------------------------------------------------------------------------------ + /// f32 exponent field of `noised` (`= eta + w + carry - 412` on a nonzero result, else 0). + pub noised_exp: T, + /// Sign bit of `noised`. + pub noised_sign: T, + /// f32 23-bit trailing significand of `noised`. + pub noised_mant: T, + /// `noised` low 16-bit limb (the exposed f32 word). + pub noised_lo: T, + /// `noised` high 16-bit limb. + pub noised_hi: T, +} + +/// Total committed columns. +pub const NUM_FMA_COLUMNS: usize = size_of::>(); + +const _: () = assert!(NUM_FMA_COLUMNS == 90); + +/// No public inputs. +pub const NUM_FMA_PUBLIC_INPUTS: usize = 0; + +columns_view!(FmaColumnsView, NUM_FMA_COLUMNS, FMA_COL_MAP); + +/// Number of leading class (a) ("known") columns: just `IS_PAD`. +pub const NUM_FMA_KNOWN_COLUMNS: usize = FMA_COL_MAP.is_pad + 1; + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_FMA_COLUMNS] = FMA_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + assert_eq!(FMA_COL_MAP.is_pad, 0); + assert_eq!(NUM_FMA_KNOWN_COLUMNS, 1); + assert_eq!(FMA_COL_MAP.noised_hi, NUM_FMA_COLUMNS - 1); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_FMA_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: FmaColumnsView = arr.into(); + assert_eq!(view.is_pad, 1); + assert_eq!(view.w_abs, FMA_COL_MAP.w_abs as u64 * 3 + 1); + let back: [u64; NUM_FMA_COLUMNS] = view.into(); + assert_eq!(back, arr); + let borrowed: &FmaColumnsView = arr.borrow(); + assert_eq!(borrowed.noised_hi, arr[FMA_COL_MAP.noised_hi]); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/ctl.rs b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/ctl.rs new file mode 100644 index 000000000..af2c07be7 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/ctl.rs @@ -0,0 +1,164 @@ +//! Cross-table-lookup declarations for the FP16 single-rounding FMA AIR (group G2). +//! +//! * **Pairing hook** ([`ctl_fma_pairing_looking`]): exposes the tuple +//! `(alpha, raw, t_sign, t_mant, t_exp, noised_lo, noised_hi)`, filter `1 - IS_PAD`. This is the +//! EXACT tuple [`crate::circuit::fp16::noisy_quant_stark::ctl::ctl_fma_hook_looking`] exposes, so +//! pairing the two in the batch binds this AIR's inputs `(alpha, raw, t)` and its proven output +//! `noised` to group G1's `t` and group G3's `noised` input in one channel. The table index is +//! supplied at integration time (this AIR is not registered in [`crate::circuit::fp16::ctl`]). +//! * The committed-LUT inventory ([`fma_lut_lookups`]): FP16DECODE (raw), WIDTH32 (the two bit-width +//! normalizations), FP16POW2 (the two alignment shifts), and RANGE16 (every limb/slack). No new +//! table is introduced — all facts target the FP16 batch's `Fp16Decode`/`Width32`/`Fp16Pow2`/ +//! `Range16` tables. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::FMA_COL_MAP; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +fn live_filter() -> Filter { + Filter::from_column(Column::linear_combination_with_constant([(FMA_COL_MAP.is_pad, -F::ONE)], F::ONE)) +} + +/// `(1 - IS_PAD) * (1 - flag_col)` as a product filter. +fn live_and_not(flag_col: usize) -> Filter { + Filter::new( + vec![( + Column::linear_combination_with_constant([(FMA_COL_MAP.is_pad, -F::ONE)], F::ONE), + Column::linear_combination_with_constant([(flag_col, -F::ONE)], F::ONE), + )], + vec![], + ) +} + +/// The pairing hook: `(alpha, raw, t_sign, t_mant, t_exp, noised_lo, noised_hi)`, filter `1-IS_PAD`. +pub fn ctl_fma_pairing_looking(table: usize) -> TableWithColumns { + let m = &FMA_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + Column::singles([m.alpha, m.raw, m.t_sign, m.t_mant, m.t_exp, m.noised_lo, m.noised_hi]).collect(), + live_filter(), + ) +} + +/// Committed-LUT inventory (FP16DECODE + WIDTH32 + FP16POW2 + RANGE16). +pub fn fma_lut_lookups() -> Vec> { + let m = &FMA_COL_MAP; + let nz_p = live_and_not::(m.p_is_zero); + let nz_w = live_and_not::(m.w_is_zero); + let mut lu: Vec> = Vec::new(); + + // ---- FP16DECODE: raw -> (sig, sign, eps_biased, is_zero). Filtered to live rows: the all-zero + // padding rows carry a default value tuple that does not match FP16DECODE's slot for code 0, so + // an unfiltered lookup would be an unservable (value-mismatch) instance in the batch. Padding + // rows are unconstrained; every live row is still decoded. ---- + lu.push(LutLookup { + table: LutTable::Fp16Decode, + keys: vec![Column::single(m.raw)], + values: Column::singles([m.x_sig, m.x_sign, m.x_eps_biased, m.x_is_zero]).collect(), + filter: live_filter(), + }); + + // ---- WIDTH32: b_p -> (trunc_p, lift_p) (nonzero-P rows), w -> (trunc_w, lift_w) (nonzero-W). ---- + lu.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.bp)], + values: Column::singles([m.trunc_p, m.lift_p]).collect(), + filter: nz_p.clone(), + }); + lu.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.ww)], + values: Column::singles([m.trunc_w, m.lift_w]).collect(), + filter: nz_w.clone(), + }); + + // ---- FP16POW2: alignment shifts, keyed on rel, filtered to active rows. ---- + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.rel_p)], + values: vec![Column::single(m.pow_p)], + filter: Filter::from_column(Column::single(m.active_p)), + }); + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.rel_t)], + values: vec![Column::single(m.pow_t)], + filter: Filter::from_column(Column::single(m.active_t)), + }); + + // ---- RANGE16. ---- + let rc = |c: Column| LutLookup::rc16(c); + let scaled = |col: usize, sh: u64| Column::linear_combination([(col, F::from_canonical_u64(1 << sh))]); + // 7-bit fields. + lu.push(rc(scaled(m.alpha_mant, 9))); + // Mp_norm limbs (hi in [128,256), filtered nonzero-P). + lu.push(rc(Column::single(m.mp_norm_lo))); + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant([(m.mp_norm_hi, F::from_canonical_u64(1 << 8))], -F::from_canonical_u64(128 << 8)), + nz_p, + )); + // rel, far slacks. + lu.push(rc(Column::single(m.rel_p))); + lu.push(rc(Column::single(m.rel_t))); + lu.push(rc(Column::single(m.far_p_slack))); + lu.push(rc(Column::single(m.far_t_slack))); + // aligned limbs (< 2^27: lo < 2^16, hi*2^5 < 2^16 -> hi < 2^11). + lu.push(rc(Column::single(m.aligned_p_lo))); + lu.push(rc(scaled(m.aligned_p_hi, 5))); + lu.push(rc(Column::single(m.aligned_t_lo))); + lu.push(rc(scaled(m.aligned_t_hi, 5))); + // rem / rem_bound limbs (< 2^26: lo < 2^16, hi*2^6 < 2^16 -> hi < 2^10). + for (lo, hi) in [ + (m.rem_p_lo, m.rem_p_hi), + (m.rem_p_bound_lo, m.rem_p_bound_hi), + (m.rem_t_lo, m.rem_t_hi), + (m.rem_t_bound_lo, m.rem_t_bound_hi), + ] { + lu.push(rc(Column::single(lo))); + lu.push(rc(scaled(hi, 6))); + } + // |W| limbs (< 2^28: lo < 2^16, hi*2^4 < 2^16 -> hi < 2^12). + lu.push(rc(Column::single(m.w_abs_lo))); + lu.push(rc(scaled(m.w_abs_hi, 4))); + // M_rz limbs (hi in [128,256), filtered nonzero-W). + lu.push(rc(Column::single(m.m_rz_lo))); + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant([(m.m_rz_hi, F::from_canonical_u64(1 << 8))], -F::from_canonical_u64(128 << 8)), + nz_w, + )); + // RNE small slacks. + lu.push(rc(Column::single(m.rz_rem))); + lu.push(rc(Column::single(m.rz_rem_bound))); + lu.push(rc(Column::single(m.rz_half))); + lu.push(rc(Column::single(m.gt_slack))); + + lu +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + + type F = GoldilocksField; + + #[test] + fn ctl_halves_are_well_formed() { + ctl_fma_pairing_looking::(5); + } + + #[test] + fn lut_inventory_counts() { + let lu = fma_lut_lookups::(); + let count = |t: LutTable| lu.iter().filter(|l| l.table == t).count(); + assert_eq!(count(LutTable::Fp16Decode), 1); + assert_eq!(count(LutTable::Width32), 2); + assert_eq!(count(LutTable::Fp16Pow2), 2); + assert_eq!(count(LutTable::Range16), lu.len() - 5); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/mod.rs b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/mod.rs new file mode 100644 index 000000000..81beb90e8 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/mod.rs @@ -0,0 +1,24 @@ +//! FP16 single-rounding FMA AIR — group G2 of the fused noisy quantization. +//! +//! Proves `noised = fma(af, X, t)` bit-exact vs the Rust `af.mul_add(fp16_to_f32(raw), t)` of +//! [`crate::api::fp16::quantization::noisy_quantize`], with `af = bf16_to_f32(alpha)`, +//! `X = fp16_to_f32(raw)`, and `t = RNE_f32(bf*N)` (group G1's output). It is a signed, +//! arbitrarily-aligned add of the exact product `af*X` and `t` with a SINGLE f32 +//! round-to-nearest-ties-to-even and possible cancellation — the core of the kernel. The sibling +//! [`crate::circuit::fp16::noisy_quant_stark`] proves G1 (`t`) and G3 (the FP16 cast); this AIR's +//! [`ctl::ctl_fma_pairing_looking`] exposes the exact tuple that module's +//! `ctl_fma_hook_looking` does, so the batch binds `t` (G1 output) and `noised` (G3 input) to this +//! AIR's proven FMA in one channel. +//! +//! The windowed-alignment datapath mirrors [`crate::circuit::fp16::matmul_a100_stark`] (24-bit +//! normalization, FP16POW2/WIDTH32 alignment, signed sum, far-gap sticky), with the single RNE +//! round proved by the exact quarter-ulp bracket / parity / IS_BOTTOM (normalized-range) / is-zero +//! technique — no quarter-ulp grinding slack. See [`stark`] for the constraint groups and the +//! documented soundness/completeness envelope. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{FMA_COL_MAP, FmaColumnsView, NUM_FMA_COLUMNS, NUM_FMA_PUBLIC_INPUTS}; +pub use stark::{FmaProgram, NoisyQuantFmaStark}; diff --git a/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/stark.rs b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/stark.rs new file mode 100644 index 000000000..c8a3d26b7 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_fma_stark/stark.rs @@ -0,0 +1,1073 @@ +//! Proves group G2 of the fused noisy quantization: the single-rounding f32 FMA +//! `noised = fma(af, X, t)`, bit-exact vs the Rust `af.mul_add(fp16_to_f32(raw), t)` of +//! [`crate::api::fp16::quantization::noisy_quantize`], where `af = bf16_to_f32(alpha)`, +//! `X = fp16_to_f32(raw)`, and `t = RNE_f32(bf*N)` is group G1's output (carried in as +//! `(T_SIGN, T_MANT, T_EXP)`). +//! +//! # The datapath (mirrors the A100 accumulation AIR, adapted to RNE and 2 terms) +//! +//! `af*X` is the EXACT product with significand `Mp = M_a * M_x < 2^19` (both operands decode +//! losslessly to f32, and `19 < 24`, so the product is exact). `t` has a 24-bit significand `M_t`. +//! Both are normalized to 24-bit significands (`Mp_norm = Mp << (24-b_p)` via WIDTH32; `M_t` is +//! already 24-bit), given biased value-MSBs `P_MSB`, `T_MSB`. The window anchor +//! `eta = max(P_MSB, T_MSB)` over the nonzero terms; the window unit is `2^(eta-26)` (3 guard bits +//! below the 24-bit significand). Each term contributes `floor(sig * 8 / 2^rel)`, +//! `rel = eta - term_MSB` (FP16POW2; a term with `rel >= 27` falls entirely below the window and +//! contributes only to the sticky bit). The two signed aligned terms sum exactly to `|W| < 2^28` +//! (a far-gap sticky records any bits dropped below the window); the sum is renormalized into +//! `[2^23, 2^24)` (WIDTH32) and rounded once (RNE, ties to even) using the exact quarter-ulp +//! bracket / parity / sticky machinery. The result `noised` is emitted as an f32. +//! +//! # Soundness / completeness envelope +//! +//! `alpha` is a normal positive BF16; `raw` is any FP16 code (zero/subnormal/normal — FP16DECODE +//! serves all); `t` is G1's output (24-bit normal, or zero). The ONLY envelope restriction is that +//! the f32 **result** is normal (`noised_exp >= 1`) — a subnormal f32 result needs `|noised| < +//! 2^-126`, which the in-scheme datapath (alpha ~ the FP16 ceiling over a row norm) never produces; +//! the generator asserts it (so an out-of-envelope row is simply unprovable, exactly as +//! [`crate::circuit::fp16::noise_stark`]). A tiny FP16 element is fine here: it yields a normal f32 +//! `noised` (whose subsequent FP16 *cast* may be subnormal — that is group G3's concern, not G2's). +//! Every RNE rounding carries the full ties-to-even machinery (parity split + binade-bottom via the +//! `[2^23, 2^24)` normalized-range pin + the far-gap sticky), with NO quarter-ulp grinding slack. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{FmaColumnsView, NUM_FMA_COLUMNS, NUM_FMA_PUBLIC_INPUTS}; +use crate::api::fp16::dtype::fp16_decode_fields; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// `noised_exp = eta_biased + w + carry - EXP_OFFSET` (= `(eta-512) + w + 100 + carry`); the +/// value-MSB bias is 512 and GUARD = 3 (both folded into the literal offsets 352/385/412 below). +const EXP_OFFSET: u64 = 412; + +fn inv_f(x: u64) -> F { + if x == 0 { F::ZERO } else { F::from_canonical_u64(x).inverse() } +} + +/// Inverse of the field difference `a - b` (zero when equal); handles `a < b` without u64 underflow. +fn inv_diff(a: u64, b: u64) -> F { + let d = F::from_canonical_u64(a) - F::from_canonical_u64(b); + if d == F::ZERO { F::ZERO } else { d.inverse() } +} + +fn bit_length(x: u64) -> u32 { + 64 - x.leading_zeros() +} + +/// The committed geometry: just the element count. +#[derive(Clone, Debug)] +pub struct FmaProgram { + pub num_elems: usize, + /// Trace height (a power of two `>= num_elems`). + pub num_rows: usize, +} + +impl FmaProgram { + pub fn new(num_elems: usize) -> Self { + Self::with_rows(num_elems, num_elems.next_power_of_two().max(2)) + } + + /// Program at an explicit `num_rows` height (the batch pins an on-ladder height). + pub fn with_rows(num_elems: usize, num_rows: usize) -> Self { + assert!(num_elems >= 1, "at least one element"); + assert!(num_rows.is_power_of_two() && num_rows >= num_elems, "height covers the live elements"); + Self { num_elems, num_rows } + } + + pub fn live_rows(&self) -> usize { + self.num_elems + } + + pub fn num_rows(&self) -> usize { + self.num_rows + } + + pub fn known_values(&self) -> Vec> { + let num_rows = self.num_rows(); + let is_pad = (0..num_rows).map(|i| F::from_bool(i >= self.num_elems)).collect(); + vec![PolynomialValues::new(is_pad)] + } + + /// Generates the trace. Each of `alpha` (BF16 code), `raw` (FP16 code), and `t` (as + /// `(t_sign, t_mant=M_t, t_exp)` from G1) has one entry per live element. The emitted `noised` + /// is bit-exact with `(bf16_to_f32(alpha)).mul_add(fp16_to_f32(raw), t_value)`. + pub fn generate_trace( + &self, + alpha: &[u16], + raw: &[u16], + t_sign: &[u64], + t_mant: &[u64], + t_exp: &[u64], + ) -> Vec<[F; NUM_FMA_COLUMNS]> { + let n = self.num_elems; + assert!(alpha.len() == n && raw.len() == n && t_sign.len() == n && t_mant.len() == n && t_exp.len() == n); + let num_rows = self.num_rows(); + let mut rows = Vec::with_capacity(num_rows); + + for e in 0..n { + let mut v = FmaColumnsView::::default(); + + // ---- Decode alpha (normal positive BF16). ---- + let alpha_code = alpha[e]; + let alpha_exp = u64::from(alpha_code >> 7); + let alpha_mant = u64::from(alpha_code & 0x7F); + assert!((1..=254).contains(&alpha_exp), "envelope: alpha normal BF16"); + let m_a = 128 + alpha_mant; + v.alpha = F::from_canonical_u16(alpha_code); + v.alpha_exp = F::from_canonical_u64(alpha_exp); + v.alpha_mant = F::from_canonical_u64(alpha_mant); + + // ---- Decode raw (FP16DECODE). ---- + let (x_sig, x_sign, x_eps_biased, x_is_zero) = fp16_decode_fields(raw[e]); + v.raw = F::from_canonical_u16(raw[e]); + v.x_sig = F::from_canonical_u64(x_sig); + v.x_sign = F::from_canonical_u64(x_sign); + v.x_eps_biased = F::from_canonical_u64(x_eps_biased); + v.x_is_zero = F::from_canonical_u64(x_is_zero); + + // ---- t (from G1). ---- + let ts = t_sign[e]; + let mt = t_mant[e]; + let te = t_exp[e]; + let t_is_zero = mt == 0; + v.t_sign = F::from_canonical_u64(ts); + v.t_mant = F::from_canonical_u64(mt); + v.t_exp = F::from_canonical_u64(te); + v.t_is_zero = F::from_bool(t_is_zero); + v.t_mant_inv = inv_f::(mt); + + // ---- Exact product significand + 24-bit normalization. ---- + let p_is_zero = x_is_zero == 1; + let mp = m_a * x_sig; + v.p_is_zero = F::from_bool(p_is_zero); + v.mp = F::from_canonical_u64(mp); + let (bp, lift_p, mp_norm) = if p_is_zero { + (0u64, 1u64, 0u64) + } else { + let b = u64::from(bit_length(mp)); + let lift = 1u64 << (24 - b); + (b, lift, mp * lift) + }; + v.bp = F::from_canonical_u64(bp); + v.trunc_p = F::ONE; // 2^max(bp-24,0) = 1 for bp <= 24 + v.lift_p = F::from_canonical_u64(lift_p); + v.mp_norm = F::from_canonical_u64(mp_norm); + v.mp_norm_lo = F::from_canonical_u64(mp_norm & 0xFFFF); + v.mp_norm_hi = F::from_canonical_u64(mp_norm >> 16); + + // Biased value-MSBs. + let p_msb_b = alpha_exp + x_eps_biased + bp + 352; // (L_p + b_p - 1) + 512; only valid if P nonzero + let t_msb_b = te + 385; // (t_exp - 127) + 512 + let eff_p = if p_is_zero { 0 } else { p_msb_b }; + let eff_t = if t_is_zero { 0 } else { t_msb_b }; + let eta = eff_p.max(eff_t); + v.eta = F::from_canonical_u64(eta); + let rel_p = eta - eff_p; + let rel_t = eta - eff_t; + v.rel_p = F::from_canonical_u64(rel_p); + v.rel_t = F::from_canonical_u64(rel_t); + let far_p = rel_p >= 27; + let far_t = rel_t >= 27; + v.far_p = F::from_bool(far_p); + v.far_p_slack = F::from_canonical_u64(if far_p { rel_p - 27 } else { 26 - rel_p }); + v.far_t = F::from_bool(far_t); + v.far_t_slack = F::from_canonical_u64(if far_t { rel_t - 27 } else { 26 - rel_t }); + let active_p = !far_p && !p_is_zero; + let active_t = !far_t && !t_is_zero; + v.active_p = F::from_bool(active_p); + v.active_t = F::from_bool(active_t); + + // ---- Alignment. ---- + let (pow_p, aligned_p, rem_p) = if active_p { + let pow = 1u64 << rel_p; + let a = (mp_norm * 8) / pow; + (pow, a, mp_norm * 8 - a * pow) + } else { + (1u64, 0u64, 0u64) + }; + v.pow_p = F::from_canonical_u64(pow_p); + v.aligned_p = F::from_canonical_u64(aligned_p); + v.aligned_p_lo = F::from_canonical_u64(aligned_p & 0xFFFF); + v.aligned_p_hi = F::from_canonical_u64(aligned_p >> 16); + v.rem_p = F::from_canonical_u64(rem_p); + v.rem_p_lo = F::from_canonical_u64(rem_p & 0xFFFF); + v.rem_p_hi = F::from_canonical_u64(rem_p >> 16); + let rem_p_bound = if active_p { pow_p - 1 - rem_p } else { 0 }; + v.rem_p_bound = F::from_canonical_u64(rem_p_bound); + v.rem_p_bound_lo = F::from_canonical_u64(rem_p_bound & 0xFFFF); + v.rem_p_bound_hi = F::from_canonical_u64(rem_p_bound >> 16); + + let (pow_t, aligned_t, rem_t) = if active_t { + let pow = 1u64 << rel_t; + let a = (mt * 8) / pow; + (pow, a, mt * 8 - a * pow) + } else { + (1u64, 0u64, 0u64) + }; + v.pow_t = F::from_canonical_u64(pow_t); + v.aligned_t = F::from_canonical_u64(aligned_t); + v.aligned_t_lo = F::from_canonical_u64(aligned_t & 0xFFFF); + v.aligned_t_hi = F::from_canonical_u64(aligned_t >> 16); + v.rem_t = F::from_canonical_u64(rem_t); + v.rem_t_lo = F::from_canonical_u64(rem_t & 0xFFFF); + v.rem_t_hi = F::from_canonical_u64(rem_t >> 16); + let rem_t_bound = if active_t { pow_t - 1 - rem_t } else { 0 }; + v.rem_t_bound = F::from_canonical_u64(rem_t_bound); + v.rem_t_bound_lo = F::from_canonical_u64(rem_t_bound & 0xFFFF); + v.rem_t_bound_hi = F::from_canonical_u64(rem_t_bound >> 16); + + // ---- Sticky bits. ---- + let rem_p_nz = rem_p != 0; + let rem_t_nz = rem_t != 0; + v.rem_p_nz = F::from_bool(rem_p_nz); + v.rem_p_nz_inv = inv_f::(rem_p); + v.rem_t_nz = F::from_bool(rem_t_nz); + v.rem_t_nz_inv = inv_f::(rem_t); + let or_p = far_p || rem_p_nz; + let or_t = far_t || rem_t_nz; + v.or_p = F::from_bool(or_p); + v.or_t = F::from_bool(or_t); + let sticky_p = !p_is_zero && or_p; + let sticky_t = !t_is_zero && or_t; + v.sticky_p = F::from_bool(sticky_p); + v.sticky_t = F::from_bool(sticky_t); + let far_sticky = sticky_p || sticky_t; + v.far_sticky = F::from_bool(far_sticky); + + // ---- Signed window sum. ---- + let term_p: i128 = if x_sign == 1 { -(aligned_p as i128) } else { aligned_p as i128 }; + let term_t: i128 = if ts == 1 { -(aligned_t as i128) } else { aligned_t as i128 }; + let w_signed = term_p + term_t; + let w_sign = w_signed < 0; + let w_abs = w_signed.unsigned_abs() as u64; + let w_is_zero = w_signed == 0; + v.w_sign = F::from_bool(w_sign); + v.w_abs = F::from_canonical_u64(w_abs); + v.w_abs_lo = F::from_canonical_u64(w_abs & 0xFFFF); + v.w_abs_hi = F::from_canonical_u64(w_abs >> 16); + v.w_is_zero = F::from_bool(w_is_zero); + v.w_abs_inv = inv_f::(w_abs); + + // ---- Renormalize + RNE. ---- + let (ww, trunc_w, lift_w, m_rz, rz_rem) = if w_is_zero { + (0u64, 1u64, 1u64, 0u64, 0u64) + } else { + let w = u64::from(bit_length(w_abs)); + let tr = 1u64 << w.saturating_sub(24); + let lf = 1u64 << 24u64.saturating_sub(w); + let m = w_abs * lf / tr; + (w, tr, lf, m, w_abs * lf - m * tr) + }; + v.ww = F::from_canonical_u64(ww); + v.trunc_w = F::from_canonical_u64(trunc_w); + v.lift_w = F::from_canonical_u64(lift_w); + v.m_rz = F::from_canonical_u64(m_rz); + v.m_rz_lo = F::from_canonical_u64(m_rz & 0xFFFF); + v.m_rz_hi = F::from_canonical_u64(m_rz >> 16); + v.rz_rem = F::from_canonical_u64(rz_rem); + v.rz_rem_bound = F::from_canonical_u64(if w_is_zero { 0 } else { trunc_w - 1 - rz_rem }); + let rz_parity = m_rz & 1; + v.rz_parity = F::from_canonical_u64(rz_parity); + v.rz_half = F::from_canonical_u64(((m_rz & 0xFFFF) - rz_parity) / 2); + + let gt = 2 * rz_rem > trunc_w; + let eq = 2 * rz_rem == trunc_w; + v.gt = F::from_bool(gt); + v.gt_slack = F::from_canonical_u64(if gt { 2 * rz_rem - trunc_w - 1 } else { trunc_w - 2 * rz_rem }); + v.eq = F::from_bool(eq); + v.eq_inv = inv_diff::(trunc_w, 2 * rz_rem); + // Sign-aware sticky: the single sub-window sticky term (the non-dominant one) pushes |W| + // up only if it shares W's sign; an opposite-sign remainder (subtraction) makes |W| + // smaller, so a tie must round DOWN. `x_sign`/`ts` are the term signs; `w_sign` is W's. + let ws = u64::from(w_sign); + let sticky_up = + (sticky_p && x_sign == ws) || (sticky_t && ts == ws); + v.sticky_up = F::from_bool(sticky_up); + let or_rs = sticky_up || (!far_sticky && rz_parity == 1); + v.or_rs = F::from_bool(or_rs); + let round_up = gt || (eq && or_rs); + v.round_up = F::from_bool(round_up); + let m_out = m_rz + u64::from(round_up); + let carry = m_out == (1 << 24); + v.carry = F::from_bool(carry); + v.carry_inv = inv_f::((1 << 24) - m_out); + let m_out_final = if carry { 1 << 23 } else { m_out }; + + // ---- Result f32. ---- + let (noised_exp, noised_mant, noised_sign) = if w_is_zero { + (0u64, 0u64, 0u64) + } else { + let exp = eta + ww + u64::from(carry) - EXP_OFFSET; + assert!((1..=254).contains(&exp), "envelope: f32-normal result (noised_exp {exp})"); + (exp, m_out_final - (1 << 23), u64::from(w_sign)) + }; + v.noised_exp = F::from_canonical_u64(noised_exp); + v.noised_sign = F::from_canonical_u64(noised_sign); + v.noised_mant = F::from_canonical_u64(noised_mant); + let nbits = (noised_sign << 31) | (noised_exp << 23) | noised_mant; + v.noised_lo = F::from_canonical_u64(nbits & 0xFFFF); + v.noised_hi = F::from_canonical_u64(nbits >> 16); + + // ---- Bit-exact cross-check vs the reference f32 FMA. ---- + let af = crate::api::fp8::dtype::bf16_to_f32(alpha_code); + let xval = crate::api::fp16::dtype::fp16_to_f32(raw[e]); + let tval = if t_is_zero { + if ts == 1 { -0.0f32 } else { 0.0f32 } + } else { + f32::from_bits(((ts as u32) << 31) | ((te as u32) << 23) | ((mt - (1 << 23)) as u32)) + }; + let reference = af.mul_add(xval, tval); + let ref_bits = reference.to_bits(); + if w_is_zero { + debug_assert_eq!(ref_bits & 0x7FFF_FFFF, 0, "reference should be zero when W == 0"); + } else { + debug_assert_eq!(nbits as u32, ref_bits, "noised {nbits:#010x} vs reference {ref_bits:#010x}"); + } + + rows.push(v.into()); + } + + for _ in n..num_rows { + rows.push(FmaColumnsView:: { is_pad: F::ONE, ..Default::default() }.into()); + } + rows + } +} + +/// `flag = [x == 0]`, gated: `flag` boolean, `flag*x = 0`, `x*inv = 1 - flag`. +fn is_zero_flag(eval: &mut E, x: V, inv: V, flag: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + eval.constraint_bool(flag); + let fx = eval.mul(flag, x); + let c = eval.mul(gate, fx); + eval.constraint(c); + let xi = eval.mul(x, inv); + let omf = eval.sub(one, flag); + let d = eval.sub(xi, omf); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `a OR b` for booleans, committed to `out`: `out = a + b - a*b`, gated. +fn or_flag(eval: &mut E, a: V, b: V, out: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let ab = eval.mul(a, b); + let apb = eval.add(a, b); + let expect = eval.sub(apb, ab); + let d = eval.sub(out, expect); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +pub(crate) fn eval_fma_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_FMA_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &FmaColumnsView = lv.borrow(); + + let one = eval.u64(1); + let live = eval.sub(one, lv.is_pad); + eval.constraint_bool(lv.is_pad); + + let c128 = eval.u64(128); + let c8 = eval.u64(8); + let c2_16 = eval.u64(1 << 16); + let c2_23 = eval.u64(1 << 23); + let c2_24 = eval.u64(1 << 24); + let c2_31 = eval.u64(1 << 31); + let two = eval.u64(2); + + let gated = |eval: &mut E, expr: V| { + let c = eval.mul(live, expr); + eval.constraint(c); + }; + + // ---- alpha decode: code = alpha_exp*128 + alpha_mant. ---- + let beta_rec = eval.mad(lv.alpha_exp, c128, lv.alpha_mant); + let d = eval.sub(lv.alpha, beta_rec); + gated(eval, d); + + // ---- booleans. ---- + eval.constraint_bool(lv.x_sign); + eval.constraint_bool(lv.x_is_zero); + eval.constraint_bool(lv.t_sign); + eval.constraint_bool(lv.far_p); + eval.constraint_bool(lv.far_t); + eval.constraint_bool(lv.active_p); + eval.constraint_bool(lv.active_t); + eval.constraint_bool(lv.rem_p_nz); + eval.constraint_bool(lv.rem_t_nz); + eval.constraint_bool(lv.or_p); + eval.constraint_bool(lv.or_t); + eval.constraint_bool(lv.sticky_p); + eval.constraint_bool(lv.sticky_t); + eval.constraint_bool(lv.far_sticky); + eval.constraint_bool(lv.w_sign); + eval.constraint_bool(lv.w_is_zero); + eval.constraint_bool(lv.gt); + eval.constraint_bool(lv.eq); + eval.constraint_bool(lv.or_rs); + eval.constraint_bool(lv.round_up); + eval.constraint_bool(lv.carry); + eval.constraint_bool(lv.p_is_zero); + + // ---- t_is_zero = [M_t == 0]; p_is_zero = x_is_zero. ---- + is_zero_flag(eval, lv.t_mant, lv.t_mant_inv, lv.t_is_zero, live); + let d = eval.sub(lv.p_is_zero, lv.x_is_zero); + gated(eval, d); + + // ---- product significand Mp = (128 + alpha_mant) * x_sig. ---- + let m_a = eval.add(c128, lv.alpha_mant); + let mp_expect = eval.mul(m_a, lv.x_sig); + let d = eval.sub(lv.mp, mp_expect); + gated(eval, d); + // Mp_norm = Mp * lift_p (WIDTH32 pins lift_p = 2^(24-b_p), and the [2^23,2^24) range of + // Mp_norm pins b_p = bitlen(Mp)). Active only on nonzero-P rows. + let nonzero_p = eval.sub(one, lv.p_is_zero); + let mp_norm_expect = eval.mul(lv.mp, lv.lift_p); + let d = eval.sub(lv.mp_norm, mp_norm_expect); + // Degree-3 (nonzero_p * degree-2); 0 on padding rows (all columns 0), so no extra live gate. + let c = eval.mul(nonzero_p, d); + eval.constraint(c); + // Zero-P rows: Mp_norm = 0. + let c = eval.mul(lv.p_is_zero, lv.mp_norm); + gated(eval, c); + // Mp_norm limb reconstruction. + let mp_norm_rec = eval.mad(lv.mp_norm_hi, c2_16, lv.mp_norm_lo); + let d = eval.sub(lv.mp_norm, mp_norm_rec); + gated(eval, d); + + // ---- eta / rel. EFF = (1 - is_zero)*MSB_biased; rel = eta - EFF. ---- + // P_MSB_biased = alpha_exp + x_eps_biased + b_p + 352. + let c352 = eval.u64(352); + let p_msb = { + let s = eval.add(lv.alpha_exp, lv.x_eps_biased); + let s = eval.add(s, lv.bp); + eval.add(s, c352) + }; + let eff_p = eval.mul(nonzero_p, p_msb); + let rel_p_expect = eval.sub(lv.eta, eff_p); + let d = eval.sub(lv.rel_p, rel_p_expect); + gated(eval, d); + // T_MSB_biased = t_exp + 385. + let c385 = eval.u64(385); + let t_msb = eval.add(lv.t_exp, c385); + let nonzero_t = eval.sub(one, lv.t_is_zero); + let eff_t = eval.mul(nonzero_t, t_msb); + let rel_t_expect = eval.sub(lv.eta, eff_t); + let d = eval.sub(lv.rel_t, rel_t_expect); + gated(eval, d); + // Attainment: rel_p * rel_t = 0 (one term defines eta; rel_p, rel_t >= 0 via RANGE16 pin eta + // as the max). Both-zero -> eta = 0. + let rr = eval.mul(lv.rel_p, lv.rel_t); + gated(eval, rr); + + // ---- far flags + two-sided slacks: far*(rel-27) + (1-far)*(26-rel) >= 0. ---- + let c27 = eval.u64(27); + let c26 = eval.u64(26); + for (far, rel, slack) in [(lv.far_p, lv.rel_p, lv.far_p_slack), (lv.far_t, lv.rel_t, lv.far_t_slack)] { + let rel_m27 = eval.sub(rel, c27); + let hi = eval.mul(far, rel_m27); + let not_far = eval.sub(one, far); + let c26_m_rel = eval.sub(c26, rel); + let lo = eval.mul(not_far, c26_m_rel); + let expect = eval.add(hi, lo); + let d = eval.sub(slack, expect); + gated(eval, d); + } + // active = (1 - far)*(1 - is_zero). + let d = { + let a = eval.sub(one, lv.far_p); + let ap = eval.mul(a, nonzero_p); + eval.sub(lv.active_p, ap) + }; + gated(eval, d); + let d = { + let a = eval.sub(one, lv.far_t); + let ap = eval.mul(a, nonzero_t); + eval.sub(lv.active_t, ap) + }; + gated(eval, d); + + // ---- alignment Euclidean floors: active rows: sig*8 = aligned*pow + rem, 0 <= rem < pow. ---- + // (pow is FP16POW2(rel) on active rows, 1 otherwise.) + #[allow(clippy::type_complexity)] + let align_terms: [(V, V, V, V, V, V, V, V, V, V, V, V, V); 2] = [ + ( + lv.active_p, lv.mp_norm, lv.pow_p, lv.aligned_p, lv.aligned_p_lo, lv.aligned_p_hi, lv.rem_p, lv.rem_p_lo, + lv.rem_p_hi, lv.rem_p_bound, lv.rem_p_bound_lo, lv.rem_p_bound_hi, lv.far_p, + ), + ( + lv.active_t, lv.t_mant, lv.pow_t, lv.aligned_t, lv.aligned_t_lo, lv.aligned_t_hi, lv.rem_t, lv.rem_t_lo, + lv.rem_t_hi, lv.rem_t_bound, lv.rem_t_bound_lo, lv.rem_t_bound_hi, lv.far_t, + ), + ]; + for (active, sig, pow, aligned, aligned_lo, aligned_hi, rem, rem_lo, rem_hi, rem_bound, rem_bound_lo, rem_bound_hi, _far) in + align_terms + { + let sig8 = eval.mul(c8, sig); + let ap = eval.mul(aligned, pow); + let floor = eval.sub(sig8, ap); + let floor = eval.sub(floor, rem); + // Degree-3 (active * degree-2); 0 on padding (active = 0 there), so no extra live gate. + let c = eval.mul(active, floor); + eval.constraint(c); + // rem + rem_bound + 1 = pow (active rows). + let rem_sum = eval.add(rem, rem_bound); + let rem_sum = eval.add(rem_sum, one); + let rem_id = eval.sub(rem_sum, pow); + let c = eval.mul(active, rem_id); + gated(eval, c); + // Inactive rows: aligned = 0, rem = 0. + let not_active = eval.sub(one, active); + let c = eval.mul(not_active, aligned); + gated(eval, c); + let c = eval.mul(not_active, rem); + gated(eval, c); + // Limb reconstructions (aligned, rem, rem_bound). + let rec = eval.mad(aligned_hi, c2_16, aligned_lo); + let d = eval.sub(aligned, rec); + gated(eval, d); + let rec = eval.mad(rem_hi, c2_16, rem_lo); + let d = eval.sub(rem, rec); + gated(eval, d); + let rec = eval.mad(rem_bound_hi, c2_16, rem_bound_lo); + let d = eval.sub(rem_bound, rec); + gated(eval, d); + } + + // ---- sticky bits. rem_*_nz = [rem != 0], so [rem == 0] = 1 - rem_*_nz. ---- + let rem_p_zero = eval.sub(one, lv.rem_p_nz); + is_zero_flag(eval, lv.rem_p, lv.rem_p_nz_inv, rem_p_zero, live); + let rem_t_zero = eval.sub(one, lv.rem_t_nz); + is_zero_flag(eval, lv.rem_t, lv.rem_t_nz_inv, rem_t_zero, live); + // or_p = far_p OR rem_p_nz; or_t likewise. + or_flag(eval, lv.far_p, lv.rem_p_nz, lv.or_p, live); + or_flag(eval, lv.far_t, lv.rem_t_nz, lv.or_t, live); + // sticky = (1 - is_zero)*or. + let st = eval.mul(nonzero_p, lv.or_p); + let d = eval.sub(lv.sticky_p, st); + gated(eval, d); + let st = eval.mul(nonzero_t, lv.or_t); + let d = eval.sub(lv.sticky_t, st); + gated(eval, d); + or_flag(eval, lv.sticky_p, lv.sticky_t, lv.far_sticky, live); + + // ---- signed window sum: |W| = (1-2*w_sign) * ((1-2*x_sign)*aligned_p + (1-2*t_sign)*aligned_t). ---- + let sgn = |eval: &mut E, s: V, a: V| { + let two_s = eval.mul(two, s); + let factor = eval.sub(one, two_s); + eval.mul(factor, a) + }; + let tp = sgn(eval, lv.x_sign, lv.aligned_p); + let tt = sgn(eval, lv.t_sign, lv.aligned_t); + let w_signed = eval.add(tp, tt); + let two_ws = eval.mul(two, lv.w_sign); + let wfac = eval.sub(one, two_ws); + let w_abs_expect = eval.mul(wfac, w_signed); + // Degree-3 (sign factor * degree-2 signed sum); 0 on padding, so no extra live gate. + let d = eval.sub(lv.w_abs, w_abs_expect); + eval.constraint(d); + is_zero_flag(eval, lv.w_abs, lv.w_abs_inv, lv.w_is_zero, live); + // A zero sum is +0 (sign pinned off). + let c = eval.mul(lv.w_is_zero, lv.w_sign); + gated(eval, c); + // |W| limb reconstruction. + let w_rec = eval.mad(lv.w_abs_hi, c2_16, lv.w_abs_lo); + let d = eval.sub(lv.w_abs, w_rec); + gated(eval, d); + + // ---- renormalize |W| (WIDTH32) + RNE. nonzero-W rows only. ---- + let nz_w = eval.sub(one, lv.w_is_zero); + // |W| * lift_w = M_rz * trunc_w + rz_rem, 0 <= rz_rem < trunc_w. + let lifted = eval.mul(lv.w_abs, lv.lift_w); + let truncated = eval.mul(lv.m_rz, lv.trunc_w); + let diff = eval.sub(lifted, truncated); + let diff = eval.sub(diff, lv.rz_rem); + // Degree-3 (nz_w * degree-2); 0 on padding (all columns 0), so no extra live gate. + let c = eval.mul(nz_w, diff); + eval.constraint(c); + let rem_sum = eval.add(lv.rz_rem, lv.rz_rem_bound); + let rem_sum = eval.add(rem_sum, one); + let rem_id = eval.sub(rem_sum, lv.trunc_w); + let c = eval.mul(nz_w, rem_id); + gated(eval, c); + // M_rz limb reconstruction (hi in [128,256) pinned by ctl -> M_rz in [2^23, 2^24)). + let m_rz_rec = eval.mad(lv.m_rz_hi, c2_16, lv.m_rz_lo); + let d = eval.sub(lv.m_rz, m_rz_rec); + gated(eval, d); + // parity split on M_rz low limb. + eval.constraint_bool(lv.rz_parity); + let two_half = eval.mul(two, lv.rz_half); + let recomposed = eval.add(two_half, lv.rz_parity); + let d = eval.sub(lv.m_rz_lo, recomposed); + gated(eval, d); + // gt = [2*rz_rem > trunc_w], two-sided slack. + let two_rem = eval.mul(two, lv.rz_rem); + { + let hi_arg = eval.sub(two_rem, lv.trunc_w); + let hi_arg = eval.sub(hi_arg, one); + let hi = eval.mul(lv.gt, hi_arg); + let not_gt = eval.sub(one, lv.gt); + let lo_arg = eval.sub(lv.trunc_w, two_rem); + let lo = eval.mul(not_gt, lo_arg); + let expect = eval.add(hi, lo); + let d = eval.sub(lv.gt_slack, expect); + gated(eval, d); + } + // eq = [trunc_w - 2*rz_rem == 0]. + let eq_arg = eval.sub(lv.trunc_w, two_rem); + is_zero_flag(eval, eq_arg, lv.eq_inv, lv.eq, live); + // Sign-aware sticky: STICKY_UP = STICKY_P*[X_SIGN==W_SIGN] + STICKY_T*[T_SIGN==W_SIGN]. At most + // one of STICKY_P/STICKY_T is set (the dominant term has rel=0, hence no sub-window remainder), + // so the sum is boolean. `[a==b]` for booleans is `1 - (a-b)^2`. + eval.constraint_bool(lv.sticky_up); + { + let match_flag = |eval: &mut E, a: V, b: V| { + let diff = eval.sub(a, b); + let sq = eval.mul(diff, diff); + eval.sub(one, sq) + }; + let mp = match_flag(eval, lv.x_sign, lv.w_sign); + let mt = match_flag(eval, lv.t_sign, lv.w_sign); + let up_p = eval.mul(lv.sticky_p, mp); + let up_t = eval.mul(lv.sticky_t, mt); + let up = eval.add(up_p, up_t); + let d = eval.sub(lv.sticky_up, up); + // Already 0 on padding (all operand/sticky columns are 0 there), so no live gate is needed — + // which also keeps this constraint at degree 3 (sticky * (1 - (sign-diff)^2)). + eval.constraint(d); + } + // or_rs = STICKY_UP + (1 - FAR_STICKY)*RZ_PARITY (the two summands are disjoint, so it is boolean): + // a same-sign remainder rounds the tie up; with no remainder, ties-to-even uses the parity. + { + let not_far = eval.sub(one, lv.far_sticky); + let parity_term = eval.mul(not_far, lv.rz_parity); + let expect = eval.add(lv.sticky_up, parity_term); + let d = eval.sub(lv.or_rs, expect); + gated(eval, d); + } + // round_up = gt + eq*or_rs. + let eqor = eval.mul(lv.eq, lv.or_rs); + let ru = eval.add(lv.gt, eqor); + let d = eval.sub(lv.round_up, ru); + gated(eval, d); + // carry = [2^24 - (M_rz + round_up) == 0]. + let m_out = eval.add(lv.m_rz, lv.round_up); + let carry_arg = eval.sub(c2_24, m_out); + is_zero_flag(eval, carry_arg, lv.carry_inv, lv.carry, live); + + // ---- result f32. nonzero-W: noised_exp = eta + w + carry - 412; mant = M_out_final - 2^23. ---- + // M_out_final = M_rz + round_up - carry*2^23. + let carry_term = eval.mul(lv.carry, c2_23); + let m_out_final = eval.sub(m_out, carry_term); + // noised_exp. + let c412 = eval.u64(EXP_OFFSET); + let exp_core = { + let s = eval.add(lv.eta, lv.ww); + let s = eval.add(s, lv.carry); + eval.sub(s, c412) + }; + let exp_expect = eval.mul(nz_w, exp_core); + let d = eval.sub(lv.noised_exp, exp_expect); + gated(eval, d); + // noised_mant = (1 - w_is_zero)*(M_out_final - 2^23). + let mant_core = eval.sub(m_out_final, c2_23); + let mant_expect = eval.mul(nz_w, mant_core); + let d = eval.sub(lv.noised_mant, mant_expect); + gated(eval, d); + // noised_sign = (1 - w_is_zero)*w_sign. + let sign_expect = eval.mul(nz_w, lv.w_sign); + let d = eval.sub(lv.noised_sign, sign_expect); + gated(eval, d); + // noised limb reconstruction: lo + 2^16*hi = sign*2^31 + exp*2^23 + mant. + let fields = { + let s = eval.mul(lv.noised_sign, c2_31); + let e = eval.mul(lv.noised_exp, c2_23); + let se = eval.add(s, e); + eval.add(se, lv.noised_mant) + }; + let limbs = eval.mad(lv.noised_hi, c2_16, lv.noised_lo); + let d = eval.sub(fields, limbs); + gated(eval, d); +} + +/// FP16 single-rounding FMA AIR (group G2). A CTL party (`requires_ctls`). +#[derive(Clone, Debug)] +pub struct NoisyQuantFmaStark, const D: usize> { + pub program: FmaProgram, + _phantom: PhantomData, +} + +impl, const D: usize> NoisyQuantFmaStark { + pub fn new(program: FmaProgram) -> Self { + Self { program, _phantom: PhantomData } + } +} + +impl, const D: usize> Stark for NoisyQuantFmaStark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_FMA_COLUMNS, NUM_FMA_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_fma_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_fma_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + use starky::util::trace_rows_to_poly_values; + + use super::super::columns::FMA_COL_MAP; + use super::super::ctl::fma_lut_lookups; + use super::*; + use crate::api::fp16::dtype::{f32_to_fp16, fp16_to_f32}; + use crate::api::fp8::dtype::{bf16_to_f32, f32_to_bf16}; + use crate::circuit::fp8::luts::LutTable; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type Stk = NoisyQuantFmaStark; + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + /// Decode a finite f32 `t` into `(sign, M_t, exp)` as group G1 emits it. + fn t_fields(t: f32) -> (u64, u64, u64) { + let b = t.to_bits(); + let sign = u64::from(b >> 31); + let exp = u64::from((b >> 23) & 0xFF); + if exp == 0 { + (sign, 0, 0) // zero (envelope: t is G1's output = normal or zero) + } else { + (sign, (1u64 << 23) + u64::from(b & 0x7F_FFFF), exp) + } + } + + fn trace_from(items: &[(u16, u16, f32)]) -> (FmaProgram, Vec<[F; NUM_FMA_COLUMNS]>) { + let n = items.len(); + let program = FmaProgram::new(n); + let alpha: Vec = items.iter().map(|x| x.0).collect(); + let raw: Vec = items.iter().map(|x| x.1).collect(); + let tf: Vec<(u64, u64, u64)> = items.iter().map(|x| t_fields(x.2)).collect(); + let ts: Vec = tf.iter().map(|x| x.0).collect(); + let tm: Vec = tf.iter().map(|x| x.1).collect(); + let te: Vec = tf.iter().map(|x| x.2).collect(); + let rows = program.generate_trace::(&alpha, &raw, &ts, &tm, &te); + (program, rows) + } + + fn constraints_violated(stark: &Stk, rows: &[[F; NUM_FMA_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().iter().any(|&acc| acc != F::ZERO) + }) + } + + /// Deterministic in-envelope sample: normal `alpha`, finite `raw`, moderate `t` (occasionally 0). + fn sample(seed: u64) -> (u16, u16, f32) { + let mut s = seed.wrapping_add(0x9E3779B97F4A7C15); + let mut next = || { + s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + s + }; + let alpha = f32_to_bf16(0.5 + (next() % 64) as f32 * 0.5).unwrap(); + // A finite FP16 code (exponent field != 0x1F): signed, any mantissa. + let raw = { + let sign = ((next() & 1) as u16) << 15; + let exp = ((next() % 31) as u16) << 10; // [0, 30] + let man = (next() % 1024) as u16; + sign | exp | man + }; + let t = if next() % 7 == 0 { + 0.0 + } else { + let mag = 2f32.powi(((next() % 20) as i32) - 8) * (1.0 + (next() % 1000) as f32 / 1000.0); + if next() & 1 == 0 { mag } else { -mag } + }; + (alpha, raw, t) + } + + fn ref_noised(alpha: u16, raw: u16, t: f32) -> f32 { + bf16_to_f32(alpha).mul_add(fp16_to_f32(raw), t) + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + let items: Vec<_> = (0..60).map(sample).collect(); + let (program, rows) = trace_from(&items); + assert_eq!(rows.len(), 64); + let known = program.known_values::(); + for (r, row) in rows.iter().enumerate() { + assert_eq!(known[0].values[r], row[FMA_COL_MAP.is_pad], "is_pad row {r}"); + } + assert!(!constraints_violated(&Stk::new(program), &rows), "honest trace violated a constraint"); + } + + #[test] + fn fma_bit_exact_vs_reference_fma() { + // Cover: cancellation, far gaps, zero t, zero X, carry, power-of-two result, random. + let mut items: Vec<(u16, u16, f32)> = Vec::new(); + // Cancellation: af*X = +k, t = -k (exact). + items.push((f32_to_bf16(2.0).unwrap(), f32_to_fp16(3.0).unwrap(), -6.0)); // 6 - 6 = 0 + items.push((f32_to_bf16(2.0).unwrap(), f32_to_fp16(3.0).unwrap(), -5.75)); // near-cancel + // Far gap: af*X ~ 1e3, t ~ 1e-6. + items.push((f32_to_bf16(8.0).unwrap(), f32_to_fp16(100.0).unwrap(), 1e-6)); + items.push((f32_to_bf16(8.0).unwrap(), f32_to_fp16(100.0).unwrap(), -1e-6)); + // t dominates, P tiny. + items.push((f32_to_bf16(1.0).unwrap(), f32_to_fp16(2f32.powi(-14)).unwrap(), 1234.5)); + // Zero t. + items.push((f32_to_bf16(3.0).unwrap(), f32_to_fp16(5.0).unwrap(), 0.0)); + // Zero X (raw = 0): noised = t. + items.push((f32_to_bf16(3.0).unwrap(), 0u16, 7.25)); + // Power-of-two result. + items.push((f32_to_bf16(1.0).unwrap(), f32_to_fp16(1.0).unwrap(), 0.0)); + items.push((f32_to_bf16(1.0).unwrap(), f32_to_fp16(1.0).unwrap(), 3.0)); // 1+3 = 4 + // Random coverage. + for s in 0..400 { + items.push(sample(s)); + } + // Keep only in-envelope rows (f32-normal result) to avoid the generator's envelope panic. + items.retain(|&(a, r, t)| { + let n = ref_noised(a, r, t); + let e = (n.abs().to_bits() >> 23) & 0xFF; + n != 0.0 && (1..=254).contains(&e) || n == 0.0 + }); + let (_program, rows) = trace_from(&items); + for (e, &(a, r, t)) in items.iter().enumerate() { + let reference = ref_noised(a, r, t); + let got_lo = to_u64(rows[e][FMA_COL_MAP.noised_lo]); + let got_hi = to_u64(rows[e][FMA_COL_MAP.noised_hi]); + let got = (got_hi << 16) | got_lo; + if reference == 0.0 { + assert_eq!(got & 0x7FFF_FFFF, 0, "elem {e}: expected zero noised"); + } else { + assert_eq!(got as u32, reference.to_bits(), "elem {e}: noised mismatch (alpha={a:#06x} raw={r:#06x} t={t})"); + } + } + } + + /// Bit-exact against the real `noisy_quantize`: derive `t = bf*N` and `noised` from the AIR, and + /// check the AIR's `noised` reproduces the kernel's per-element FMA. + #[test] + fn fma_bit_exact_vs_noisy_quantize() { + use crate::api::fp16::quantization::{noisy_quantize, row_norms}; + const R: usize = 32; + let k = 48usize; + let rows_in: Vec = (0..k) + .map(|j| f32_to_fp16(if j == 0 { 7.5 } else { 1.0 + (j % 5) as f32 * 0.25 }).unwrap()) + .collect(); + let e: Vec = (0..R).map(|t| f32_to_fp16(((t % 5) as f32 - 2.0) * 8.0).unwrap()).collect(); + let f: Vec = (0..k * R).map(|t| f32_to_fp16(((t % 7) as f32 - 3.0) * 8.0).unwrap()).collect(); + let norms = [row_norms(&rows_in).unwrap()]; + let built = noisy_quantize(&rows_in, &e, &f, &norms, R).unwrap(); + let noise = crate::api::fp16::accumulate::a100_matmul(&e, &f, None, 1, k, R); + let bf = bf16_to_f32(built.beta[0]); + let af = bf16_to_f32(built.alpha[0]); + + let items: Vec<(u16, u16, f32)> = + (0..k).map(|j| (built.alpha[0], rows_in[j], bf * noise[j])).collect(); + let (_program, trace) = trace_from(&items); + for j in 0..k { + let noised_ref = af.mul_add(fp16_to_f32(rows_in[j]), bf * noise[j]); + let got = (to_u64(trace[j][FMA_COL_MAP.noised_hi]) << 16) | to_u64(trace[j][FMA_COL_MAP.noised_lo]); + assert_eq!(got as u32, noised_ref.to_bits(), "noised mismatch elem {j}"); + // And the cast of the AIR-derived noised matches the kernel's published FP16 code. + let out = f32_to_fp16(f32::from_bits(got as u32)).unwrap(); + assert_eq!(out, built.noised_part[j], "end-to-end FP16 code mismatch elem {j}"); + } + } + + #[test] + fn tampered_traces_fail() { + let items: Vec<_> = (0..16).map(sample).collect(); + let (program, rows) = trace_from(&items); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "baseline honest trace must pass"); + for (name, col) in [ + ("alpha", FMA_COL_MAP.alpha), + ("x_sig", FMA_COL_MAP.x_sig), + ("mp", FMA_COL_MAP.mp), + ("mp_norm", FMA_COL_MAP.mp_norm), + ("eta", FMA_COL_MAP.eta), + ("rel_p", FMA_COL_MAP.rel_p), + ("aligned_p", FMA_COL_MAP.aligned_p), + ("aligned_t", FMA_COL_MAP.aligned_t), + ("w_abs", FMA_COL_MAP.w_abs), + ("w_sign", FMA_COL_MAP.w_sign), + ("m_rz", FMA_COL_MAP.m_rz), + ("round_up", FMA_COL_MAP.round_up), + ("noised_exp", FMA_COL_MAP.noised_exp), + ("noised_mant", FMA_COL_MAP.noised_mant), + ("noised_lo", FMA_COL_MAP.noised_lo), + ] { + let mut forged = rows.clone(); + forged[0][col] += F::ONE; + assert!(constraints_violated(&stark, &forged), "{name} tamper undetected"); + } + } + + /// RNE uniqueness (ties-to-even): find a row whose final round is an exact tie (`eq = 1`) with + /// `round_up = 0` (even significand, no sticky); forging `round_up = 1` is rejected by the + /// `round_up = gt + eq*(far_sticky OR parity)` constraint — no quarter-ulp slack. + #[test] + fn fma_round_ties_to_even_is_pinned() { + let mut found = false; + for s in 0..20000u64 { + let item = sample(s); + let n = ref_noised(item.0, item.1, item.2); + let ebit = (n.abs().to_bits() >> 23) & 0xFF; + if n == 0.0 || !(1..=254).contains(&ebit) { + continue; + } + let (program, rows) = trace_from(&[item]); + if to_u64(rows[0][FMA_COL_MAP.eq]) == 1 && to_u64(rows[0][FMA_COL_MAP.round_up]) == 0 { + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "honest tie row passes"); + let mut forged = rows.clone(); + forged[0][FMA_COL_MAP.round_up] = F::ONE; // round up at an even tie + assert!(constraints_violated(&stark, &forged), "ties-to-even: forced round-up rejected"); + found = true; + break; + } + } + assert!(found, "expected to find an exact-tie row in the sample space"); + } + + #[test] + fn honest_lut_keys_are_in_domain() { + let items: Vec<_> = (0..40).map(sample).collect(); + let (program, rows) = trace_from(&items); + let live = program.live_rows(); + let polys = trace_rows_to_poly_values(rows); + let lu = fma_lut_lookups::(); + for (li, lookup) in lu.iter().enumerate() { + for r in 0..live { + match lookup.table { + LutTable::Range16 => { + // Filtered lookups (the [128,256) hi checks) are only meaningful where active. + let active = lookup.filter.eval_table(&polys, r, &[]).to_canonical_u64(); + if active == 0 { + continue; + } + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k < 1 << 16, "RANGE16 lookup {li} key {k} out of range at row {r}"); + } + LutTable::Fp16Pow2 => { + let active = lookup.filter.eval_table(&polys, r, &[]).to_canonical_u64(); + if active == 0 { + continue; + } + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + let v = lookup.values[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k <= 255, "FP16POW2 key {k} at row {r}"); + assert_eq!(v, 1 << k.min(26), "FP16POW2 value {v} != 2^min({k},26) at row {r}"); + } + LutTable::Width32 => { + let active = lookup.filter.eval_table(&polys, r, &[]).to_canonical_u64(); + if active == 0 { + continue; + } + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!((1..=32).contains(&k), "WIDTH32 key {k} at row {r}"); + let tp = lookup.values[0].eval_table(&polys, r, &[]).to_canonical_u64(); + let lp = lookup.values[1].eval_table(&polys, r, &[]).to_canonical_u64(); + assert_eq!(tp, 1 << (k.saturating_sub(24)), "trunc at {r}"); + assert_eq!(lp, 1 << (24u64.saturating_sub(k)), "lift at {r}"); + } + LutTable::Fp16Decode => {} + other => panic!("unexpected table {other:?}"), + } + } + } + } + + #[test] + fn degree_is_at_most_three() { + let (program, _) = trace_from(&(0..8).map(sample).collect::>()); + test_stark_low_degree::(Stk::new(program)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + let (program, _) = trace_from(&(0..8).map(sample).collect::>()); + test_stark_circuit_constraints::(Stk::new(program)).unwrap(); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_stark/columns.rs b/zk-pow/src/circuit/fp16/noisy_quant_stark/columns.rs new file mode 100644 index 000000000..13e474ec2 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_stark/columns.rs @@ -0,0 +1,272 @@ +//! Fixed trace layout for the FP16 fused noisy-quantization AIR. +//! +//! One row per operand element `(i, j)`. The AIR proves two of the three f32 roundings of the +//! plaintext ground truth [`crate::api::fp16::quantization::noisy_quantize`]'s per-element fused +//! kernel +//! +//! ```text +//! t = RNE_f32(bf * N_ij) // group G1 (pre-FMA f32 multiply) +//! noised = fma(af, X_ij, t) // SINGLE-rounding f32 FMA — GROUP G2, DEFERRED (see mod.rs) +//! out = f32_to_fp16(clamp(noised, -MAX, MAX)) // group G3 (clamp + FP16 cast) +//! ``` +//! +//! with `af = bf16_to_f32(alpha)`, `bf = bf16_to_f32(beta)`, `X_ij = fp16_to_f32(raw_ij)`. +//! +//! `alpha`, `beta`, `raw`, the noise word `N_ij` and the fused f32 `noised` all enter as witness +//! **input** columns; binding `raw`/`N`/`noised`/`out` to their producing/consuming stages (the +//! operand commitment, the `N = E@F^T` matmul, the single-rounding FMA, and the output tile) is a +//! set of separate later CTL stages — this AIR proves the arithmetic of G1 and G3 only, and +//! [`super::ctl`] exposes the parameterized channel hooks. See [`super::stark`] for the +//! constraint groups and the documented soundness envelope. +//! +//! [`NoisyQuantColumnsView`] is `#[repr(C)]`; declaration order is committed column order. + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one `NoisyQuantStark` trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct NoisyQuantColumnsView { + // ------------------------------------------------------------------------------------------ + // Class (a) ("known") column (verifier-recomputed, checked against the trace openings). Must + // come first. + // ------------------------------------------------------------------------------------------ + /// 1 on the trailing padding rows (live elements padded to a power of two). + pub is_pad: T, + /// The operand-row index this element belongs to (`floor(element / k)`): A rows `0..h`, B rows + /// `h..h+w`, in one disjoint space. The scales-import CTL's key, matching + /// [`crate::circuit::fp16::row_scale_stark`]'s `OPERAND_ROW_INDEX` so each element consumes its + /// own operand row's `(alpha, beta)`. A known column (recomputed by the verifier). Held at the + /// final live index on padding rows (filtered out of the CTL). + pub operand_row_index: T, + /// The global operand element index this row proves (`e` in `0..(h+w)*k`, the trace row index on + /// live rows; held at the final live index on padding). Known column (recomputed by the + /// verifier). The two operand-provenance channels key on it: + /// * **operand-bytes** (6c): key `2*ELEMENT_INDEX` = the element's low-byte offset in the Blake3 + /// operand stream, so the committed byte pair (Blake3) equals this element's `RAW`. + /// * **operand-codes** (6d): key `ELEMENT_INDEX` = the matmul's `operand_index_base_{a,b} + lane`, + /// so the matmul's operand code equals this element's noised `OUT`. + pub element_index: T, + /// The matmul reuse multiplicity of this element (`w` for an A-side element — reused in `w` + /// output cells — and `h` for a B-side element). Known column (recomputed by the verifier). It is + /// the per-row multiplicity the operand-codes (6d) looked side carries, so the single + /// `ELEMENT_INDEX` key balances the matmul's repeated lookups of each operand element. Held at the + /// final live element's multiplicity on padding rows (filtered out of the CTL by `1 - IS_PAD`). + pub operand_mult: T, + + // ------------------------------------------------------------------------------------------ + // Pure CTL-hook inputs (NOT constrained by this AIR; bound to their producing stages later). + // ------------------------------------------------------------------------------------------ + /// The per-row clean-operand scale `alpha` (BF16 code). Hook for the deferred G2 FMA. + pub alpha: T, + /// The clean FP16 operand code `X_ij`. Hook for the operand-commitment binding. + pub raw: T, + /// The deferred-G2 FMA output `noised` as an f32, low 16-bit limb. Hook + G3 decodes it. + pub noised_lo: T, + /// `noised` high 16-bit limb. + pub noised_hi: T, + + // ========================================================================================== + // GROUP G1 — t = RNE_f32(bf * N_ij). + // ========================================================================================== + /// The per-row noise scale `beta` (BF16 code); decoded below. + pub beta: T, + /// BF16 exponent field of `beta` (structurally normal positive). + pub beta_exp: T, + /// BF16 mantissa field of `beta` in `[0, 127]` (`M_beta = 128 + BETA_MANT`). + pub beta_mant: T, + /// The noise word `N_ij` as an f32, low 16-bit limb. Hook for the `N = E@F^T` binding. + pub noise_lo: T, + /// `N_ij` high 16-bit limb. + pub noise_hi: T, + /// Sign bit of `N_ij`. + pub noise_sign: T, + /// f32 exponent field of `N_ij` (`[0, 254]`; envelope: normal, or 0 meaning exact zero). + pub noise_exp: T, + /// f32 23-bit trailing significand of `N_ij`. + pub noise_mant: T, + /// Low 16-bit limb of `NOISE_MANT`. + pub noise_mant_lo: T, + /// High 7-bit limb of `NOISE_MANT` (`NOISE_MANT = lo + 2^16*hi`). + pub noise_mant_hi: T, + /// `[NOISE_EXP == 0]` flag — a zero (or, out of envelope, subnormal) noise word gives `t = 0`. + pub noise_is_zero: T, + /// Inverse witness for the `[NOISE_EXP == 0]` is-zero gadget. + pub noise_exp_inv: T, + /// Noise significand `M_N = (1 - NOISE_IS_ZERO)*2^23 + NOISE_MANT` (24-bit, 0 when zero). + pub mn: T, + /// Exact product significand `P = M_beta * M_N < 2^32` (0 when the noise is zero). + pub pm: T, + /// Low 16-bit limb of `P`. + pub pm_lo: T, + /// High 16-bit limb of `P` (`P = lo + 2^16*hi`). + pub pm_hi: T, + /// RNE rounding shift `d1 = bitlen(P) - 24 in {7, 8}` (FP16POW2 key; 0 when the noise is zero). + pub t_shift: T, + /// `2^d1` (FP16POW2 value; 1 when the noise is zero). + pub t_pow: T, + /// 24-bit significand `M_t = RNE(P / 2^d1) in [2^23, 2^24)` of `t` (0 when the noise is zero). + pub t_mant: T, + /// Low 16-bit limb of `M_t`. + pub t_mant_lo: T, + /// High limb of `M_t` in `[128, 256)` (`M_t = lo + 2^16*hi`). + pub t_mant_hi: T, + /// Binade-bottom flag `[M_t == 2^23]` (significand is a power of two): lower boundary is + /// `-ulp/4`, not `-ulp/2`. Boolean, pinned by the is-zero gadget on `M_t - 2^23`. + pub t_bottom: T, + /// Inverse witness for the `[M_t == 2^23]` is-zero gadget. + pub t_bottom_inv: T, + /// `M_t & 1` (ties-to-even parity; boolean). + pub t_parity: T, + /// `(T_MANT_LO - T_PARITY) / 2` (RANGE16; two-sided parity split on M_t's low limb, which + /// shares M_t's parity since the high limb's `2^16` weight is even — keeps T_HALF a single limb). + pub t_half: T, + /// Lower quarter-ulp boundary product `(4*M_t - 2 + T_BOTTOM) * 2^d1`. + pub t_blo: T, + /// Upper quarter-ulp boundary product `(4*M_t + 2) * 2^d1`. + pub t_bhi: T, + /// Middle limb of the lower bracket slack `4*P - T_BLO - T_PARITY` (`< 2^34`). + pub t_sl_mid: T, + /// Top limb (bits 32..) of the lower bracket slack. + pub t_sl_hi: T, + /// Middle limb of the upper bracket slack `T_BHI - 4*P - T_PARITY`. + pub t_su_mid: T, + /// Top limb of the upper bracket slack. + pub t_su_hi: T, + /// f32 exponent field of `t` (`BETA_EXP + NOISE_EXP + T_SHIFT - 134` when nonzero, else 0). + pub t_exp: T, + + // ========================================================================================== + // GROUP G3 — out = f32_to_fp16(noised). (The clamp is subsumed: f32_to_fp16 already + // saturates, so f32_to_fp16(clamp(x, +/-MAX)) == f32_to_fp16(x) for every finite x.) + // ========================================================================================== + /// Sign bit of `noised`. + pub noised_sign: T, + /// f32 exponent field of `noised` in `[1, 254]` (any normal f32 — the FP16 cast then lands in + /// the normal/subnormal/zero/saturating branch per its exponent). + pub noised_exp: T, + /// f32 23-bit trailing significand of `noised`. + pub noised_mant: T, + /// Low 16-bit limb of `NOISED_MANT`. + pub noised_mant_lo: T, + /// High 7-bit limb of `NOISED_MANT`. + pub noised_mant_hi: T, + // --- Branch classification by the f32 exponent E: saturate (E>=143), normal (113<=E<=142), + // subnormal (102<=E<=112), zero (E<=101). Three monotone flags + two-sided slacks pin them. + /// `F_SAT = [E >= 143]`. + pub f_sat: T, + /// Two-sided slack: `F_SAT*(E-143) + (1-F_SAT)*(142-E) >= 0`. + pub sat_slack: T, + /// `GE113 = [E >= 113]`. + pub ge113: T, + /// Two-sided slack: `GE113*(E-113) + (1-GE113)*(112-E) >= 0`. + pub ge113_slack: T, + /// Normal-output flag `F_NORM = GE113*(1 - F_SAT)`. + pub f_norm: T, + /// `GE102 = [E >= 102]`. + pub ge102: T, + /// Two-sided slack: `GE102*(E-102) + (1-GE102)*(101-E) >= 0`. + pub ge102_slack: T, + /// Subnormal-output flag `F_SUB = GE102*(1 - GE113)`. + pub f_sub: T, + /// Zero-output flag `F_ZERO = 1 - GE102`. + pub f_zero: T, + /// Cast rounding shift: `13` on the normal branch, `126 - E` on the subnormal branch, `0` + /// otherwise (FP16POW2 key; `<= 24`). + pub cast_shift: T, + /// `2^CAST_SHIFT` (FP16POW2 value; `1` off the rounding branches). + pub cast_pow: T, + /// Rounded significand `q = RNE((2^23 + NOISED_MANT) / 2^CAST_SHIFT)` on the rounding branches: + /// `[2^10, 2^11]` (normal) or `[0, 2^10]` (subnormal). + pub q: T, + /// RANGE16 slack `q - 2^10 >= 0` (normal branch only). + pub q_lo_slack: T, + /// Binade-bottom flag `[q == 2^10]`. + pub q_bottom: T, + /// Inverse witness for the `[q == 2^10]` is-zero gadget (on `q - 2^10`). + pub q_bottom_inv: T, + /// `q & 1` (ties-to-even parity; boolean). + pub q_parity: T, + /// `(q - Q_PARITY) / 2` (RANGE16). + pub q_half: T, + /// Lower quarter-ulp boundary product `(4*q - 2 + Q_BOTTOM) * CAST_POW`. + pub cast_blo: T, + /// Upper quarter-ulp boundary product `(4*q + 2) * CAST_POW`. + pub cast_bhi: T, + /// High 16-bit limb of the lower bracket slack `4*(2^23 + NOISED_MANT) - CAST_BLO - Q_PARITY`. + pub cast_sl_hi: T, + /// High 16-bit limb of the upper bracket slack `CAST_BHI - 4*(2^23 + NOISED_MANT) - Q_PARITY`. + pub cast_su_hi: T, + /// Rounding-carry flag `[q == 2^11]` (normal round overflowed the significand; exponent bumps). + pub carry: T, + /// Inverse witness for the `[q == 2^11]` is-zero gadget (on `2^11 - q`). + pub carry_inv: T, + /// `[NOISED_EXP == 142]` flag (a normal carry here means `e_adj = 16`, i.e. saturation). + pub e142: T, + /// Inverse witness for the `[NOISED_EXP == 142]` is-zero gadget (on `142 - NOISED_EXP`). + pub e142_inv: T, + /// `CCE = CARRY * E142` (committed to keep the saturation-fold degree <= 3). + pub cce: T, + /// Effective saturation flag `IS_SAT_EFF = F_SAT + F_NORM*CCE` (also the FP16-inf carry case). + pub is_sat_eff: T, + /// Non-saturating normal flag `FNNS = F_NORM*(1 - CCE)`. + pub fnns: T, + /// Normal FP16 output mantissa field `(1 - CARRY)*(q - 2^10)` (degree-budget helper). + pub mf: T, + /// `(1 - IS_PAD) * (1 - NOISE_IS_ZERO)` — the live-and-nonzero-noise gate for G1's bracket + /// (committed so that gating degree-2 boundary constraints stays degree <= 3; boolean). + pub nz_live: T, + /// The output FP16 code. + pub out: T, +} + +/// Total number of committed columns. +pub const NUM_NOISY_QUANT_COLUMNS: usize = size_of::>(); + +const _: () = assert!(NUM_NOISY_QUANT_COLUMNS == 76); + +/// No public inputs: the identity is program-independent (geometry enters via `IS_PAD` + height). +pub const NUM_NOISY_QUANT_PUBLIC_INPUTS: usize = 0; + +columns_view!(NoisyQuantColumnsView, NUM_NOISY_QUANT_COLUMNS, NOISY_QUANT_COL_MAP); + +/// Number of leading class (a) ("known") columns: `IS_PAD`, `OPERAND_ROW_INDEX`, `ELEMENT_INDEX` +/// and `OPERAND_MULT`. +pub const NUM_NOISY_QUANT_KNOWN_COLUMNS: usize = NOISY_QUANT_COL_MAP.operand_mult + 1; + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_NOISY_QUANT_COLUMNS] = NOISY_QUANT_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + assert_eq!(NOISY_QUANT_COL_MAP.is_pad, 0); + assert_eq!(NOISY_QUANT_COL_MAP.operand_row_index, 1); + assert_eq!(NOISY_QUANT_COL_MAP.element_index, 2); + assert_eq!(NOISY_QUANT_COL_MAP.operand_mult, 3); + assert_eq!(NUM_NOISY_QUANT_KNOWN_COLUMNS, 4); + assert_eq!(NOISY_QUANT_COL_MAP.out, NUM_NOISY_QUANT_COLUMNS - 1); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_NOISY_QUANT_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: NoisyQuantColumnsView = arr.into(); + assert_eq!(view.is_pad, 1); + assert_eq!(view.pm, NOISY_QUANT_COL_MAP.pm as u64 * 3 + 1); + let back: [u64; NUM_NOISY_QUANT_COLUMNS] = view.into(); + assert_eq!(back, arr); + + let borrowed: &NoisyQuantColumnsView = arr.borrow(); + assert_eq!(borrowed.out, arr[NOISY_QUANT_COL_MAP.out]); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_stark/ctl.rs b/zk-pow/src/circuit/fp16/noisy_quant_stark/ctl.rs new file mode 100644 index 000000000..76461762c --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_stark/ctl.rs @@ -0,0 +1,278 @@ +//! Cross-table-lookup declarations for the FP16 NoisyQuantStark. +//! +//! Two kinds of channel: +//! +//! * **Parameterized hooks** — this AIR proves only the two roundings G1/G3 (see [`super::stark`]); +//! binding its witness inputs to their producing/consuming stages is left to later integration, +//! so each builder takes the counterparty table's batch index explicitly, exactly like +//! [`crate::circuit::fp16::xor_fold_stark::ctl`] and [`crate::circuit::fp16::noise_stark::ctl`] +//! (NoisyQuantStark is not registered in [`crate::circuit::fp16::ctl`]): +//! - [`ctl_raw_operand_looking`] exposes `raw` (the clean FP16 operand) for the operand commitment. +//! - [`ctl_noise_word_looking`] exposes the noise word `N_ij` (two f32 limbs) for the `N = E@F^T` +//! matmul. +//! - [`ctl_fma_hook_looking`] exposes `(alpha, raw, t_sign, t_mant, t_exp, noised_lo, noised_hi)` +//! so the **deferred G2** single-rounding FMA stage can bind `noised = fma(af, X, t)`. +//! - [`ctl_output_looking`] exposes `out` for the output-tile commitment. +//! * The committed-LUT inventory ([`noisy_quant_lut_lookups`]): the RANGE16 limb/slack range checks +//! and the FP16POW2 shift that make G1's and G3's ties-to-even brackets sound. No new table is +//! introduced — every fact targets the shared `RANGE16` and `FP16POW2` tables of the FP16 batch. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::NOISY_QUANT_COL_MAP; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// The live-row filter `1 - IS_PAD`. +fn live_filter() -> Filter { + Filter::from_column(Column::linear_combination_with_constant([(NOISY_QUANT_COL_MAP.is_pad, -F::ONE)], F::ONE)) +} + +/// The live-and-nonzero-noise filter `NZ_LIVE` (a committed boolean = `(1-IS_PAD)*(1-NOISE_IS_ZERO)`). +fn nz_live_filter() -> Filter { + Filter::from_column(Column::single(NOISY_QUANT_COL_MAP.nz_live)) +} + +/// Hook: the clean FP16 operand code `raw`, filter `1 - IS_PAD`. Counterparty: the operand +/// commitment (index supplied at integration time). +pub fn ctl_raw_operand_looking(table: usize) -> TableWithColumns { + TableWithColumns::new(TableIdx::from(table), vec![Column::single(NOISY_QUANT_COL_MAP.raw)], live_filter()) +} + +/// Hook: the noise word `N_ij` (low, high f32 limbs), filter `1 - IS_PAD`. Counterparty: the +/// `N = E@F^T` noise matmul. +pub fn ctl_noise_word_looking(table: usize) -> TableWithColumns { + TableWithColumns::new( + TableIdx::from(table), + Column::singles([NOISY_QUANT_COL_MAP.noise_lo, NOISY_QUANT_COL_MAP.noise_hi]).collect(), + live_filter(), + ) +} + +/// 6e noise-word **looked** side: `(ELEMENT_INDEX, NOISE_LO, NOISE_HI)` per live element, filter +/// `1 - IS_PAD`. The key `ELEMENT_INDEX` is the global operand element index (A elements `0..h*k`, +/// B elements past them), matching the `N = E@F^T` noise matmul's `CELL_ID = i*k + j` (its output is +/// `(h+w) x k`, row-major). `(NOISE_LO, NOISE_HI)` is the f32 noise word this element's G1 rounding +/// consumes (low/high 16-bit limbs). The noise matmul's looking side +/// ([`crate::circuit::fp16::matmul_a100_stark::ctl::ctl_cell_results_looked_matmul`]) emits each +/// finished cell's `(CELL_ID, CELL_RESULT_F32_LO, CELL_RESULT_F32_HI)` once, so the multiset balance +/// forces every consumed noise word to equal the proven `E@F^T` product — closing the noise's +/// free-witness gap (increment 6e-1). `E`/`F` remain free witness (binding them to the seed-derived +/// keyed-XOF lines is increment 6e-2/6e-3), so the noise is `E@F` but not yet seed-bound. +pub fn ctl_noise_word_looked_noisy_quant(table: usize) -> TableWithColumns { + let m = &NOISY_QUANT_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + Column::singles([m.element_index, m.noise_lo, m.noise_hi]).collect(), + live_filter(), + ) +} + +/// Hook: the deferred-G2 FMA tuple `(alpha, raw, t_sign, t_mant, t_exp, noised_lo, noised_hi)`, +/// filter `1 - IS_PAD`. The G2 stage proves `noised = fma(bf16_to_f32(alpha), fp16_to_f32(raw), t)` +/// where `t` is reconstructed from `(t_sign, t_mant, t_exp)`; `t_sign = NOISE_SIGN`. +pub fn ctl_fma_hook_looking(table: usize) -> TableWithColumns { + let m = &NOISY_QUANT_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + Column::singles([m.alpha, m.raw, m.noise_sign, m.t_mant, m.t_exp, m.noised_lo, m.noised_hi]).collect(), + live_filter(), + ) +} + +/// Hook: the output FP16 code `out`, filter `1 - IS_PAD`. Counterparty: the output-tile commitment. +pub fn ctl_output_looking(table: usize) -> TableWithColumns { + TableWithColumns::new(TableIdx::from(table), vec![Column::single(NOISY_QUANT_COL_MAP.out)], live_filter()) +} + +/// 6c operand-bytes **looked** side: `(2*ELEMENT_INDEX, RAW)` per live element, filter `1 - IS_PAD`. +/// The key `2*ELEMENT_INDEX` is the element's low-byte offset in the Blake3 operand stream (A +/// elements `0..h*k` at byte `2*e`, B elements at byte `2*h*k + 2*e_B = 2*e`), matching Blake3's +/// looking side ([`crate::circuit::fp16::blake3_commit::ctl_operand_bytes_looking_blake3`], key +/// `CTL_KEY_BASE + 2j`, value the committed LE `u16`). Each committed operand element crosses exactly +/// once on each side, so the multiset balance forces `RAW` to equal the committed byte pair — the +/// clean operand the matmul's noised codes derive from (Blake3's bytes are BYTES2-checked, making the +/// pair packing sound). Closes audit Finding 3's operand-bytes leg. +pub fn ctl_operand_bytes_looked_noisy_quant(table: usize) -> TableWithColumns { + let m = &NOISY_QUANT_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + vec![ + Column::linear_combination([(m.element_index, F::from_canonical_u64(2))]), + Column::single(m.raw), + ], + live_filter(), + ) +} + +/// 6d operand-codes **looked** side: `(ELEMENT_INDEX, OUT)` per live element, filter +/// `OPERAND_MULT * (1 - IS_PAD)` (a degree-2 multiplicity filter). The key `ELEMENT_INDEX` is the +/// matmul's `operand_index_base_{a,b} + lane` global element index; `OUT` is the proven noised FP16 +/// code. The matmul reuses each A element in `w` output cells and each B element in `h` cells, so the +/// multiplicity `OPERAND_MULT` (`w` on A rows, `h` on B rows) lets this single keyed tuple balance +/// the matmul's repeated lookups ([`crate::circuit::fp16::matmul_a100_stark::ctl::ctl_operand_codes_looking_matmul`]). +/// The multiset equality binds BOTH operand provenance (matmul code == noised `OUT`) AND cross-cell +/// row/column sharing (every cell of a row reuses the same A element because they look up the same +/// key). Closes audit Finding 3's noised->matmul leg. +pub fn ctl_operand_codes_looked_noisy_quant(table: usize) -> TableWithColumns { + let m = &NOISY_QUANT_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + vec![Column::single(m.element_index), Column::single(m.out)], + Filter::new( + vec![( + Column::single(m.operand_mult), + Column::linear_combination_with_constant([(m.is_pad, -F::ONE)], F::ONE), + )], + vec![], + ), + ) +} + +/// NoisyQuantStark's per-row committed-LUT inventory (RANGE16 + FP16POW2 only). +pub fn noisy_quant_lut_lookups() -> Vec> { + let m = &NOISY_QUANT_COL_MAP; + let one = F::ONE; + let neg = -F::ONE; + let two16 = F::from_canonical_u64(1 << 16); + let two32 = F::from_canonical_u64(1 << 32); + let live = live_filter::(); + let mut lu: Vec> = Vec::new(); + + // ---- FP16POW2: the G1 rounding shift 2^d1, keyed on T_SHIFT (filtered live; zero-noise rows + // present key 0 -> value 1, a valid in-domain entry). ---- + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.t_shift)], + values: vec![Column::single(m.t_pow)], + filter: live.clone(), + }); + + // ---- G1 field range checks. ---- + // beta_mant < 128 (the 2^9-scaled check), noise_exp < 256 (2^8-scaled), noise_mant_hi < 2^7. + lu.push(LutLookup::rc16(Column::linear_combination([(m.beta_mant, F::from_canonical_u64(1 << 9))]))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.noise_exp, F::from_canonical_u64(1 << 8))]))); + lu.push(LutLookup::rc16(Column::single(m.noise_mant_lo))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.noise_mant_hi, F::from_canonical_u64(1 << 9))]))); + // P limbs (P < 2^32). + lu.push(LutLookup::rc16(Column::single(m.pm_lo))); + lu.push(LutLookup::rc16(Column::single(m.pm_hi))); + // M_t limbs: lo < 2^16 and hi in [128, 256) (the (hi - 128)*2^8 check) -> M_t in [2^23, 2^24). + // The [128, 256) check is filtered to live nonzero-noise rows: on zero-noise/padding rows + // M_t = 0 (hi = 0), where `(0 - 128)*2^8` would be out of RANGE16's domain. + lu.push(LutLookup::rc16(Column::single(m.t_mant_lo))); + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant( + [(m.t_mant_hi, F::from_canonical_u64(1 << 8))], + -F::from_canonical_u64(128 << 8), + ), + nz_live_filter(), + )); + lu.push(LutLookup::rc16(Column::single(m.t_half))); + + // ---- G1 bracket slacks (each < 2^34, split lo/mid/hi). ---- + // Lower slack SL = 4*P - T_BLO - T_PARITY = low + 2^16*T_SL_MID + 2^32*T_SL_HI. + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.pm, F::from_canonical_u64(4)), + (m.t_blo, neg), + (m.t_parity, neg), + (m.t_sl_mid, -two16), + (m.t_sl_hi, -two32), + ]))); + lu.push(LutLookup::rc16(Column::single(m.t_sl_mid))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.t_sl_hi, F::from_canonical_u64(1 << 14))]))); + // Upper slack SU = T_BHI - 4*P - T_PARITY = low + 2^16*T_SU_MID + 2^32*T_SU_HI. + lu.push(LutLookup::rc16(Column::linear_combination([ + (m.t_bhi, one), + (m.pm, -F::from_canonical_u64(4)), + (m.t_parity, neg), + (m.t_su_mid, -two16), + (m.t_su_hi, -two32), + ]))); + lu.push(LutLookup::rc16(Column::single(m.t_su_mid))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.t_su_hi, F::from_canonical_u64(1 << 14))]))); + + // ---- G3 field range checks. ---- + lu.push(LutLookup::rc16(Column::single(m.noised_mant_lo))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.noised_mant_hi, F::from_canonical_u64(1 << 9))]))); + lu.push(LutLookup::rc16(Column::linear_combination([(m.noised_exp, F::from_canonical_u64(1 << 8))]))); + lu.push(LutLookup::rc16(Column::single(m.sat_slack))); + lu.push(LutLookup::rc16(Column::single(m.ge113_slack))); + lu.push(LutLookup::rc16(Column::single(m.ge102_slack))); + lu.push(LutLookup::rc16(Column::single(m.q_lo_slack))); + lu.push(LutLookup::rc16(Column::single(m.q_half))); + + // ---- FP16POW2: the cast rounding shift 2^CAST_SHIFT, keyed on CAST_SHIFT, filtered to the + // rounding branches (normal/subnormal); 0 off them (CAST_SHIFT in [13, 24] on those rows). ---- + lu.push(LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![Column::single(m.cast_shift)], + values: vec![Column::single(m.cast_pow)], + filter: Filter::from_column(Column::linear_combination([(m.f_norm, F::ONE), (m.f_sub, F::ONE)])), + }); + + // ---- G3 cast bracket slacks (each < 2^26, split low + 2^16*hi with hi < 2^10). ---- + // Both carry the constant `4*2^23`, so on the all-zero padding rows the raw key would be `+/-2^25` + // (out of RANGE16's domain). They are therefore filtered to live rows (padding rows are + // unconstrained; the standalone soundness is unchanged — every live row is still checked). + // SL = 4*(2^23 + NOISED_MANT) - CAST_BLO - Q_PARITY. + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant( + [ + (m.noised_mant, F::from_canonical_u64(4)), + (m.cast_blo, neg), + (m.q_parity, neg), + (m.cast_sl_hi, -two16), + ], + F::from_canonical_u64(4 * (1 << 23)), + ), + live.clone(), + )); + lu.push(LutLookup::rc16(Column::linear_combination([(m.cast_sl_hi, F::from_canonical_u64(1 << 6))]))); + // SU = CAST_BHI - 4*(2^23 + NOISED_MANT) - Q_PARITY. + lu.push(LutLookup::rc16_filtered( + Column::linear_combination_with_constant( + [ + (m.cast_bhi, one), + (m.noised_mant, -F::from_canonical_u64(4)), + (m.q_parity, neg), + (m.cast_su_hi, -two16), + ], + -F::from_canonical_u64(4 * (1 << 23)), + ), + live.clone(), + )); + lu.push(LutLookup::rc16(Column::linear_combination([(m.cast_su_hi, F::from_canonical_u64(1 << 6))]))); + + lu +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + + type F = GoldilocksField; + + #[test] + fn ctl_halves_are_well_formed() { + ctl_raw_operand_looking::(3); + ctl_noise_word_looking::(3); + ctl_noise_word_looked_noisy_quant::(5); + ctl_fma_hook_looking::(3); + ctl_output_looking::(3); + ctl_operand_bytes_looked_noisy_quant::(5); + ctl_operand_codes_looked_noisy_quant::(5); + } + + #[test] + fn lut_inventory_matches_documented_counts() { + let lu = noisy_quant_lut_lookups::(); + let count = |t: LutTable| lu.iter().filter(|l| l.table == t).count(); + assert_eq!(count(LutTable::Fp16Pow2), 2); // G1 t_shift + G3 cast_shift + assert_eq!(count(LutTable::Range16), lu.len() - 2); + } +} diff --git a/zk-pow/src/circuit/fp16/noisy_quant_stark/mod.rs b/zk-pow/src/circuit/fp16/noisy_quant_stark/mod.rs new file mode 100644 index 000000000..c64c74e23 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_stark/mod.rs @@ -0,0 +1,26 @@ +//! FP16 fused noisy-quantization AIR: proves, in-AIR, two of the three per-element f32 roundings of +//! the plaintext ground truth [`crate::api::fp16::quantization::noisy_quantize`]: +//! +//! * **G1** — the pre-FMA f32 multiply `t = RNE_f32(bf * N_ij)`. +//! * **G3** — the clamp + FP16 cast `out = f32_to_fp16(clamp(noised, -MAX, MAX))` (the clamp is +//! subsumed by `f32_to_fp16`'s own saturation), covering all four branches: saturate, normal, +//! subnormal and zero FP16 outputs. +//! +//! The single-rounding f32 FMA that connects them (`noised = fma(af, X, t)` — a signed add with +//! cancellation) is group **G2**, proved by the sibling AIR +//! [`crate::circuit::fp16::noisy_quant_fma_stark`]; its `ctl_fma_pairing_looking` exposes the same +//! tuple [`ctl::ctl_fma_hook_looking`] does, so the batch binds `t` (G1) and `noised` (G3) to G2's +//! proven FMA — `noised` is a proven value, not a free witness. See [`stark`] for the constraint +//! groups and the documented soundness envelope. +//! +//! Both roundings are proved with ties-to-even quarter-ulp *bracket* gadgets (the binade-bottom +//! `BOTTOM` correction closing every power-of-two rounding) over the shared `RANGE16`/`FP16POW2` +//! committed LUTs — no new table is added. NoisyQuantStark is a CTL party (`requires_ctls`), so the +//! batch driver is the only supported proving path; wiring it into the batch is a later increment. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{NUM_NOISY_QUANT_COLUMNS, NUM_NOISY_QUANT_PUBLIC_INPUTS, NOISY_QUANT_COL_MAP, NoisyQuantColumnsView}; +pub use stark::{NoisyQuantProgram, NoisyQuantStark}; diff --git a/zk-pow/src/circuit/fp16/noisy_quant_stark/stark.rs b/zk-pow/src/circuit/fp16/noisy_quant_stark/stark.rs new file mode 100644 index 000000000..b6b5c6690 --- /dev/null +++ b/zk-pow/src/circuit/fp16/noisy_quant_stark/stark.rs @@ -0,0 +1,1140 @@ +//! Proves two of the three f32 roundings of the plaintext ground truth +//! [`crate::api::fp16::quantization::noisy_quantize`]'s fused per-element noisy quantization. Per +//! element `(i, j)`, that kernel computes (with `af = bf16_to_f32(alpha)`, `bf = +//! bf16_to_f32(beta)`, `X = fp16_to_f32(raw)`, and the per-element noise `N = (E@F^T)_ij`): +//! +//! ```text +//! t = RNE_f32(bf * N) // G1: pre-FMA f32 multiply +//! noised = af.mul_add(X, t) // G2: SINGLE-rounding f32 FMA — DEFERRED +//! out = f32_to_fp16(clamp(noised, -MAX, MAX)) // G3: clamp + FP16 cast +//! ``` +//! +//! # Scope (included vs deferred) +//! +//! * **G1 (included).** `t = RNE_f32(bf * N)`. `bf` is a normal BF16 (significand +//! `M_beta in [128, 255]`); `N` is a normal f32 (significand `M_N in [2^23, 2^24)`) or exactly +//! zero. The exact product significand `P = M_beta * M_N < 2^32` is rounded once to the 24-bit +//! f32 significand `M_t` by the ties-to-even quarter-ulp *bracket* +//! `(4*M_t - 2 + BOTTOM)*2^d1 <= 4*P <= (4*M_t + 2)*2^d1`, the shift `2^d1` an FP16POW2 value and +//! `M_t in [2^23, 2^24)` pinning `d1 = bitlen(P) - 24` uniquely. A zero (or, out of envelope, +//! subnormal) noise word gates the bracket off and forces `t = 0`. +//! +//! * **G3 (included).** `out = f32_to_fp16(noised)`. The clamp is subsumed: `f32_to_fp16` already +//! saturates on overflow, so `f32_to_fp16(clamp(x, +/-MAX)) == f32_to_fp16(x)` for every finite +//! `x` (verified exhaustively over a random f32 sweep). All four cast branches are proved — +//! saturate (`E >= 143`), normal (`113 <= E <= 142`, shift 13), subnormal (`102 <= E <= 112`, +//! shift `126 - E` via FP16POW2) and zero (`E <= 101`) — classified by three monotone flags with +//! two-sided range slacks. The rounding uses the quarter-ulp bracket with the parity tie-break; it +//! is **uniform** (no IS_BOTTOM, because the cast rounds within a fixed exponent), unlike G1's +//! product round. The mantissa-overflow carry (`q = 2^11`) and the FP16-inf boundary (`e_adj > 15`) +//! fold into the output encode. +//! +//! * **G2 (the single-rounding f32 FMA `noised = fma(af, X, t)`)** lives in the sibling AIR +//! [`crate::circuit::fp16::noisy_quant_fma_stark`] (a signed, arbitrarily-aligned add with +//! cancellation and one RNE round, via A100-style windowed alignment). Its +//! `ctl_fma_pairing_looking` exposes the same tuple this module's [`super::ctl::ctl_fma_hook_looking`] +//! does, so the batch binds `t` (G1 here) and `noised` (G3 here) to G2's proven FMA. `noised` is +//! therefore a proven value, not a free witness. +//! +//! # Soundness envelope (documented, not an unproved shortcut) +//! +//! `beta` normal positive; `N` normal f32 or exactly zero; `noised` a normal f32 (`E in [1, 254]`). +//! A subnormal-f32 *operand* (`|.| < 2^-126`) is out of envelope — the generator asserts against it +//! (it never arises in-scheme: alpha scales a row toward the FP16 ceiling) — but a tiny FP16 *output* +//! is fully handled (G3's subnormal/zero branches), so a tiny element does not crash the prover. G1's +//! product round carries the full ties-to-even machinery with the binade-bottom (`BOTTOM`) `+1` +//! correction; G3's cast is uniform with the parity tie-break. Both pin the rounded significand to +//! the **unique** RNE result with no residual grinding freedom. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{NUM_NOISY_QUANT_COLUMNS, NUM_NOISY_QUANT_PUBLIC_INPUTS, NoisyQuantColumnsView}; +use crate::api::fp16::dtype::f32_to_fp16; +use crate::api::fp8::dtype::bf16_to_f32; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// Field inverse of a small integer, or zero when it is zero (the is-zero gadget's witness). +fn inv_f(x: u64) -> F { + if x == 0 { F::ZERO } else { F::from_canonical_u64(x).inverse() } +} + +/// Inverse of the field difference `a - b` (zero when `a == b`); handles `a < b` without u64 +/// underflow (the is-zero gadget's witness for a difference key). +fn inv_diff(a: u64, b: u64) -> F { + let d = F::from_canonical_u64(a) - F::from_canonical_u64(b); + if d == F::ZERO { F::ZERO } else { d.inverse() } +} + +/// Signed i128 to field (the lower bracket boundary is negative when `q` is small/zero). +fn fe_i128(x: i128) -> F { + if x >= 0 { F::from_canonical_u64(x as u64) } else { -F::from_canonical_u64((-x) as u64) } +} + +/// `x >> shift` rounded to nearest, ties to even (the f32 significand rounding; mirrors the +/// `round_shift` of [`crate::api::fp16::dtype`]). +fn round_shift(x: u64, shift: u32) -> u64 { + if shift == 0 { + return x; + } + let dropped = x & ((1u64 << shift) - 1); + let kept = x >> shift; + let half = 1u64 << (shift - 1); + if dropped > half || (dropped == half && (kept & 1) == 1) { kept + 1 } else { kept } +} + +fn bit_length(x: u64) -> u32 { + 64 - x.leading_zeros() +} + +/// One decoded + proved element of the fused noisy quantization. The committed geometry is just the +/// element count; the identity is otherwise program-independent. +#[derive(Clone, Debug)] +pub struct NoisyQuantProgram { + /// Number of live operand elements (`(h + w) * k` in the batch). + pub num_elems: usize, + /// Block size (elements per operand row); `OPERAND_ROW_INDEX = floor(element / k)`. + pub k: usize, + /// Trace height (a power of two `>= num_elems`). + pub num_rows: usize, + /// Number of A-side operand rows (`h` in the batch). Operand rows `0..num_a_rows` are the A + /// operand (reused `mult_a` times each by the matmul), the rest are the B operand (reused + /// `mult_b` times). Standalone programs use `num_elems/k` (all A) with unit multiplicity. + pub num_a_rows: usize, + /// Matmul reuse multiplicity of an A-side element (`w` in the batch): `OPERAND_MULT` on A rows. + pub mult_a: usize, + /// Matmul reuse multiplicity of a B-side element (`h` in the batch): `OPERAND_MULT` on B rows. + pub mult_b: usize, +} + +impl NoisyQuantProgram { + /// Single-block standalone program (`k = num_elems`), padded to the next power of two. Unit + /// reuse multiplicity (no matmul counterpart in the standalone tests). + pub fn new(num_elems: usize) -> Self { + Self::with_rows(num_elems, num_elems, num_elems.next_power_of_two().max(2), 1, 1, 1) + } + + /// Multi-operand-row program: `num_elems` elements grouped into `k`-element blocks, at an + /// explicit `num_rows` height. `num_a_rows` splits the operand rows into the A operand + /// (`0..num_a_rows`, element reuse `mult_a`) and the B operand (reuse `mult_b`) — the + /// operand-codes (6d) looked-side multiplicity. + pub fn with_rows(num_elems: usize, k: usize, num_rows: usize, num_a_rows: usize, mult_a: usize, mult_b: usize) -> Self { + assert!(num_elems >= 1, "at least one element"); + assert!(k >= 1 && num_elems % k == 0, "num_elems must be a whole number of k-element rows"); + assert!(num_rows.is_power_of_two() && num_rows >= num_elems, "height covers the live elements"); + assert!(num_a_rows <= num_elems / k, "A rows cannot exceed the operand-row count"); + Self { num_elems, k, num_rows, num_a_rows, mult_a, mult_b } + } + + pub fn live_rows(&self) -> usize { + self.num_elems + } + + /// Trace height. + pub fn num_rows(&self) -> usize { + self.num_rows + } + + /// `OPERAND_ROW_INDEX` for a trace row (`floor(element / k)`; the final live index on padding). + fn operand_row_index(&self, i: usize) -> usize { + if i >= self.num_elems { self.num_elems / self.k - 1 } else { i / self.k } + } + + /// `ELEMENT_INDEX` for a trace row (the row's global element index `e`; the final live index on + /// padding, filtered out of every CTL). + fn element_index(&self, i: usize) -> usize { + if i >= self.num_elems { self.num_elems - 1 } else { i } + } + + /// `OPERAND_MULT` for a trace row: `mult_a` for an A-side element (operand row `< num_a_rows`), + /// else `mult_b` — the matmul reuse multiplicity the operand-codes (6d) looked side carries. + fn operand_mult(&self, i: usize) -> usize { + if self.operand_row_index(i) < self.num_a_rows { self.mult_a } else { self.mult_b } + } + + /// The class (a) ("known") columns `IS_PAD`, `OPERAND_ROW_INDEX`, `ELEMENT_INDEX` and + /// `OPERAND_MULT`, pure functions of geometry. + pub fn known_values(&self) -> Vec> { + let num_rows = self.num_rows(); + let is_pad = (0..num_rows).map(|i| F::from_bool(i >= self.num_elems)).collect(); + let ori = (0..num_rows).map(|i| F::from_canonical_usize(self.operand_row_index(i))).collect(); + let eidx = (0..num_rows).map(|i| F::from_canonical_usize(self.element_index(i))).collect(); + let mult = (0..num_rows).map(|i| F::from_canonical_usize(self.operand_mult(i))).collect(); + vec![ + PolynomialValues::new(is_pad), + PolynomialValues::new(ori), + PolynomialValues::new(eidx), + PolynomialValues::new(mult), + ] + } + + /// Generates the trace. Each of `alpha`/`raw`/`beta` (BF16/FP16 codes), `noise`/`noised` + /// (f32 values) has one entry per live element. `out` (G3) and `t` (G1) are computed internally, + /// bit-exact with the reference kernel. Panics on an out-of-envelope element. + pub fn generate_trace( + &self, + alpha: &[u16], + raw: &[u16], + beta: &[u16], + noise: &[f32], + noised: &[f32], + ) -> Vec<[F; NUM_NOISY_QUANT_COLUMNS]> { + let n = self.num_elems; + assert!(alpha.len() == n && raw.len() == n && beta.len() == n && noise.len() == n && noised.len() == n); + let num_rows = self.num_rows(); + let mut rows = Vec::with_capacity(num_rows); + + for e in 0..n { + let mut v = NoisyQuantColumnsView::::default(); + v.operand_row_index = F::from_canonical_usize(self.operand_row_index(e)); + v.element_index = F::from_canonical_usize(self.element_index(e)); + v.operand_mult = F::from_canonical_usize(self.operand_mult(e)); + v.alpha = F::from_canonical_u16(alpha[e]); + v.raw = F::from_canonical_u16(raw[e]); + + // ---- G1: t = RNE_f32(bf * N). ---- + let beta_code = beta[e]; + let beta_exp = u64::from(beta_code >> 7); + let beta_mant = u64::from(beta_code & 0x7F); + assert!((1..=254).contains(&beta_exp), "envelope: beta must be a normal BF16"); + let m_beta = 128 + beta_mant; + v.beta = F::from_canonical_u16(beta_code); + v.beta_exp = F::from_canonical_u64(beta_exp); + v.beta_mant = F::from_canonical_u64(beta_mant); + + let nbits = noise[e].to_bits(); + let noise_sign = u64::from(nbits >> 31); + let noise_exp = u64::from((nbits >> 23) & 0xFF); + let noise_mant = u64::from(nbits & 0x7F_FFFF); + assert!(noise_exp != 255, "noise must be finite"); + let noise_is_zero = noise_exp == 0; + if noise_is_zero { + assert_eq!(noise_mant, 0, "envelope: a zero-exponent noise word must be exactly zero"); + } + v.noise_lo = F::from_canonical_u64(u64::from(nbits & 0xFFFF)); + v.noise_hi = F::from_canonical_u64(u64::from(nbits >> 16)); + v.noise_sign = F::from_canonical_u64(noise_sign); + v.noise_exp = F::from_canonical_u64(noise_exp); + v.noise_mant = F::from_canonical_u64(noise_mant); + v.noise_mant_lo = F::from_canonical_u64(noise_mant & 0xFFFF); + v.noise_mant_hi = F::from_canonical_u64(noise_mant >> 16); + v.noise_is_zero = F::from_bool(noise_is_zero); + v.noise_exp_inv = inv_f::(noise_exp); + + let mn = if noise_is_zero { 0 } else { (1u64 << 23) + noise_mant }; + let pm = m_beta * mn; + v.mn = F::from_canonical_u64(mn); + v.pm = F::from_canonical_u64(pm); + v.pm_lo = F::from_canonical_u64(pm & 0xFFFF); + v.pm_hi = F::from_canonical_u64(pm >> 16); + + if noise_is_zero { + v.t_pow = F::ONE; // 2^0, an in-domain FP16POW2 key on the gated-off row. + } else { + // d1 = bitlen(P) - 24, with the mantissa-overflow renormalization folded in. + let mut d1 = bit_length(pm) - 24; + let mut m_t = round_shift(pm, d1); + if m_t == (1u64 << 24) { + m_t = 1u64 << 23; + d1 += 1; + } + assert!((1 << 23..1 << 24).contains(&m_t), "M_t normalized"); + // Cross-check against the reference f32 multiply. + let t_f32 = bf16_to_f32(beta_code) * noise[e]; + let tbits = t_f32.to_bits(); + debug_assert_eq!((1u64 << 23) + u64::from(tbits & 0x7F_FFFF), m_t, "M_t vs f32 mul"); + let t_exp = u64::from((tbits >> 23) & 0xFF); + debug_assert_eq!(t_exp, beta_exp + noise_exp + u64::from(d1) - 134, "t exp relation"); + + let pow = 1u64 << d1; + let bottom = u64::from(m_t == (1 << 23)); + let parity = m_t & 1; + // The parity split rides the low limb (M_t = t_mant_lo + 2^16*hi; 2^16*hi is even, so + // M_t and t_mant_lo share parity) so T_HALF stays a single RANGE16 limb (< 2^15). + let half = ((m_t & 0xFFFF) - parity) / 2; + let blo = (4 * m_t - 2 + bottom) * pow; + let bhi = (4 * m_t + 2) * pow; + let sl = 4 * pm - blo - parity; + let su = bhi - 4 * pm - parity; + v.t_shift = F::from_canonical_u64(u64::from(d1)); + v.t_pow = F::from_canonical_u64(pow); + v.t_mant = F::from_canonical_u64(m_t); + v.t_mant_lo = F::from_canonical_u64(m_t & 0xFFFF); + v.t_mant_hi = F::from_canonical_u64(m_t >> 16); + v.t_bottom = F::from_canonical_u64(bottom); + v.t_bottom_inv = inv_f::(m_t - (1 << 23)); + v.t_parity = F::from_canonical_u64(parity); + v.t_half = F::from_canonical_u64(half); + v.t_blo = F::from_canonical_u64(blo); + v.t_bhi = F::from_canonical_u64(bhi); + v.t_sl_mid = F::from_canonical_u64((sl >> 16) & 0xFFFF); + v.t_sl_hi = F::from_canonical_u64(sl >> 32); + v.t_su_mid = F::from_canonical_u64((su >> 16) & 0xFFFF); + v.t_su_hi = F::from_canonical_u64(su >> 32); + v.t_exp = F::from_canonical_u64(t_exp); + } + v.nz_live = F::from_bool(!noise_is_zero); + + // ---- G3: out = f32_to_fp16(noised) (normal / subnormal / zero / saturating). ---- + let xbits = noised[e].to_bits(); + let noised_sign = u64::from(xbits >> 31); + let noised_exp = u64::from((xbits >> 23) & 0xFF); + let noised_mant = u64::from(xbits & 0x7F_FFFF); + assert!((1..=254).contains(&noised_exp), "noised must be a normal f32 (exp {noised_exp})"); + v.noised_lo = F::from_canonical_u64(u64::from(xbits & 0xFFFF)); + v.noised_hi = F::from_canonical_u64(u64::from(xbits >> 16)); + v.noised_sign = F::from_canonical_u64(noised_sign); + v.noised_exp = F::from_canonical_u64(noised_exp); + v.noised_mant = F::from_canonical_u64(noised_mant); + v.noised_mant_lo = F::from_canonical_u64(noised_mant & 0xFFFF); + v.noised_mant_hi = F::from_canonical_u64(noised_mant >> 16); + + // Branch classification. + let f_sat = noised_exp >= 143; + let ge113 = noised_exp >= 113; + let ge102 = noised_exp >= 102; + let f_norm = ge113 && !f_sat; + let f_sub = ge102 && !ge113; + let f_zero = !ge102; + v.f_sat = F::from_bool(f_sat); + v.sat_slack = F::from_canonical_u64(if f_sat { noised_exp - 143 } else { 142 - noised_exp }); + v.ge113 = F::from_bool(ge113); + v.ge113_slack = F::from_canonical_u64(if ge113 { noised_exp - 113 } else { 112 - noised_exp }); + v.ge102 = F::from_bool(ge102); + v.ge102_slack = F::from_canonical_u64(if ge102 { noised_exp - 102 } else { 101 - noised_exp }); + v.f_norm = F::from_bool(f_norm); + v.f_sub = F::from_bool(f_sub); + v.f_zero = F::from_bool(f_zero); + + let full = (1u64 << 23) + noised_mant; + let round_active = f_norm || f_sub; + let cast_shift: u64 = if f_norm { 13 } else if f_sub { 126 - noised_exp } else { 0 }; + let cast_pow: u64 = 1 << cast_shift; + let q = if round_active { round_shift(full, cast_shift as u32) } else { 0 }; + let q_bottom = u64::from(q == (1 << 10)); + let parity = q & 1; + v.cast_shift = F::from_canonical_u64(cast_shift); + v.cast_pow = F::from_canonical_u64(cast_pow); + v.q = F::from_canonical_u64(q); + v.q_lo_slack = F::from_canonical_u64(if f_norm { q - (1 << 10) } else { 0 }); + v.q_bottom = F::from_canonical_u64(q_bottom); + v.q_bottom_inv = inv_diff::(q, 1 << 10); + v.q_parity = F::from_canonical_u64(parity); + v.q_half = F::from_canonical_u64((q - parity) / 2); + if round_active { + // The cast rounds within a FIXED exponent (uniform grid) — this is `round_shift`, + // so there is NO binade-bottom asymmetry (unlike G1's product round). The bracket is + // the plain quarter-ulp bracket (4q-2 .. 4q+2) with the parity tie-break. + let blo_i: i128 = (4 * q as i128 - 2) * cast_pow as i128; + let bhi: u64 = (4 * q + 2) * cast_pow; + let sl: i128 = 4 * full as i128 - blo_i - parity as i128; + let su: i128 = bhi as i128 - 4 * full as i128 - parity as i128; + debug_assert!(sl >= 0 && su >= 0 && (sl >> 16) < (1 << 16) && (su >> 16) < (1 << 16)); + v.cast_blo = fe_i128::(blo_i); + v.cast_bhi = F::from_canonical_u64(bhi); + v.cast_sl_hi = F::from_canonical_u64((sl >> 16) as u64); + v.cast_su_hi = F::from_canonical_u64((su >> 16) as u64); + } + let carry = u64::from(q == (1 << 11)); + v.carry = F::from_canonical_u64(carry); + v.carry_inv = inv_diff::(1 << 11, q); + let e142 = u64::from(noised_exp == 142); + v.e142 = F::from_canonical_u64(e142); + v.e142_inv = inv_diff::(142, noised_exp); + let cce = carry * e142; + v.cce = F::from_canonical_u64(cce); + let is_sat_eff = u64::from(f_sat) + u64::from(f_norm) * cce; + v.is_sat_eff = F::from_canonical_u64(is_sat_eff); + let fnns = u64::from(f_norm) * (1 - cce); + v.fnns = F::from_canonical_u64(fnns); + let mf = if f_norm { (1 - carry) * (q - (1 << 10)) } else { 0 }; + v.mf = F::from_canonical_u64(mf); + + let out = f32_to_fp16(noised[e]).expect("finite noised casts to FP16"); + v.out = F::from_canonical_u16(out); + // Cross-check the encode the constraints rebuild (normal_mag only meaningful when f_norm). + let normal_mag = if f_norm { (noised_exp - 112 + carry) * (1 << 10) + mf } else { 0 }; + let expect = (noised_sign << 15) + is_sat_eff * 0x7BFF + fnns * normal_mag + u64::from(f_sub) * q; + debug_assert_eq!(u64::from(out), expect, "G3 encode mismatch (exp {noised_exp})"); + + rows.push(v.into()); + } + + for i in n..num_rows { + rows.push( + NoisyQuantColumnsView:: { + is_pad: F::ONE, + operand_row_index: F::from_canonical_usize(self.operand_row_index(i)), + element_index: F::from_canonical_usize(self.element_index(i)), + operand_mult: F::from_canonical_usize(self.operand_mult(i)), + ..Default::default() + } + .into(), + ); + } + rows + } +} + +/// `flag = [x == 0]`, gated: `flag` boolean, `flag*x = 0`, `x*inv = 1 - flag`. +fn is_zero_flag(eval: &mut E, x: V, inv: V, flag: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + eval.constraint_bool(flag); + let fx = eval.mul(flag, x); + let c = eval.mul(gate, fx); + eval.constraint(c); + let xi = eval.mul(x, inv); + let omf = eval.sub(one, flag); + let d = eval.sub(xi, omf); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `mant = 2*half + parity` with `parity` boolean (`half` is RANGE16'd in `ctl.rs`). +fn parity_split(eval: &mut E, mant: V, half: V, parity: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + eval.constraint_bool(parity); + let two = eval.u64(2); + let two_half = eval.mul(two, half); + let recomposed = eval.add(two_half, parity); + let d = eval.sub(mant, recomposed); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// Evaluates every arithmetic constraint (degree <= 3). All range facts (RANGE16 limbs/slacks, the +/// FP16POW2 shift) live in [`super::ctl`]. +pub(crate) fn eval_noisy_quant_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_NOISY_QUANT_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &NoisyQuantColumnsView = lv.borrow(); + + let one = eval.u64(1); + let live = eval.sub(one, lv.is_pad); + eval.constraint_bool(lv.is_pad); + + let c128 = eval.u64(128); + let c4 = eval.u64(4); + let two = eval.u64(2); + + // ================= GROUP G1 — t = RNE_f32(bf * N). ================= + // Decode beta: code = beta_exp*128 + beta_mant (beta is a normal positive BF16). + let beta_rec = eval.mad(lv.beta_exp, c128, lv.beta_mant); + let d = eval.sub(lv.beta, beta_rec); + let c = eval.mul(live, d); + eval.constraint(c); + + // Decode N: bits = sign*2^31 + exp*2^23 + mant; mant = lo + 2^16*hi; bits = lo16 + 2^16*hi16. + let c2_16 = eval.u64(1 << 16); + let c2_23 = eval.u64(1 << 23); + let c2_31 = eval.u64(1 << 31); + let noise_mant_rec = eval.mad(lv.noise_mant_hi, c2_16, lv.noise_mant_lo); + let d = eval.sub(lv.noise_mant, noise_mant_rec); + let c = eval.mul(live, d); + eval.constraint(c); + let nbits_fields = { + let s = eval.mul(lv.noise_sign, c2_31); + let e = eval.mul(lv.noise_exp, c2_23); + let se = eval.add(s, e); + eval.add(se, lv.noise_mant) + }; + let nbits_limbs = eval.mad(lv.noise_hi, c2_16, lv.noise_lo); + let d = eval.sub(nbits_fields, nbits_limbs); + let c = eval.mul(live, d); + eval.constraint(c); + eval.constraint_bool(lv.noise_sign); + + // noise_is_zero = [noise_exp == 0]. + is_zero_flag(eval, lv.noise_exp, lv.noise_exp_inv, lv.noise_is_zero, live); + + // mn = (1 - noise_is_zero)*2^23 + noise_mant. + let nz = eval.sub(one, lv.noise_is_zero); + let hi = eval.mul(nz, c2_23); + let mn_expect = eval.add(hi, lv.noise_mant); + let d = eval.sub(lv.mn, mn_expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // P = M_beta * M_N = (128 + beta_mant) * mn; P = pm_lo + 2^16*pm_hi. + let m_beta = eval.add(c128, lv.beta_mant); + let pm_expect = eval.mul(m_beta, lv.mn); + let d = eval.sub(lv.pm, pm_expect); + let c = eval.mul(live, d); + eval.constraint(c); + let pm_rec = eval.mad(lv.pm_hi, c2_16, lv.pm_lo); + let d = eval.sub(lv.pm, pm_rec); + let c = eval.mul(live, d); + eval.constraint(c); + + // t fields (reconstruct M_t from limbs; M_t_hi carries the [128,256) pin from ctl.rs). + let t_mant_rec = eval.mad(lv.t_mant_hi, c2_16, lv.t_mant_lo); + let d = eval.sub(lv.t_mant, t_mant_rec); + let c = eval.mul(live, d); + eval.constraint(c); + + // Nonzero-noise rows re-prove the full bracket; zero-noise rows force t = 0. NZ_LIVE is a + // committed boolean = live*(1 - noise_is_zero), used as a degree-1 gate so the degree-2 boundary + // constraints stay degree <= 3; it is 0 on padding rows (live = 0 there). + eval.constraint_bool(lv.nz_live); + let nz_live_expect = eval.mul(live, nz); + let d = eval.sub(lv.nz_live, nz_live_expect); + eval.constraint(d); + let live_nz = lv.nz_live; + // Bracket boundaries blo = (4*M_t - 2 + BOTTOM)*2^d1, bhi = (4*M_t + 2)*2^d1. + let four_mt = eval.mul(c4, lv.t_mant); + let lo_coef = { + let m2 = eval.sub(four_mt, two); + eval.add(m2, lv.t_bottom) + }; + let hi_coef = eval.add(four_mt, two); + let blo_expect = eval.mul(lo_coef, lv.t_pow); + let d = eval.sub(lv.t_blo, blo_expect); + let c = eval.mul(live_nz, d); + eval.constraint(c); + let bhi_expect = eval.mul(hi_coef, lv.t_pow); + let d = eval.sub(lv.t_bhi, bhi_expect); + let c = eval.mul(live_nz, d); + eval.constraint(c); + // Parity split on the low limb (shares M_t's parity; keeps T_HALF a single RANGE16 limb). + parity_split(eval, lv.t_mant_lo, lv.t_half, lv.t_parity, live_nz); + // t_bottom = [M_t - 2^23 == 0]. + let mt_rel = eval.sub(lv.t_mant, c2_23); + is_zero_flag(eval, mt_rel, lv.t_bottom_inv, lv.t_bottom, live_nz); + // t_exp = beta_exp + noise_exp + t_shift - 134 (nonzero rows). + let c134 = eval.u64(134); + let s = eval.add(lv.beta_exp, lv.noise_exp); + let s = eval.add(s, lv.t_shift); + let texp_expect = eval.sub(s, c134); + let d = eval.sub(lv.t_exp, texp_expect); + let c = eval.mul(live_nz, d); + eval.constraint(c); + // Zero-noise rows: t_mant = t_exp = t_shift = 0, t_pow = 1. + let live_z = eval.mul(live, lv.noise_is_zero); + let c = eval.mul(live_z, lv.t_mant); + eval.constraint(c); + let c = eval.mul(live_z, lv.t_exp); + eval.constraint(c); + let c = eval.mul(live_z, lv.t_shift); + eval.constraint(c); + let pow_m1 = eval.sub(lv.t_pow, one); + let c = eval.mul(live_z, pow_m1); + eval.constraint(c); + + // ================= GROUP G3 — out = f32_to_fp16(noised) (all four branches). ================= + eval.constraint_bool(lv.noised_sign); + let noised_mant_rec = eval.mad(lv.noised_mant_hi, c2_16, lv.noised_mant_lo); + let d = eval.sub(lv.noised_mant, noised_mant_rec); + gated_g3(eval, live, d); + let xbits_fields = { + let s = eval.mul(lv.noised_sign, c2_31); + let e = eval.mul(lv.noised_exp, c2_23); + let se = eval.add(s, e); + eval.add(se, lv.noised_mant) + }; + let xbits_limbs = eval.mad(lv.noised_hi, c2_16, lv.noised_lo); + let d = eval.sub(xbits_fields, xbits_limbs); + gated_g3(eval, live, d); + + let c142 = eval.u64(142); + let c142_m_e = eval.sub(c142, lv.noised_exp); + // Monotone branch flags via two-sided slacks: flag*(E - lo) + (1-flag)*(hi - E) >= 0. + eval.constraint_bool(lv.f_sat); + eval.constraint_bool(lv.ge113); + eval.constraint_bool(lv.ge102); + for (flag, lo, hi, slack) in [ + (lv.f_sat, 143u64, 142u64, lv.sat_slack), + (lv.ge113, 113, 112, lv.ge113_slack), + (lv.ge102, 102, 101, lv.ge102_slack), + ] { + let clo = eval.u64(lo); + let chi = eval.u64(hi); + let e_m_lo = eval.sub(lv.noised_exp, clo); + let hi_m_e = eval.sub(chi, lv.noised_exp); + let a = eval.mul(flag, e_m_lo); + let not_f = eval.sub(one, flag); + let b = eval.mul(not_f, hi_m_e); + let expect = eval.add(a, b); + let d = eval.sub(slack, expect); + gated_g3(eval, live, d); + } + // f_norm = ge113*(1 - f_sat); f_sub = ge102*(1 - ge113); f_zero = 1 - ge102. + eval.constraint_bool(lv.f_norm); + eval.constraint_bool(lv.f_sub); + eval.constraint_bool(lv.f_zero); + let not_sat = eval.sub(one, lv.f_sat); + let fn_expect = eval.mul(lv.ge113, not_sat); + let d = eval.sub(lv.f_norm, fn_expect); + gated_g3(eval, live, d); + let not_113 = eval.sub(one, lv.ge113); + let fs_expect = eval.mul(lv.ge102, not_113); + let d = eval.sub(lv.f_sub, fs_expect); + gated_g3(eval, live, d); + let fz_expect = eval.sub(one, lv.ge102); + let d = eval.sub(lv.f_zero, fz_expect); + gated_g3(eval, live, d); + let round_active = eval.add(lv.f_norm, lv.f_sub); + + // cast_shift = 13*f_norm + (126 - E)*f_sub; cast_pow = 2^cast_shift (FP16POW2, ctl). + let c13 = eval.u64(13); + let c126 = eval.u64(126); + let shift_norm = eval.mul(c13, lv.f_norm); + let c126_m_e = eval.sub(c126, lv.noised_exp); + let shift_sub = eval.mul(c126_m_e, lv.f_sub); + let shift_expect = eval.add(shift_norm, shift_sub); + let d = eval.sub(lv.cast_shift, shift_expect); + gated_g3(eval, live, d); + + // Cast bracket (rounding branches): cast_blo = (4q - 2 + bottom)*cast_pow, cast_bhi = (4q+2)*pow. + let c2_10 = eval.u64(1 << 10); + let four_q = eval.mul(c4, lv.q); + // Uniform quarter-ulp bracket (no IS_BOTTOM: the cast rounds within a fixed exponent). + let lo_coef = eval.sub(four_q, two); + let hi_coef = eval.add(four_q, two); + let blo_expect = eval.mul(lo_coef, lv.cast_pow); + let d = eval.sub(lv.cast_blo, blo_expect); + let c = eval.mul(round_active, d); // degree 3, 0 off the rounding branches + eval.constraint(c); + let bhi_expect = eval.mul(hi_coef, lv.cast_pow); + let d = eval.sub(lv.cast_bhi, bhi_expect); + let c = eval.mul(round_active, d); + eval.constraint(c); + // Off the rounding branches: cast_blo = cast_bhi = q = 0 (so the ctl slacks vanish). + let not_round = eval.sub(one, round_active); + let c = eval.mul(not_round, lv.q); + gated_g3(eval, live, c); + let c = eval.mul(not_round, lv.cast_blo); + gated_g3(eval, live, c); + let c = eval.mul(not_round, lv.cast_bhi); + gated_g3(eval, live, c); + parity_split(eval, lv.q, lv.q_half, lv.q_parity, live); + // q_lo_slack = q - 2^10 on the normal branch (pins q >= 2^10 there). + let q_rel = eval.sub(lv.q, c2_10); + let d = eval.sub(lv.q_lo_slack, q_rel); + let c = eval.mul(lv.f_norm, d); + gated_g3(eval, live, c); + // q_bottom = [q - 2^10 == 0]; carry = [2^11 - q == 0]; e142 = [142 - E == 0]. + is_zero_flag(eval, q_rel, lv.q_bottom_inv, lv.q_bottom, live); + let c2_11 = eval.u64(1 << 11); + let q_hi_rel = eval.sub(c2_11, lv.q); + is_zero_flag(eval, q_hi_rel, lv.carry_inv, lv.carry, live); + is_zero_flag(eval, c142_m_e, lv.e142_inv, lv.e142, live); + // cce = carry*e142; is_sat_eff = f_sat + f_norm*cce; fnns = f_norm*(1 - cce). + eval.constraint_bool(lv.cce); + eval.constraint_bool(lv.is_sat_eff); + eval.constraint_bool(lv.fnns); + let cce_expect = eval.mul(lv.carry, lv.e142); + let d = eval.sub(lv.cce, cce_expect); + gated_g3(eval, live, d); + let fncce = eval.mul(lv.f_norm, lv.cce); + let ise_expect = eval.add(lv.f_sat, fncce); + let d = eval.sub(lv.is_sat_eff, ise_expect); + gated_g3(eval, live, d); + let fnns_expect = eval.sub(lv.f_norm, fncce); + let d = eval.sub(lv.fnns, fnns_expect); + gated_g3(eval, live, d); + // MF = (1 - carry)*(q - 2^10) on the normal branch (degree-budget helper). + let not_carry = eval.sub(one, lv.carry); + let mf_expect = eval.mul(not_carry, q_rel); + let d = eval.sub(lv.mf, mf_expect); + let c = eval.mul(lv.f_norm, d); + eval.constraint(c); + + // Output encode: + // out = sign*2^15 + IS_SAT_EFF*0x7BFF + FNNS*((E-112+carry)*2^10 + MF) + F_SUB*q. + let c2_15 = eval.u64(1 << 15); + let sign_hi = eval.mul(lv.noised_sign, c2_15); + let c7bff = eval.u64(0x7BFF); + let c112 = eval.u64(112); + let expfield = { + let em = eval.sub(lv.noised_exp, c112); + eval.add(em, lv.carry) + }; + let exp_term = eval.mul(expfield, c2_10); + let normal_mag = eval.add(exp_term, lv.mf); + let sat_term = eval.mul(lv.is_sat_eff, c7bff); + let norm_term = eval.mul(lv.fnns, normal_mag); + let sub_term = eval.mul(lv.f_sub, lv.q); + let out_expect = eval.add(sign_hi, sat_term); + let out_expect = eval.add(out_expect, norm_term); + let out_expect = eval.add(out_expect, sub_term); + let d = eval.sub(lv.out, out_expect); + gated_g3(eval, live, d); +} + +/// Emit `live * expr = 0` (degree = 1 + deg(expr)); use only when `expr` is degree <= 2. +fn gated_g3(eval: &mut E, live: V, expr: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let c = eval.mul(live, expr); + eval.constraint(c); +} + +/// FP16 NoisyQuantStark. A CTL party (`requires_ctls`): the FP16POW2 shift and the RANGE16 range +/// facts are served by the committed LUTs, and the operand / noise / FMA / output hooks are +/// CTL-bound in later stages, so the batch driver is the only supported proving path. +#[derive(Clone, Debug)] +pub struct NoisyQuantStark, const D: usize> { + pub program: NoisyQuantProgram, + _phantom: PhantomData, +} + +impl, const D: usize> NoisyQuantStark { + pub fn new(program: NoisyQuantProgram) -> Self { + Self { program, _phantom: PhantomData } + } +} + +impl, const D: usize> Stark for NoisyQuantStark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_NOISY_QUANT_COLUMNS, NUM_NOISY_QUANT_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_noisy_quant_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_noisy_quant_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + use starky::util::trace_rows_to_poly_values; + + use super::super::columns::NOISY_QUANT_COL_MAP; + use super::super::ctl::noisy_quant_lut_lookups; + use super::*; + use crate::api::fp16::dtype::fp16_to_f32; + use crate::api::fp16::quantization::{MAX_FP16, noisy_quantize, row_norms}; + use crate::api::fp8::dtype::f32_to_bf16; + use crate::circuit::fp8::luts::LutTable; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type Stk = NoisyQuantStark; + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + fn constraints_violated(stark: &Stk, rows: &[[F; NUM_NOISY_QUANT_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().iter().any(|&acc| acc != F::ZERO) + }) + } + + /// A deterministic in-envelope sample: a normal `noised` in the FP16-normal range, a normal + /// `beta`, and a normal `noise` word. Returns `(alpha, raw, beta, noise, noised)`. + fn sample(seed: u64) -> (u16, u16, u16, f32, f32) { + let mut s = seed.wrapping_add(0x9E3779B97F4A7C15); + let mut next = || { + s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + s + }; + let raw = ((next() >> 40) as u16) & 0x3FF | 0x3C00; // a normal FP16 near 1..2 + let alpha = f32_to_bf16(1.0 + (next() % 7) as f32 * 0.5).unwrap(); + let beta = f32_to_bf16(0.25 + (next() % 5) as f32 * 0.1).unwrap(); + // Always a nonzero normal noise word (keeps the sample-based tests on the G1 bracket path). + let noise = (((next() % 1000) + 1) as f32) * if next() & 1 == 0 { 0.5 } else { -0.5 }; + // A normal mid-range noised value (FP16-normal: |x| in [2^-6, 2^10] here). + let mag = 2f32.powi(((next() % 16) as i32) - 6) * (1.0 + (next() % 1000) as f32 / 1000.0); + let sign = if next() & 1 == 0 { 1.0 } else { -1.0 }; + let noised = sign * mag; + (alpha, raw, beta, noise, noised) + } + + fn trace_from( + items: &[(u16, u16, u16, f32, f32)], + ) -> (NoisyQuantProgram, Vec<[F; NUM_NOISY_QUANT_COLUMNS]>) { + let n = items.len(); + let program = NoisyQuantProgram::new(n); + let alpha: Vec = items.iter().map(|x| x.0).collect(); + let raw: Vec = items.iter().map(|x| x.1).collect(); + let beta: Vec = items.iter().map(|x| x.2).collect(); + let noise: Vec = items.iter().map(|x| x.3).collect(); + let noised: Vec = items.iter().map(|x| x.4).collect(); + let rows = program.generate_trace::(&alpha, &raw, &beta, &noise, &noised); + (program, rows) + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + let items: Vec<_> = (0..40).map(sample).collect(); + let (program, rows) = trace_from(&items); + assert_eq!(rows.len(), 64); + let known = program.known_values::(); + for (r, row) in rows.iter().enumerate() { + assert_eq!(known[0].values[r], row[NOISY_QUANT_COL_MAP.is_pad], "is_pad row {r}"); + } + assert!(!constraints_violated(&Stk::new(program), &rows), "honest trace violated a constraint"); + } + + /// Several hand-picked `noised` values exercise the G3 branches: a power-of-two rounding, a + /// ties-to-even case, a clamp/saturation case, and ordinary normal casts — each compared against + /// `f32_to_fp16(clamp(.))` (the plaintext reference, whose clamp `f32_to_fp16` subsumes). + #[test] + fn g3_cast_is_bit_exact_incl_clamp_and_power_of_two() { + let noised_vals: Vec = vec![ + 1.0, // power of two -> q at binade bottom (0x3C00) + 2.0, + -4.0, + 1024.0, + 65504.0, // exactly MAX + 70000.0, // clamp/saturate -> 0x7BFF + -80000.0, // clamp/saturate -> 0xFBFF + 12345.0, + f32::from_bits(0x477FE001), // just above a tie near the top normal binade + 0.013_f32, + 333.0, + ]; + let items: Vec<_> = noised_vals + .iter() + .map(|&x| (f32_to_bf16(1.0).unwrap(), 0x3C00u16, f32_to_bf16(0.5).unwrap(), 2.0f32, x)) + .collect(); + let (_program, rows) = trace_from(&items); + for (e, &x) in noised_vals.iter().enumerate() { + let got = to_u64(rows[e][NOISY_QUANT_COL_MAP.out]) as u16; + let want = f32_to_fp16(x.clamp(-MAX_FP16, MAX_FP16)).unwrap(); + assert_eq!(got, want, "G3 cast mismatch for noised={x}"); + } + // Spot-check the documented codes. + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.out]) as u16, 0x3C00); // 1.0 + assert_eq!(to_u64(rows[5][NOISY_QUANT_COL_MAP.out]) as u16, 0x7BFF); // saturate + + assert_eq!(to_u64(rows[6][NOISY_QUANT_COL_MAP.out]) as u16, 0xFBFF); // saturate - + } + + /// Bit-exact against the real `noisy_quantize`, with `noised` DERIVED BY THE AIR (not supplied): + /// G1 (this module) proves `t`, the G2 sibling AIR proves `noised = fma(af, X, t)`, and G3 (this + /// module) casts that AIR-derived `noised`. The end-to-end FP16 codes must equal the kernel's. + /// The row deliberately contains a tiny element (subnormal FP16 output) and a large one + /// (near-saturation), exercising every G3 branch. + #[test] + fn g1_and_g3_bit_exact_vs_noisy_quantize() { + use super::super::super::noisy_quant_fma_stark::{FMA_COL_MAP, FmaProgram}; + const R: usize = 32; + let k = 48usize; + let rows: Vec = (0..k) + .map(|j| { + let v = if j == 0 { + 7.5 // near-saturation after scaling + } else if j == 1 { + 2f32.powi(-9) // tiny -> subnormal/zero FP16 output after scaling + } else { + 1.0 + (j % 5) as f32 * 0.25 + }; + f32_to_fp16(v).unwrap() + }) + .collect(); + let e: Vec = (0..R).map(|t| f32_to_fp16(((t % 5) as f32 - 2.0) * 8.0).unwrap()).collect(); + let f: Vec = (0..k * R).map(|t| f32_to_fp16(((t % 7) as f32 - 3.0) * 8.0).unwrap()).collect(); + let norms = [row_norms(&rows).unwrap()]; + let built = noisy_quantize(&rows, &e, &f, &norms, R).unwrap(); + let noise = crate::api::fp16::accumulate::a100_matmul(&e, &f, None, 1, k, R); + let bf = crate::api::fp8::dtype::bf16_to_f32(built.beta[0]); + + // Build t from G1 (= bf*noise), then DERIVE noised via the G2 AIR. + let t: Vec = (0..k).map(|j| bf * noise[j]).collect(); + let t_sign: Vec = t.iter().map(|&x| u64::from(x.to_bits() >> 31)).collect(); + let t_mant: Vec = + t.iter().map(|&x| if (x.to_bits() >> 23) & 0xFF == 0 { 0 } else { (1u64 << 23) + u64::from(x.to_bits() & 0x7F_FFFF) }).collect(); + let t_exp: Vec = t.iter().map(|&x| u64::from((x.to_bits() >> 23) & 0xFF)).collect(); + let fma_prog = FmaProgram::new(k); + let alpha_vec = vec![built.alpha[0]; k]; + let fma_trace = fma_prog.generate_trace::(&alpha_vec, &rows, &t_sign, &t_mant, &t_exp); + let noised: Vec = (0..k) + .map(|j| { + let lo = to_u64(fma_trace[j][FMA_COL_MAP.noised_lo]); + let hi = to_u64(fma_trace[j][FMA_COL_MAP.noised_hi]); + f32::from_bits(((hi << 16) | lo) as u32) + }) + .collect(); + + // Feed the AIR-derived noised to this module (G1 proves t; G3 casts noised). + let items: Vec<_> = (0..k).map(|j| (built.alpha[0], rows[j], built.beta[0], noise[j], noised[j])).collect(); + let (_program, trace) = trace_from(&items); + for j in 0..k { + // noised is DERIVED by the G2 AIR; confirm it reproduces the reference FMA exactly. + let ref_noised = crate::api::fp8::dtype::bf16_to_f32(built.alpha[0]).mul_add(fp16_to_f32(rows[j]), t[j]); + assert_eq!(noised[j].to_bits(), ref_noised.to_bits(), "G2 noised mismatch elem {j}"); + let got = to_u64(trace[j][NOISY_QUANT_COL_MAP.out]) as u16; + assert_eq!(got, built.noised_part[j], "end-to-end FP16 code mismatch at element {j}"); + } + assert!(built.noised_part.iter().any(|&c| c & 0x7FFF >= 0x7000), "expected a near-ceiling element"); + } + + /// G3 subnormal + zero + smallest-normal boundary casts, bit-exact vs `f32_to_fp16(clamp(.))`. + #[test] + fn g3_subnormal_and_zero_outputs() { + let vals: Vec = vec![ + 2f32.powi(-15), // subnormal FP16 (0x0200) + 2f32.powi(-20), // deeper subnormal + 2f32.powi(-24), // smallest subnormal (0x0001) + 2f32.powi(-25), // ties to even -> 0 + 2f32.powi(-26), // underflow -> 0 + -2f32.powi(-16), // signed subnormal + 2f32.powi(-14), // smallest NORMAL (0x0400) via the subnormal round boundary + 2f32.powi(-14) - 2f32.powi(-25), // just below smallest normal + f32::from_bits((102u32 << 23) | 0x400000), // E=102 subnormal with a nonzero rounding + ]; + let items: Vec<_> = vals + .iter() + .map(|&x| (f32_to_bf16(1.0).unwrap(), 0x3C00u16, f32_to_bf16(0.5).unwrap(), 2.0f32, x)) + .collect(); + let (program, rows) = trace_from(&items); + for (i, &x) in vals.iter().enumerate() { + let got = to_u64(rows[i][NOISY_QUANT_COL_MAP.out]) as u16; + assert_eq!(got, f32_to_fp16(x.clamp(-MAX_FP16, MAX_FP16)).unwrap(), "subnormal cast mismatch for {x}"); + } + assert!(!constraints_violated(&Stk::new(program), &rows), "subnormal/zero trace must satisfy constraints"); + } + + #[test] + fn zero_noise_gives_zero_t() { + let items: Vec<_> = vec![( + f32_to_bf16(1.0).unwrap(), + 0x3C00u16, + f32_to_bf16(0.5).unwrap(), + 0.0f32, // zero noise + 3.5f32, + )]; + let (program, rows) = trace_from(&items); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.t_mant]), 0); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.noise_is_zero]), 1); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.t_pow]), 1); + assert!(!constraints_violated(&Stk::new(program), &rows)); + } + + #[test] + fn tampered_traces_fail() { + let items: Vec<_> = (0..16).map(sample).collect(); + let (program, rows) = trace_from(&items); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "baseline honest trace must pass"); + let cases = [ + ("beta", NOISY_QUANT_COL_MAP.beta), + ("noise_sign", NOISY_QUANT_COL_MAP.noise_sign), + ("mn", NOISY_QUANT_COL_MAP.mn), + ("pm", NOISY_QUANT_COL_MAP.pm), + ("t_mant", NOISY_QUANT_COL_MAP.t_mant), + ("t_blo", NOISY_QUANT_COL_MAP.t_blo), + ("t_exp", NOISY_QUANT_COL_MAP.t_exp), + ("noised_exp", NOISY_QUANT_COL_MAP.noised_exp), + ("noised_mant", NOISY_QUANT_COL_MAP.noised_mant), + ("f_sat", NOISY_QUANT_COL_MAP.f_sat), + ("q", NOISY_QUANT_COL_MAP.q), + ("cast_blo", NOISY_QUANT_COL_MAP.cast_blo), + ("is_sat_eff", NOISY_QUANT_COL_MAP.is_sat_eff), + ("out", NOISY_QUANT_COL_MAP.out), + ]; + for (name, col) in cases { + let mut forged = rows.clone(); + forged[0][col] += F::ONE; + assert!(constraints_violated(&stark, &forged), "{name} tamper undetected"); + } + } + + /// Binade-bottom uniqueness: at a power-of-two rounding the former (relaxed) witness — the lower + /// boundary WITHOUT the `+BOTTOM` correction, differing by exactly the former quarter-ulp slack — + /// must be REJECTED, while the honest (corrected) trace passes. `noised = 1.0` makes `q = 2^10` + /// (FP16 1.0, binade bottom); a crafted `beta`/`noise` makes `M_t` a power of two for G1. + #[test] + fn binade_bottom_correction_pins_the_rounding() { + // G3: noised = 1.0 -> q = 2^10, q_bottom = 1. G1: beta = 1.0, noise = 2.0 -> bf*noise = 2.0, + // M_t = 2^23 (power of two), t_bottom = 1. + let items = vec![(f32_to_bf16(1.0).unwrap(), 0x3C00u16, f32_to_bf16(1.0).unwrap(), 2.0f32, 1.0f32)]; + let (program, rows) = trace_from(&items); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "honest power-of-two trace must pass"); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.q_bottom]), 1, "q is a power of two"); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.t_bottom]), 1, "M_t is a power of two"); + + // (a) Revert each lower boundary to the uncorrected value (subtract one factor: the cast + // factor 2^13, the G1 factor 2^d1 = t_pow). The AIR's `blo = (... + BOTTOM)*factor` rejects it. + let mut forged = rows.clone(); + forged[0][NOISY_QUANT_COL_MAP.cast_blo] -= F::from_canonical_u64(1 << 13); + assert!(constraints_violated(&stark, &forged), "cast: uncorrected half-ulp boundary must be rejected"); + let mut forged = rows.clone(); + let tpow = rows[0][NOISY_QUANT_COL_MAP.t_pow]; + forged[0][NOISY_QUANT_COL_MAP.t_blo] -= tpow; + assert!(constraints_violated(&stark, &forged), "G1: uncorrected half-ulp boundary must be rejected"); + + // (b) Clearing either BOTTOM flag at a power of two violates the is-zero gadget. + let mut forged = rows.clone(); + forged[0][NOISY_QUANT_COL_MAP.q_bottom] = F::ZERO; + assert!(constraints_violated(&stark, &forged), "q_bottom must stay pinned to 1"); + let mut forged = rows.clone(); + forged[0][NOISY_QUANT_COL_MAP.t_bottom] = F::ZERO; + assert!(constraints_violated(&stark, &forged), "t_bottom must stay pinned to 1"); + } + + /// RNE uniqueness (anti-grind): at an exact ties-to-even boundary, the honest `q` is the EVEN + /// neighbor; the odd neighbor is the "near-miss" that the former quarter-ulp grinding slack would + /// have admitted. A fully-consistent forged witness for the odd `q` still satisfies every + /// *arithmetic* constraint — it is the RANGE16 bound on the bracket slack (which goes negative + /// => out of domain) that rejects it. This demonstrates the rounding is pinned with no residual + /// slack. + #[test] + fn cast_rne_is_uniquely_pinned_by_the_slack_range() { + // noised = f32(E=130, mant=4096): full = 2^23 + 4096, low 13 bits = 0x1000 (an exact tie), + // full>>13 = 1024 (EVEN) -> honest q = 1024 (ties to even, rounds down). + let noised = f32::from_bits((130u32 << 23) | 4096); + let items = vec![(f32_to_bf16(1.0).unwrap(), 0x3C00u16, f32_to_bf16(0.5).unwrap(), 2.0f32, noised)]; + let (program, rows) = trace_from(&items); + let stark = Stk::new(program.clone()); + assert_eq!(to_u64(rows[0][NOISY_QUANT_COL_MAP.q]), 1024, "honest q is the even neighbor"); + assert!(!constraints_violated(&stark, &rows), "honest tie trace passes"); + + // Honest trace: every RANGE16 key is in domain. + let lu = noisy_quant_lut_lookups::(); + let in_domain = |rows: &[[F; NUM_NOISY_QUANT_COLUMNS]]| -> bool { + let polys = trace_rows_to_poly_values(rows.to_vec()); + lu.iter().filter(|l| l.table == LutTable::Range16).all(|l| { + (0..program.live_rows()).all(|r| l.keys[0].eval_table(&polys, r, &[]).to_canonical_u64() < 1 << 16) + }) + }; + assert!(in_domain(&rows), "honest tie trace keys all in RANGE16 domain"); + + // Forge the ODD neighbor q = 1025 with a fully consistent arithmetic witness. + let mut f = rows.clone(); + let set = |f: &mut [[F; NUM_NOISY_QUANT_COLUMNS]], col: usize, val: u64| { + f[0][col] = F::from_canonical_u64(val); + }; + set(&mut f, NOISY_QUANT_COL_MAP.q, 1025); + set(&mut f, NOISY_QUANT_COL_MAP.q_parity, 1); + set(&mut f, NOISY_QUANT_COL_MAP.q_half, 512); + set(&mut f, NOISY_QUANT_COL_MAP.q_bottom, 0); + f[0][NOISY_QUANT_COL_MAP.q_bottom_inv] = F::ONE; // inv(1025 - 1024) + set(&mut f, NOISY_QUANT_COL_MAP.q_lo_slack, 1); + set(&mut f, NOISY_QUANT_COL_MAP.cast_blo, (4 * 1025 - 2) * (1 << 13)); + set(&mut f, NOISY_QUANT_COL_MAP.cast_bhi, (4 * 1025 + 2) * (1 << 13)); + set(&mut f, NOISY_QUANT_COL_MAP.carry, 0); + f[0][NOISY_QUANT_COL_MAP.carry_inv] = F::from_canonical_u64(2048 - 1025).inverse(); + set(&mut f, NOISY_QUANT_COL_MAP.mf, 1); + // Upper slack stays in range (0x7FFF); the lower slack is the one that goes negative. + set(&mut f, NOISY_QUANT_COL_MAP.cast_su_hi, 0); + set(&mut f, NOISY_QUANT_COL_MAP.cast_sl_hi, 0); + // Output encode for the forged (odd) q: exp field 18, mantissa 1. + set(&mut f, NOISY_QUANT_COL_MAP.out, (18 << 10) | 1); + + // The arithmetic constraints alone do NOT catch the near-miss... + assert!(!constraints_violated(&stark, &f), "arithmetic alone cannot reject the odd neighbor"); + // ...but the RANGE16 bound on the (now negative) lower bracket slack does. + assert!(!in_domain(&f), "the forged near-miss slack leaves RANGE16's domain (RNE is pinned)"); + } + + /// Every committed-LUT key the honest trace presents lands in its table's domain (RANGE16 keys + /// `< 2^16`, FP16POW2 keys `<= 255` with `value = 2^min(key, 26)`). + #[test] + fn honest_lut_keys_are_in_domain() { + let items: Vec<_> = (0..24).map(sample).collect(); + let (program, rows) = trace_from(&items); + let live = program.live_rows(); + let polys = trace_rows_to_poly_values(rows); + let lu = noisy_quant_lut_lookups::(); + for (li, lookup) in lu.iter().enumerate() { + for r in 0..live { + match lookup.table { + LutTable::Range16 => { + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k < 1 << 16, "RANGE16 lookup {li} key {k} out of range at row {r}"); + } + LutTable::Fp16Pow2 => { + let k = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + let v = lookup.values[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(k <= 255, "FP16POW2 key {k} out of range at row {r}"); + assert_eq!(v, 1 << k.min(26), "FP16POW2 value {v} != 2^min({k},26) at row {r}"); + } + other => panic!("unexpected table {other:?}"), + } + } + } + } + + #[test] + fn degree_is_at_most_three() { + let (program, _) = trace_from(&(0..8).map(sample).collect::>()); + test_stark_low_degree::(Stk::new(program)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + let (program, _) = trace_from(&(0..8).map(sample).collect::>()); + test_stark_circuit_constraints::(Stk::new(program)).unwrap(); + } +} diff --git a/zk-pow/src/circuit/fp16/policy_stark/columns.rs b/zk-pow/src/circuit/fp16/policy_stark/columns.rs new file mode 100644 index 000000000..24b6ec366 --- /dev/null +++ b/zk-pow/src/circuit/fp16/policy_stark/columns.rs @@ -0,0 +1,86 @@ +//! Trace columns for the FP16 "unpredictable accumulation steps" policy AIR. +//! +//! One row per `G = 8` group step (the same row grid as the A100 matmul AIR), carrying the +//! per-step census and the tile-global running accumulators that realise the exact integer gate +//! of [`crate::api::fp16::policy`]. See [`super::stark`] for the constraint derivation (`PP1..`). + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one `PolicyStarkA100` trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct PolicyA100ColumnsView { + // ---- Structural, class (a): verifier-recomputable from the AIR geometry. ---- + /// Output cell index, constant across the cell's `k/8` rows. + pub cell_id: T, + /// 1 on each cell's last row (a cell boundary — resets the run detector). + pub is_cell_final: T, + /// 1 on trailing power-of-two padding rows (excluded from every accumulator). + pub is_padding: T, + /// Operand flat-index base for this row's 8 A lanes (`r*k + j*GROUP`), mirroring the matmul + /// AIR's column of the same name. Class (a): verifier-recomputable. Together with + /// [`Self::operand_index_base_b`] it is the unique per-live-row key the census-import CTL + /// (`matmul -> policy`) binds on, so the policy reads the matmul's tightly-pinned census + /// instead of regenerating it. + pub operand_index_base_a: T, + /// Operand flat-index base for this row's 8 B lanes (`h*k + c*k + j*GROUP`). Class (a). + pub operand_index_base_b: T, + + // ---- Per-step census (CTL-imported from the matmul AIR in the full system; see docs). ---- + /// 1 iff this group step is a breakpoint (`a100_dot` breakpoint; MA11 of the matmul AIR). + pub group_breakpoint: T, + /// Number of products truncated on this step, in `[0, 8]` (the matmul AIR's per-step + /// `products_truncated_flag` sum). + pub products_truncated: T, + + // ---- Derived per-step + tile-global running accumulators. ---- + /// 1 iff this step starts a maximal run of non-breakpoint steps: non-breakpoint AND + /// (cell-start OR the previous step was a breakpoint). PP2. + pub run_start: T, + /// Inclusive running tile count of breakpoint steps (over non-padding rows). PP3. + pub tile_breakpoints: T, + /// Inclusive running tile numerator `sum[ 8*N_bp + 32*N_runs + N_pt ]` (over non-padding + /// rows): each step adds `8*breakpoint + 32*run_start + (1-breakpoint)*products_truncated`. PP4. + pub tile_numerator: T, + + // ---- Gate slack (meaningful on the last row; RANGE16-checked on every row). ---- + /// Low/high 16-bit limbs of `rho_slack = 5*tile_numerator - 6*cells*k >= 0`. PP5. + pub rho_slack_lo: T, + pub rho_slack_hi: T, + /// Low/high 16-bit limbs of `fbp_slack = 10*tile_breakpoints - 3*total_steps >= 0`. PP6. + pub fbp_slack_lo: T, + pub fbp_slack_hi: T, +} + +/// Total number of committed `PolicyStarkA100` columns. +pub const NUM_POLICY_A100_COLUMNS: usize = size_of::>(); + +const _: () = assert!(NUM_POLICY_A100_COLUMNS == 14); + +columns_view!(PolicyA100ColumnsView, NUM_POLICY_A100_COLUMNS, POLICY_A100_COL_MAP); + +/// Number of leading class (a) ("known") columns (pure functions of AIR geometry): +/// `cell_id`, `is_cell_final`, `is_padding`, and the two operand-index bases the census-import +/// CTL keys on. +pub const NUM_POLICY_A100_KNOWN_COLUMNS: usize = POLICY_A100_COL_MAP.operand_index_base_b + 1; + +/// No public inputs — the gate thresholds are AIR constants of the program geometry. +pub const NUM_POLICY_A100_PUBLIC_INPUTS: usize = 0; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_POLICY_A100_COLUMNS] = POLICY_A100_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + assert_eq!(POLICY_A100_COL_MAP.cell_id, 0); + assert_eq!(POLICY_A100_COL_MAP.is_padding, 2); + assert_eq!(POLICY_A100_COL_MAP.operand_index_base_a, 3); + assert_eq!(POLICY_A100_COL_MAP.operand_index_base_b, 4); + assert_eq!(NUM_POLICY_A100_KNOWN_COLUMNS, 5); + } +} diff --git a/zk-pow/src/circuit/fp16/policy_stark/ctl.rs b/zk-pow/src/circuit/fp16/policy_stark/ctl.rs new file mode 100644 index 000000000..b935d7e19 --- /dev/null +++ b/zk-pow/src/circuit/fp16/policy_stark/ctl.rs @@ -0,0 +1,60 @@ +//! Committed-LUT and cross-table inventory for the FP16 policy AIR. +//! +//! Two kinds of channel: +//! +//! * **RANGE16** (wired here): the gate slack limbs `rho_slack_{lo,hi}`, `fbp_slack_{lo,hi}` +//! and the per-step `products_truncated` count. The slack limb checks are the soundness of the +//! policy inequalities — a tile below either threshold has a negative slack, whose field +//! representation has no two 16-bit limbs, so no RANGE16-valid witness exists. +//! * **Census import** (wired): `group_breakpoint` and `products_truncated` are bound to equal the +//! matmul AIR's tightly-pinned per-step census (MA11 / summed MA3 flags) by a cross-table lookup +//! from the matmul table into the policy table, keyed on the unique per-live-row +//! `(operand_index_base_a, operand_index_base_b)` pair — see +//! [`crate::circuit::fp16::ctl::census_import_ctl`] and [`census_import_note`]. The trace +//! generator fills the census from the ground-truth `a100_dot`, and the batch verification +//! enforces it matches the matmul's. + +use plonky2::field::types::Field; +use starky::lookup::Column; + +use super::columns::POLICY_A100_COL_MAP; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// The policy AIR's committed-LUT instances: RANGE16 on the four gate-slack limbs and the +/// per-step products-truncated count — five instances. All reuse the shared `RANGE16` table. +pub fn policy_a100_lut_lookups() -> Vec> { + let m = &POLICY_A100_COL_MAP; + vec![ + LutLookup::rc16(Column::single(m.rho_slack_lo)), + LutLookup::rc16(Column::single(m.rho_slack_hi)), + LutLookup::rc16(Column::single(m.fbp_slack_lo)), + LutLookup::rc16(Column::single(m.fbp_slack_hi)), + LutLookup::rc16(Column::single(m.products_truncated)), + ] +} + +/// The census-import channel is implemented in +/// [`crate::circuit::fp16::ctl::census_import_ctl`]: the matmul AIR's looking side exports, per +/// group step, `(operand_index_base_a, operand_index_base_b, group_breakpoint, +/// Σ products_truncated_flag)`, and the policy AIR's looked side imports the same tuple on its +/// matching row (keyed by the unique `(base_a, base_b)` pair) — binding the policy census to the +/// matmul's tightly-pinned one bit-for-bit. +pub const fn census_import_note() -> &'static str { + "census import (matmul -> policy) is wired in circuit::fp16::ctl::census_import_ctl" +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + + type F = GoldilocksField; + + #[test] + fn inventory_is_five_range16_instances() { + let lookups = policy_a100_lut_lookups::(); + assert_eq!(lookups.len(), 5); + assert!(lookups.iter().all(|l| l.table == crate::circuit::fp8::luts::LutTable::Range16)); + } +} diff --git a/zk-pow/src/circuit/fp16/policy_stark/mod.rs b/zk-pow/src/circuit/fp16/policy_stark/mod.rs new file mode 100644 index 000000000..5317d5772 --- /dev/null +++ b/zk-pow/src/circuit/fp16/policy_stark/mod.rs @@ -0,0 +1,10 @@ +//! FP16 jackpot-policy AIR: proves an opened `h x w x k` tile clears the "unpredictable +//! accumulation steps" gate of [`crate::api::fp16::policy`] (`f_bp >= 0.30` and `rho >= 1.2`), +//! as exact integer inequalities over the per-group census. See [`stark`]. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{NUM_POLICY_A100_COLUMNS, NUM_POLICY_A100_KNOWN_COLUMNS, POLICY_A100_COL_MAP, PolicyA100ColumnsView}; +pub use stark::PolicyStarkA100; diff --git a/zk-pow/src/circuit/fp16/policy_stark/stark.rs b/zk-pow/src/circuit/fp16/policy_stark/stark.rs new file mode 100644 index 000000000..19d047f0d --- /dev/null +++ b/zk-pow/src/circuit/fp16/policy_stark/stark.rs @@ -0,0 +1,560 @@ +//! The FP16 jackpot-policy AIR: proves an opened tile clears the "unpredictable accumulation +//! steps" gate of [`crate::api::fp16::policy`] — breakpoint density `f_bp >= 0.30` AND +//! certified-work ratio `rho >= 1.2` — as exact integer inequalities over the per-group census. +//! +//! The AIR forks the tile-wide integer-budget pattern of `circuit::fp8::unpredictability`: it +//! walks the same one-row-per-group-step grid as the A100 matmul AIR, accumulates the three +//! policy quantities per cell and tile-wide, and gates on the last row. The gate avoids division +//! by clearing denominators: +//! +//! * `rho = numerator / (cells*k) >= 6/5 <=> 5*numerator >= 6*cells*k`, +//! * `f_bp = breakpoints / total_steps >= 3/10 <=> 10*breakpoints >= 3*total_steps`, +//! +//! with `numerator = sum_cells[ 8*N_bp + 32*N_runs + N_pt ]` (`G = 8`, `NOISE_RANK = 32`), +//! `N_runs` counted by a run-start detector (a step starts a run iff it is non-breakpoint and the +//! previous step was a breakpoint or the cell start), and `N_pt` the products truncated on +//! non-breakpoint steps. Each inequality is witnessed by a nonnegative slack whose 16-bit limbs +//! are RANGE16-checked, so a tile below either threshold has no satisfying (nonnegative) slack. +//! +//! The per-step census columns (`group_breakpoint`, `products_truncated`) are the matmul AIR's +//! tightly-pinned census (MA11 / MA3); in the FP16 batch they are bound to the matmul's via the +//! `matmul -> policy` census-import CTL ([`crate::circuit::fp16::ctl::census_import_ctl`]). Here the +//! trace generator fills them from the ground-truth [`crate::api::fp16::accumulate::a100_dot`] +//! census, and the tests cross-check the AIR's gate against [`crate::api::fp16::policy::evaluate`]. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{ + NUM_POLICY_A100_COLUMNS, NUM_POLICY_A100_PUBLIC_INPUTS, PolicyA100ColumnsView, +}; +use crate::api::fp16::accumulate::{GROUP, PolicyStep, a100_dot}; +use crate::api::fp16::policy::{MIN_FBP, MIN_RHO, NOISE_RANK}; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// `rho >= MIN_RHO` cleared of division: `RHO_NUM * numerator >= RHO_DEN * cells * k`. +/// `MIN_RHO = 1.2 = 6/5`. +const RHO_NUM: u64 = 5; +const RHO_DEN: u64 = 6; +/// `f_bp >= MIN_FBP` cleared of division: `FBP_NUM * breakpoints >= FBP_DEN * total_steps`. +/// `MIN_FBP = 0.30 = 3/10`. +const FBP_NUM: u64 = 10; +const FBP_DEN: u64 = 3; + +const _: () = assert!(RHO_DEN as f64 / RHO_NUM as f64 == MIN_RHO); +const _: () = assert!(FBP_DEN as f64 / FBP_NUM as f64 == MIN_FBP); + +/// The A100 FP16 policy AIR for one `h x w` tile with inner dimension `k` (a multiple of `G`). +#[derive(Clone, Debug)] +pub struct PolicyStarkA100, const D: usize> { + pub h: usize, + pub w: usize, + pub k: usize, + _phantom: PhantomData, +} + +impl, const D: usize> PolicyStarkA100 { + pub fn new(h: usize, w: usize, k: usize) -> Self { + assert_eq!(k % GROUP, 0, "k must be a multiple of the group size {GROUP}"); + Self { h, w, k, _phantom: PhantomData } + } + + pub fn rows_per_cell(&self) -> usize { + self.k / GROUP + } + + pub fn live_rows(&self) -> usize { + self.h * self.w * self.rows_per_cell() + } + + pub fn num_rows(&self) -> usize { + self.live_rows().next_power_of_two() + } + + /// `cells * k` — the `rho` denominator (before clearing). + fn cells_times_k(&self) -> u64 { + (self.h * self.w * self.k) as u64 + } + + /// `total_steps = live_rows` — the `f_bp` denominator. + fn total_steps(&self) -> u64 { + self.live_rows() as u64 + } + + /// The gate's cleared right-hand sides `(6*cells*k, 3*total_steps)`. + fn gate_constants(&self) -> (u64, u64) { + (RHO_DEN * self.cells_times_k(), FBP_DEN * self.total_steps()) + } + + /// Class (a) known columns: `cell_id`, `is_cell_final`, `is_padding`, and the two + /// operand-index bases (`operand_index_base_a/b`) the census-import CTL keys on. The bases + /// mirror the matmul AIR's columns of the same name bit-for-bit so the `(base_a, base_b)` + /// key tuple matches across the two tables on every live row. + pub fn known_values(&self) -> Vec> { + let (h, w, k) = (self.h, self.w, self.k); + let rpc = self.rows_per_cell(); + let num_rows = self.num_rows(); + let mut cell_id = Vec::with_capacity(num_rows); + let mut is_cell_final = Vec::with_capacity(num_rows); + let mut is_padding = Vec::with_capacity(num_rows); + let mut base_a = Vec::with_capacity(num_rows); + let mut base_b = Vec::with_capacity(num_rows); + for r in 0..h { + for c in 0..w { + for j in 0..rpc { + cell_id.push(F::from_canonical_usize(r * w + c)); + is_cell_final.push(F::from_bool(j == rpc - 1)); + is_padding.push(F::ZERO); + base_a.push(F::from_canonical_usize(r * k + j * GROUP)); + base_b.push(F::from_canonical_usize(h * k + c * k + j * GROUP)); + } + } + } + for t in 0..num_rows - self.live_rows() { + cell_id.push(F::from_canonical_usize(h * w + t)); + is_cell_final.push(F::ONE); + is_padding.push(F::ONE); + base_a.push(F::ZERO); + base_b.push(F::ZERO); + } + [cell_id, is_cell_final, is_padding, base_a, base_b] + .into_iter() + .map(PolynomialValues::new) + .collect() + } + + /// Generates the policy trace for the `h x w x k` tile (operands row-major; `b` transposed), + /// accumulated from `c = 0` exactly as the scheme does. The per-step census is the + /// ground-truth `a100_dot` census; the run detector and the tile accumulators are filled to + /// match [`crate::api::fp16::policy::evaluate`] bit-for-bit. + pub fn generate_trace(&self, a_codes: &[u16], b_codes: &[u16]) -> Vec<[F; NUM_POLICY_A100_COLUMNS]> { + let (h, w, k) = (self.h, self.w, self.k); + assert_eq!(a_codes.len(), h * k, "a_codes must be h*k FP16 codes"); + assert_eq!(b_codes.len(), w * k, "b_codes must be w*k FP16 codes"); + let rpc = self.rows_per_cell(); + let num_rows = self.num_rows(); + let mut rows: Vec<[F; NUM_POLICY_A100_COLUMNS]> = Vec::with_capacity(num_rows); + + let mut tile_breakpoints: u64 = 0; + let mut tile_numerator: u64 = 0; + for r in 0..h { + for c in 0..w { + let mut census: Vec = Vec::with_capacity(rpc); + a100_dot(&a_codes[r * k..r * k + k], &b_codes[c * k..c * k + k], 0.0, Some(&mut census)); + debug_assert_eq!(census.len(), rpc); + let mut in_run = false; + for (j, step) in census.iter().enumerate() { + let run_start = !step.breakpoint && !in_run; + if step.breakpoint { + in_run = false; + } else if !in_run { + in_run = true; + } + tile_breakpoints += u64::from(step.breakpoint); + tile_numerator += GROUP as u64 * u64::from(step.breakpoint) + + NOISE_RANK * u64::from(run_start) + + if step.breakpoint { 0 } else { u64::from(step.products_truncated) }; + let row = PolicyA100ColumnsView:: { + cell_id: F::from_canonical_usize(r * w + c), + is_cell_final: F::from_bool(j == rpc - 1), + operand_index_base_a: F::from_canonical_usize(r * k + j * GROUP), + operand_index_base_b: F::from_canonical_usize(h * k + c * k + j * GROUP), + group_breakpoint: F::from_bool(step.breakpoint), + products_truncated: F::from_canonical_u32(step.products_truncated), + run_start: F::from_bool(run_start), + tile_breakpoints: F::from_canonical_u64(tile_breakpoints), + tile_numerator: F::from_canonical_u64(tile_numerator), + ..Default::default() + }; + rows.push(row.into()); + } + } + } + for t in 0..num_rows - self.live_rows() { + // Padding rows carry a breakpoint of 0 and (since their predecessor is always a + // cell-final row) a run_start of 1, matching PP2's transition formula; both are gated + // out of the accumulators by `is_padding`, which only ever carry the running totals. + let row = PolicyA100ColumnsView:: { + cell_id: F::from_canonical_usize(h * w + t), + is_cell_final: F::ONE, + is_padding: F::ONE, + run_start: F::ONE, + tile_breakpoints: F::from_canonical_u64(tile_breakpoints), + tile_numerator: F::from_canonical_u64(tile_numerator), + ..Default::default() + }; + rows.push(row.into()); + } + + // The gate slack lives on the last row (RANGE16-limbed; zero elsewhere). + let (rho_rhs, fbp_rhs) = self.gate_constants(); + let rho_slack = (RHO_NUM * tile_numerator).wrapping_sub(rho_rhs); + let fbp_slack = (FBP_NUM * tile_breakpoints).wrapping_sub(fbp_rhs); + let last = num_rows - 1; + let m = &super::columns::POLICY_A100_COL_MAP; + rows[last][m.rho_slack_lo] = F::from_canonical_u64(rho_slack & 0xFFFF); + rows[last][m.rho_slack_hi] = F::from_canonical_u64((rho_slack >> 16) & 0xFFFF); + rows[last][m.fbp_slack_lo] = F::from_canonical_u64(fbp_slack & 0xFFFF); + rows[last][m.fbp_slack_hi] = F::from_canonical_u64((fbp_slack >> 16) & 0xFFFF); + rows + } +} + +/// Evaluates every policy constraint (degree <= 3). RANGE16 facts (the slack limbs and the +/// per-step `products_truncated`) are LUT-borne; see [`super::ctl`]. +pub(crate) fn eval_policy_a100_constraints( + vars: &StarkFrame, + eval: &mut E, + rho_rhs: u64, + fbp_rhs: u64, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_POLICY_A100_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &PolicyA100ColumnsView = lv.borrow(); + let nv: &[V; NUM_POLICY_A100_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let nv: &PolicyA100ColumnsView = nv.borrow(); + + let one = eval.i32(1); + + // ---- PP1 — per-step booleans. ---- + eval.constraint_bool(lv.is_padding); + eval.constraint_bool(lv.group_breakpoint); + eval.constraint_bool(lv.run_start); + + // The per-step work increment incr(x) = (1-pad)*(8*bp + 32*run_start + (1-bp)*pt). + let incr = |eval: &mut E, x: &PolicyA100ColumnsView| -> V { + let g = eval.u64(GROUP as u64); + let g_bp = eval.mul(g, x.group_breakpoint); + let r = eval.u64(NOISE_RANK); + let r_run = eval.mul(r, x.run_start); + let not_bp = eval.sub(one, x.group_breakpoint); + let pt_term = eval.mul(not_bp, x.products_truncated); + let s = eval.add(g_bp, r_run); + let s = eval.add(s, pt_term); + let not_pad = eval.sub(one, x.is_padding); + eval.mul(not_pad, s) + }; + + // ---- PP2 — run-start detector. First step of the trace is a cell start. ---- + let first_run = eval.sub(one, lv.group_breakpoint); + let first_run = eval.sub(lv.run_start, first_run); + eval.constraint_first_row(first_run); + // Transition: a non-breakpoint step starts a run iff the previous row ended a run, i.e. it was + // a cell-final row or itself a breakpoint. (cell-final + (1-cell-final)*prev_bp is in {0,1}.) + let not_bp_next = eval.sub(one, nv.group_breakpoint); + let not_final = eval.sub(one, lv.is_cell_final); + let carry_run = eval.mul(not_final, lv.group_breakpoint); + let can_start = eval.add(lv.is_cell_final, carry_run); + let expect = eval.mul(not_bp_next, can_start); + let run_diff = eval.sub(nv.run_start, expect); + eval.constraint_transition(run_diff); + + // ---- PP3 — tile breakpoint count (inclusive running sum over non-padding rows). The first + // trace row is always a live cell start, so its anchor needs no padding factor (keeping the + // Lagrange-weighted first-row constraint within the degree-3 budget). ---- + let first_bp = eval.sub(lv.tile_breakpoints, lv.group_breakpoint); + eval.constraint_first_row(first_bp); + let not_pad_next = eval.sub(one, nv.is_padding); + let add_bp = eval.mul(not_pad_next, nv.group_breakpoint); + let step_bp = eval.add(lv.tile_breakpoints, add_bp); + let step_bp = eval.sub(nv.tile_breakpoints, step_bp); + eval.constraint_transition(step_bp); + + // ---- PP4 — tile numerator (inclusive running sum of incr). The first row is live, so its + // anchor uses the padding-free increment `8*bp + 32*run_start + (1-bp)*pt` (degree 2). ---- + let g = eval.u64(GROUP as u64); + let g_bp0 = eval.mul(g, lv.group_breakpoint); + let r = eval.u64(NOISE_RANK); + let r_run0 = eval.mul(r, lv.run_start); + let not_bp0 = eval.sub(one, lv.group_breakpoint); + let pt_term0 = eval.mul(not_bp0, lv.products_truncated); + let incr0 = eval.add(g_bp0, r_run0); + let incr0 = eval.add(incr0, pt_term0); + let first_num = eval.sub(lv.tile_numerator, incr0); + eval.constraint_first_row(first_num); + let incr_next = incr(eval, nv); + let step_num = eval.add(lv.tile_numerator, incr_next); + let step_num = eval.sub(nv.tile_numerator, step_num); + eval.constraint_transition(step_num); + + // ---- PP5 — rho gate on the last row: 5*numerator - 6*cells*k = rho_slack >= 0. The slack's + // RANGE16 limbs (PP-CTL) make >= 0 and < 2^32 the only representation, so a tile with + // rho < 1.2 has no valid nonnegative slack. ---- + let limb_shift = eval.u64(1 << 16); + let rho_num = eval.u64(RHO_NUM); + let lhs = eval.mul(rho_num, lv.tile_numerator); + let rhs = eval.u64(rho_rhs); + let lhs = eval.sub(lhs, rhs); + let slack = eval.mad(lv.rho_slack_hi, limb_shift, lv.rho_slack_lo); + let gate = eval.sub(lhs, slack); + eval.constraint_last_row(gate); + + // ---- PP6 — f_bp gate on the last row: 10*breakpoints - 3*total_steps = fbp_slack >= 0. ---- + let fbp_num = eval.u64(FBP_NUM); + let lhs = eval.mul(fbp_num, lv.tile_breakpoints); + let rhs = eval.u64(fbp_rhs); + let lhs = eval.sub(lhs, rhs); + let slack = eval.mad(lv.fbp_slack_hi, limb_shift, lv.fbp_slack_lo); + let gate = eval.sub(lhs, slack); + eval.constraint_last_row(gate); +} + +impl, const D: usize> Stark for PolicyStarkA100 { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_POLICY_A100_COLUMNS, NUM_POLICY_A100_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let (rho_rhs, fbp_rhs) = self.gate_constants(); + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_policy_a100_constraints(vars, &mut evaluator, rho_rhs, fbp_rhs); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let (rho_rhs, fbp_rhs) = self.gate_constants(); + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_policy_a100_constraints(vars, &mut evaluator, rho_rhs, fbp_rhs); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + /// The policy AIR is a looking side of its RANGE16 checks and the looked side of the + /// census-import CTL, so it appears in the FP16 batch's CTL set. + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + + use super::*; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::fp16::policy::{evaluate, replay_and_evaluate}; + use crate::circuit::fp16::policy_stark::columns::POLICY_A100_COL_MAP; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type P = PolicyStarkA100; + + const VECTORS: &str = include_str!("../../../api/fp16/testdata/a100_dot_vectors.txt"); + + fn constraints_hold(program: &P, rows: &[[F; NUM_POLICY_A100_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).all(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + // z_last is zero on the last row, so `constraint_transition`s (and their cyclic + // wrap) are inactive there — matching the prover's vanishing polynomial. + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + program.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().into_iter().all(|acc| acc == F::ZERO) + }) + } + + /// The oracle numerator and breakpoint count for a tile, straight from `policy`'s definition. + fn oracle_totals(a: &[u16], b: &[u16], h: usize, w: usize, k: usize) -> (u64, u64) { + use crate::api::fp16::accumulate::{GROUP, PolicyStep, a100_dot}; + let (mut numerator, mut breakpoints) = (0u64, 0u64); + for r in 0..h { + for c in 0..w { + let mut census: Vec = Vec::new(); + a100_dot(&a[r * k..r * k + k], &b[c * k..c * k + k], 0.0, Some(&mut census)); + let mut in_run = false; + for step in &census { + if step.breakpoint { + breakpoints += 1; + numerator += GROUP as u64; + in_run = false; + } else { + numerator += u64::from(step.products_truncated); + if !in_run { + numerator += NOISE_RANK; + in_run = true; + } + } + } + } + } + (numerator, breakpoints) + } + + fn last_totals(program: &P, rows: &[[F; NUM_POLICY_A100_COLUMNS]]) -> (u64, u64) { + let last = program.num_rows() - 1; + let m = &POLICY_A100_COL_MAP; + (rows[last][m.tile_numerator].to_canonical_u64(), rows[last][m.tile_breakpoints].to_canonical_u64()) + } + + #[test] + fn padded_trace_matches_known_values() { + let program = P::new(3, 5, 32); // 15 cells x 4 rows = 60 live -> 64. + let a: Vec = (0..program.h * program.k).map(|i| f32_to_fp16(((i % 7) as f32) - 3.0).unwrap()).collect(); + let b: Vec = (0..program.w * program.k).map(|i| f32_to_fp16(((i % 5) as f32) - 2.0).unwrap()).collect(); + let rows = program.generate_trace(&a, &b); + assert_eq!(program.live_rows(), 60); + assert_eq!(rows.len(), 64); + let known = program.known_values(); + for (col, poly) in known.iter().enumerate() { + for (r, row) in rows.iter().enumerate() { + assert_eq!(poly.values[r], row[col], "known column {col} row {r}"); + } + } + assert!(constraints_hold(&program, &rows) == evaluate_from_codes(&program, &a, &b).accept); + } + + fn evaluate_from_codes(program: &P, a: &[u16], b: &[u16]) -> crate::api::fp16::policy::PolicyReport { + replay_and_evaluate(a, b, program.h, program.w, program.k).1 + } + + /// The AIR's gate decision equals `policy::evaluate` on every reference-vector tile, and its + /// running numerator / breakpoint totals equal the oracle's — covering both accept and reject. + #[test] + fn gate_matches_policy_oracle_on_reference_vectors() { + let (mut saw_accept, mut saw_reject) = (false, false); + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % GROUP != 0 { + continue; + } + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let program = P::new(1, 1, k); + let rows = program.generate_trace(&a, &b); + let report = evaluate(&replay_census(&a, &b, k), k); + // Accumulators match the oracle totals exactly. + assert_eq!(last_totals(&program, &rows), oracle_totals(&a, &b, 1, 1, k), "totals k={k}"); + // The gate decision matches policy::evaluate. + assert_eq!(constraints_hold(&program, &rows), report.accept, "gate decision k={k}"); + saw_accept |= report.accept; + saw_reject |= !report.accept; + } + assert!(saw_accept, "reference vectors must include an accepting 1x1 tile"); + assert!(saw_reject, "reference vectors must include a rejecting 1x1 tile"); + } + + fn replay_census(a: &[u16], b: &[u16], _k: usize) -> Vec> { + use crate::api::fp16::accumulate::a100_dot; + let mut steps = Vec::new(); + a100_dot(a, b, 0.0, Some(&mut steps)); + vec![steps] + } + + /// A flat tile (all operands equal, no truncation, no breakpoints) has `f_bp = 0` and + /// `rho < 1.2`: both gate slacks go negative, so no RANGE16-valid witness exists and the + /// last-row gate constraints cannot vanish. + #[test] + fn flat_tile_is_rejected_by_the_gate() { + let program = P::new(2, 2, 64); + let one = f32_to_fp16(1.0).unwrap(); + let a = vec![one; program.h * program.k]; + let b = vec![one; program.w * program.k]; + let report = evaluate_from_codes(&program, &a, &b); + assert!(!report.accept, "a flat tile must fail the policy"); + let rows = program.generate_trace(&a, &b); + assert!(!constraints_hold(&program, &rows), "the gate must reject a flat tile"); + } + + /// Overstating the certified work after the fact — bumping the final tile numerator without a + /// matching slack — breaks the rho gate; likewise for the breakpoint count and f_bp. + #[test] + fn tampered_gate_witnesses_break_constraints() { + // Use an accepting reference-vector tile as the honest baseline. + let mut chosen: Option<(usize, Vec, Vec)> = None; + for line in VECTORS.lines() { + let t: Vec<&str> = line.split_whitespace().collect(); + if t.is_empty() || line.trim_start().starts_with('#') { + continue; + } + let k: usize = t[0].parse().unwrap(); + if k % GROUP != 0 { + continue; + } + let a: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + if evaluate(&replay_census(&a, &b, k), k).accept { + chosen = Some((k, a, b)); + break; + } + } + let (k, a, b) = chosen.expect("need an accepting reference tile"); + let program = P::new(1, 1, k); + let rows = program.generate_trace(&a, &b); + assert!(constraints_hold(&program, &rows), "honest accepting tile must satisfy the gate"); + let m = &POLICY_A100_COL_MAP; + let last = program.num_rows() - 1; + + // Bumping a slack limb breaks the gate equality (slack no longer equals LHS). + for col in [m.rho_slack_lo, m.fbp_slack_lo, m.tile_numerator, m.tile_breakpoints] { + let mut t = rows.clone(); + t[last][col] += F::ONE; + assert!(!constraints_hold(&program, &t), "tampering column {col} must break the gate/accumulator"); + } + // Inflating the running numerator mid-trace breaks the inclusive-sum transition. + let mid = program.live_rows() / 2; + let mut t = rows.clone(); + t[mid][m.tile_numerator] += F::ONE; + assert!(!constraints_hold(&program, &t), "a broken numerator running sum must be caught"); + } + + #[test] + fn degree_is_at_most_three() { + test_stark_low_degree::(P::new(2, 2, 64)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + test_stark_circuit_constraints::(P::new(2, 2, 64)).unwrap(); + } +} diff --git a/zk-pow/src/circuit/fp16/row_scale_stark/columns.rs b/zk-pow/src/circuit/fp16/row_scale_stark/columns.rs new file mode 100644 index 000000000..1941ffa03 --- /dev/null +++ b/zk-pow/src/circuit/fp16/row_scale_stark/columns.rs @@ -0,0 +1,472 @@ +//! Fixed trace layout for the FP16 per-row scale-derivation AIR. +//! +//! One row per FP16 operand element (one `code`), plus trailing all-zero `IS_PAD = 1` rows that +//! pad the live `k` elements to a power of two. Two kinds of column: +//! +//! * **Per-element** columns prove the running reduction over the row — the sequential f32 sum of +//! squares `sumsq = Σ (fp16_to_f32(x))^2` (one RNE f32 add per element, mirroring +//! [`crate::circuit::fp16::noisy_quant_fma_stark`]'s windowed fold) and the running maximum +//! `|x|` (used for `linf`). +//! * **Scalar** columns are a pure function of the whole row (the two norms and the two bf16 +//! scales). They are replicated identically on every row (held constant by transition +//! constraints and pinned to the final reduction on the last row), so every row re-proves the +//! shared derivation — exactly the structure of [`crate::circuit::fp16::noise_stark`]. +//! +//! All ties-to-even roundings are proved with quarter-ulp *bracket* gadgets (the parity split plus +//! the binade-bottom `IS_BOTTOM` correction where the binade is asymmetric), reusing only the +//! FP16-batch committed LUTs (`FP16DECODE`, `RANGE16`, `FP16POW2`, `WIDTH32`) — no new table and no +//! grinding slack. See `stark.rs` for the constraint groups and the documented soundness envelope. +//! +//! [`RowScaleColumnsView`] is `#[repr(C)]`; declaration order is committed column order. + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one RowScaleStark trace row. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct RowScaleColumnsView { + // ============================================================================================== + // Class (a) ("known") columns: pure functions of the geometry `(num_operand_rows, k)`. Must come + // first. The extended AIR lays `num_operand_rows` k-element blocks end to end (A rows then B + // rows), each block a self-contained row-norm + scale derivation, followed by trailing padding. + // ============================================================================================== + /// 1 on the trailing padding rows (the `num_operand_rows * k` live rows padded up to the trace + /// height). + pub is_pad: T, + /// The operand-row index this trace row belongs to (`floor(row / k)` on live rows; the scales + /// channel's key, keeping A rows `0..h` and B rows `h..h+w` in one disjoint space). Held at the + /// final live block index on padding rows (filtered out of every CTL anyway). + pub operand_row_index: T, + /// 1 on the first row of each k-element block — the live blocks (`row % k == 0`) and the first + /// padding row. Gates the per-block sum-of-squares / running-max reset and the scalar jumps. + pub is_block_start: T, + /// 1 on the last row of each LIVE k-element block (`row % k == k-1`, live). Pins `sumsq` / + /// `max_abs_code` to that block's finished reduction. Padding carries 0 (no scales emitted). + pub is_block_final: T, + + // ============================================================================================== + // Per-element decode (FP16DECODE) + running max |x| (group D / M). + // ============================================================================================== + /// The raw FP16 operand code `x_i` (witness input; CTL-bound to the operand commitment later). + pub code: T, + /// Integer significand of `code` (`0`, `1..=1023` subnormal, `1024..=2047` normal) — FP16DECODE. + pub x_sig: T, + /// Sign bit of `code` (bit 15) — FP16DECODE. + pub x_sign: T, + /// `stored_exponent + 15 >= 0` — FP16DECODE. + pub x_eps_biased: T, + /// `[x_sig == 0]` — FP16DECODE. + pub x_is_zero: T, + /// `code & 0x7FFF` (the magnitude code; value-ordered on nonnegative FP16). + pub abs_code: T, + /// Running max of `ABS_CODE` through this row (= max magnitude code so far). + pub run_max: T, + /// `[ABS_CODE >= prev RUN_MAX]` (boolean; the max compare-select). + pub max_ge: T, + /// Two-sided slack of the max compare (`MAX_GE ? ABS_CODE-prev : prev-ABS_CODE-1`). + pub max_slack: T, + + // ============================================================================================== + // Per-element square `sq = x_i^2` normalized to a 24-bit significand (group Q). + // ============================================================================================== + /// Exact product significand `SQ_SIG = X_SIG^2` (`< 2^22`). + pub sq_sig: T, + /// Bit-width of `SQ_SIG` (`0` when zero; WIDTH32 key on nonzero-square rows). + pub sq_w: T, + /// `2^(24 - SQ_W)` (WIDTH32 value; lifts `SQ_SIG` to a 24-bit significand). + pub sq_lift: T, + /// `SQ_NORM = SQ_SIG * SQ_LIFT in [2^23, 2^24)` (0 on zero-square rows). + pub sq_norm: T, + pub sq_norm_lo: T, + pub sq_norm_hi: T, + + // ============================================================================================== + // Accumulation fold `acc_out = RNE_f32(acc_in + sq)` (both nonnegative) (group A). + // `acc_in`/`acc_out` carry an f32 as `(SIG in [2^23,2^24) or 0, EXP biased, ZERO)`. + // ============================================================================================== + /// Running sum significand BEFORE adding this element (24-bit or 0). + pub acc_in_sig: T, + pub acc_in_sig_lo: T, + pub acc_in_sig_hi: T, + /// Biased f32 exponent of `acc_in` (0 when zero). + pub acc_in_exp: T, + /// `[acc_in == 0]`. + pub acc_in_zero: T, + + /// Biased value-MSB of the `sq` term (0 when `sq` is zero). + pub sq_msb: T, + /// Biased value-MSB of the `acc_in` term (0 when zero). + pub acc_msb: T, + /// Window anchor `eta = max(sq_msb, acc_msb)` over nonzero terms. + pub eta: T, + /// `eta - sq_msb` (0 if `sq` zero). + pub rel_sq: T, + /// `eta - acc_msb` (0 if `acc_in` zero). + pub rel_acc: T, + pub far_sq: T, + pub far_sq_slack: T, + pub far_acc: T, + pub far_acc_slack: T, + pub active_sq: T, + pub active_acc: T, + /// `2^rel_sq` (FP16POW2) on active rows. + pub pow_sq: T, + pub aligned_sq: T, + pub aligned_sq_lo: T, + pub aligned_sq_hi: T, + pub rem_sq: T, + pub rem_sq_lo: T, + pub rem_sq_hi: T, + pub rem_sq_bound: T, + pub rem_sq_bound_lo: T, + pub rem_sq_bound_hi: T, + /// `2^rel_acc` (FP16POW2) on active rows. + pub pow_acc: T, + pub aligned_acc: T, + pub aligned_acc_lo: T, + pub aligned_acc_hi: T, + pub rem_acc: T, + pub rem_acc_lo: T, + pub rem_acc_hi: T, + pub rem_acc_bound: T, + pub rem_acc_bound_lo: T, + pub rem_acc_bound_hi: T, + pub rem_sq_nz: T, + pub rem_sq_nz_inv: T, + pub rem_acc_nz: T, + pub rem_acc_nz_inv: T, + pub or_sq: T, + pub or_acc: T, + pub sticky_sq: T, + pub sticky_acc: T, + pub far_sticky: T, + /// Nonnegative window sum `|W| = aligned_sq + aligned_acc` (`< 2^29`). + pub w_abs: T, + pub w_abs_lo: T, + pub w_abs_hi: T, + pub w_is_zero: T, + pub w_abs_inv: T, + /// Bit-width of `|W|` (WIDTH32 key). + pub ww: T, + pub trunc_w: T, + pub lift_w: T, + pub m_rz: T, + pub m_rz_lo: T, + pub m_rz_hi: T, + pub rz_rem: T, + pub rz_rem_bound: T, + pub rz_parity: T, + pub rz_half: T, + pub gt: T, + pub gt_slack: T, + pub eq: T, + pub eq_inv: T, + pub or_rs: T, + pub round_up: T, + pub carry: T, + pub carry_inv: T, + /// `acc_out` significand (24-bit or 0) — next row's `acc_in`. + pub acc_out_sig: T, + pub acc_out_sig_lo: T, + pub acc_out_sig_hi: T, + pub acc_out_exp: T, + pub acc_out_zero: T, + + // ============================================================================================== + // ENTRY-LIVENESS gate (whitepaper "Shared checks"). Per element, `dead = [|x_iu| >= 4*l2_i]`; + // the per-side dead counts are then gated `64 * dead_side <= rows_side * k` (eps_idle = 1/64). + // These are PER-ELEMENT / per-row (they vary within a block), so they live BEFORE the scalar + // region (the scalar-constancy transition pins everything from `sumsq_sig` on). All class (b) + // (witness) -- NO new known column, so the wrapper PI layout and the native header-bound + // verifier are untouched. See `stark.rs` group L for the constraints. + // ============================================================================================== + /// 1 iff this element is dead: `|x| >= 4*l2` (the block's floored `l2`). `0` on padding/zero `x`. + pub dead: T, + /// 1 iff `s = (x_eps_biased - 25) - (l2_e - 132) >= 0` (the aligned-compare direction). Pins + /// `dead_key = |s|` via `dead_key = s * (2*dead_sign - 1)` (FP16POW2 bounds `dead_key` to its + /// nonneg key domain, which pins the sign). + pub dead_sign: T, + /// `|s|` -- the FP16POW2 alignment key (shift between `|x|`'s and `4*l2`'s integer significands). + pub dead_key: T, + /// `2^min(dead_key, 26)` (FP16POW2 value). Saturation at 2^26 is sound: beyond the active + /// window the larger side already dominates, so the comparison outcome never flips. + pub dead_pow: T, + /// Alignment power applied to the `|x|` side: `dead_sign ? dead_pow : 1` (the `4*l2` side gets + /// `dead_pow + 1 - dead_pow_a`). + pub dead_pow_a: T, + /// `x_sig * dead_pow_a` (the `|x|` side of the aligned integer compare). + pub dead_lhs: T, + /// `(128 + l2_m) * dead_pow_b` (the `4*l2` side). + pub dead_rhs: T, + /// Nonnegative two-sided slack `dead ? (lhs - rhs) : (rhs - lhs - 1)`, `< 2^37`, as 16/16/5-bit + /// limbs (RANGE16): `dead_slack = lo + 2^16*mid + 2^32*hi`. + pub dead_slack_lo: T, + pub dead_slack_mid: T, + pub dead_slack_hi: T, + /// 1 iff this trace row belongs to the B operand (`operand_row_index >= num_a_rows`). Masks the + /// per-side dead accumulators. Pinned two-sided by `b_side_slack` (RANGE16). + pub is_b_side: T, + pub b_side_slack: T, + /// Inclusive running count of dead A-side elements (`sum over live A rows of dead`); frozen on + /// B/padding rows, so it holds the A-side total on the last row. + pub dead_run_a: T, + /// Inclusive running count of dead B-side elements; holds the B-side total on the last row. + pub dead_run_b: T, + /// Low/high limbs of the A gate slack `a_gate = num_a_rows*k - 64*dead_run_a >= 0` (last row). + pub a_gate_slack_lo: T, + pub a_gate_slack_hi: T, + /// Low/high limbs of the B gate slack `b_gate = num_b_rows*k - 64*dead_run_b >= 0` (last row). + pub b_gate_slack_lo: T, + pub b_gate_slack_hi: T, + + // ============================================================================================== + // SCALAR columns (replicated on every row; held constant; pinned to the last row). + // ============================================================================================== + /// `sumsq` significand (= `acc_out` of the last live row). + pub sumsq_sig: T, + pub sumsq_sig_lo: T, + pub sumsq_sig_hi: T, + pub sumsq_exp: T, + pub sumsq_zero: T, + /// Max magnitude code (= `run_max` of the last live row). + pub max_abs_code: T, + + // ---- q = RNE_f32(sumsq / k) (group V) ---- + pub q_sig: T, + pub q_sig_lo: T, + pub q_sig_hi: T, + pub q_exp: T, + pub q_zero: T, + pub q_bottom: T, + pub q_bottom_inv: T, + pub q_parity: T, + pub q_half: T, + /// `2^Dq` alignment power for the division bracket (FP16POW2). + pub q_pow: T, + pub q_dexp: T, + pub q_blo: T, + pub q_bhi: T, + pub q_sl_lo: T, + pub q_sl_mid: T, + pub q_sl_hi: T, + pub q_su_lo: T, + pub q_su_mid: T, + pub q_su_hi: T, + + // ---- s = RNE_f32(sqrt(q)) (group S) ---- + pub s_sig: T, + pub s_sig_lo: T, + pub s_sig_hi: T, + pub s_exp: T, + pub s_bottom: T, + pub s_bottom_inv: T, + pub s_parity: T, + pub s_half: T, + /// `2^Ds` alignment power for the sqrt bracket (FP16POW2). + pub s_pow: T, + pub s_dexp: T, + /// Squared lower/upper quarter-ulp boundaries (`~ 2^52`). + pub s_blo: T, + pub s_bhi: T, + pub s_sl_lo: T, + pub s_sl_mid: T, + pub s_sl_hi: T, + pub s_su_lo: T, + pub s_su_mid: T, + pub s_su_hi: T, + + // ---- l2raw = f32_to_bf16(s) (round 24-bit -> 8-bit, shift 16) (group C) ---- + pub l2raw_mant: T, + pub l2raw_exp: T, + pub l2raw_carry: T, + pub l2raw_bottom: T, + pub l2raw_bottom_inv: T, + pub l2raw_parity: T, + pub l2raw_half: T, + pub l2raw_blo: T, + pub l2raw_bhi: T, + pub l2raw_sl_lo: T, + pub l2raw_sl_hi: T, + pub l2raw_su_lo: T, + pub l2raw_su_hi: T, + /// `l2raw` bf16 code (`l2raw_exp<<7 | l2raw_mant`); `0` iff `sumsq == 0`. + pub l2raw_code: T, + + // ---- l2grid = round_l2_to_grid(l2raw) (clear low 2 mantissa bits, ties up) (group G) ---- + /// `(l2raw_code + 2) >> 2` (the kept high bits). + pub grid_q: T, + /// `l2raw_code + 2 - 4*grid_q in {0,1,2,3}` (the cleared low bits + half). + pub grid_r: T, + pub grid_r_b0: T, + pub grid_r_b1: T, + /// `l2grid` bf16 code (`4 * grid_q`). + pub l2grid_code: T, + + // ---- l2 = bf16_max(l2grid, floor) (group F) ---- + pub l2_ge: T, + pub l2_floor_slack: T, + pub l2_code: T, + /// Exponent/mantissa fields of the floored `l2_code` (`l2_code = 128*l2_e + l2_m`). + pub l2_e: T, + pub l2_m: T, + + // ============================================================================================== + // linf = bf16_max(f32_to_bf16(max|x|), floor). + // ============================================================================================== + /// FP16DECODE of `MAX_ABS_CODE` (`max_sign` is always 0 — the magnitude code). + pub max_sig: T, + pub max_sign: T, + pub max_eps_biased: T, + pub max_is_zero: T, + /// Bit-width of `MAX_SIG` (WIDTH32 key; nonzero-max rows). + pub max_w: T, + pub max_lift: T, + /// `MAX_SIG * MAX_LIFT in [2^23, 2^24)` (24-bit significand of `max|x|`). + pub max_norm: T, + pub max_norm_lo: T, + pub max_norm_hi: T, + /// Round of `max_norm` (24-bit) to the 8-bit bf16 significand (shift 16). + pub linf_raw_mant: T, + pub linf_raw_exp: T, + pub linf_raw_carry: T, + pub linf_raw_bottom: T, + pub linf_raw_bottom_inv: T, + pub linf_raw_parity: T, + pub linf_raw_half: T, + pub linf_raw_blo: T, + pub linf_raw_bhi: T, + pub linf_raw_sl_lo: T, + pub linf_raw_sl_hi: T, + pub linf_raw_su_lo: T, + pub linf_raw_su_hi: T, + /// `linf_raw` bf16 code (normal when `max|x| != 0`). + pub linf_raw_code: T, + pub linf_ge: T, + pub linf_floor_slack: T, + pub linf_code: T, + /// Exponent/mantissa fields of the floored `linf_code` (`linf_code = 128*linf_e + linf_m`). + pub linf_e: T, + pub linf_m: T, + + // ============================================================================================== + // noised_bound = bf16_fma(dr, l2, linf) (dr a compile-time constant; all operands nonneg) (H1). + // Because `linf >= l2 ~ dr*l2` (max >= rms), the product `dr*l2` is the finer term: its LSB sits + // `nb_shift` bits below `linf`'s, so `W = dr.M*l2.M + linf.M * 2^nb_shift` is the EXACT sum of + // the two operands (no lost bits, no sticky). `W` is then rounded once to the 8-bit significand. + // ============================================================================================== + /// Exact product significand `dr.M * l2.M` (`< 2^16`). + pub nb_prod: T, + /// `nb_shift = E(linf) - E(l2) + 6 >= 0` (FP16POW2 key); aligns `linf` onto the product grid. + pub nb_shift: T, + /// `2^nb_shift` (FP16POW2 value). + pub nb_shiftpow: T, + /// Exact window sum `W = nb_prod + linf.M * nb_shiftpow`. + pub nb_w: T, + pub nb_w_lo: T, + pub nb_w_hi: T, + /// Rounding shift `nb_gm = bitlen(W) - 8` (FP16POW2 key; pinned by `nb_mant in [0,127]`). + pub nb_gm: T, + pub nb_pow: T, + pub nb_mant: T, + pub nb_exp: T, + pub nb_bottom: T, + pub nb_bottom_inv: T, + pub nb_parity: T, + pub nb_half: T, + pub nb_blo: T, + pub nb_bhi: T, + pub nb_sl_lo: T, + pub nb_sl_hi: T, + pub nb_su_lo: T, + pub nb_su_hi: T, + /// `noised_bound` bf16 code. + pub nb_code: T, + + // ============================================================================================== + // alpha = bf16_div(MAX_FP16_bf16, noised_bound); MAX_FP16_bf16 = 2^16 (power of two) (H3). + // Single power-of-two division bracket (mirrors noise_stark's `scale`). + // ============================================================================================== + pub alpha_exp: T, + pub alpha_mant: T, + pub alpha_bottom: T, + pub alpha_bottom_inv: T, + pub alpha_parity: T, + pub alpha_half: T, + /// `2^A` division power (FP16POW2); `A = DIV_KEY_BASE - nb_exp - alpha_exp`. + pub alpha_pow: T, + pub alpha_blo: T, + pub alpha_bhi: T, + pub alpha_sl: T, + pub alpha_su: T, + pub alpha_code: T, + + // ============================================================================================== + // m1 = bf16_mul(alpha, l2); beta = bf16_mul(m1, dos) (H4/H5). Two bf16 RNE multiplies. + // ============================================================================================== + pub m1_prod: T, + pub m1_mant: T, + pub m1_exp: T, + pub m1_bottom: T, + pub m1_bottom_inv: T, + pub m1_parity: T, + pub m1_half: T, + pub m1_pow: T, + pub m1_gm: T, + pub m1_blo: T, + pub m1_bhi: T, + pub m1_sl: T, + pub m1_su: T, + pub m1_code: T, + + pub beta_prod: T, + pub beta_mant: T, + pub beta_exp: T, + pub beta_bottom: T, + pub beta_bottom_inv: T, + pub beta_parity: T, + pub beta_half: T, + pub beta_pow: T, + pub beta_gm: T, + pub beta_blo: T, + pub beta_bhi: T, + pub beta_sl: T, + pub beta_su: T, + pub beta_code: T, +} + +/// Total number of committed RowScaleStark columns. +pub const NUM_ROW_SCALE_COLUMNS: usize = size_of::>(); + +/// RowScaleStark has no public inputs: the geometry enters through the known columns (`IS_PAD`, +/// `OPERAND_ROW_INDEX`, `IS_BLOCK_START`, `IS_BLOCK_FINAL`), the trace height, and the compile-time +/// constants baked into the AIR. +pub const NUM_ROW_SCALE_PUBLIC_INPUTS: usize = 0; + +columns_view!(RowScaleColumnsView, NUM_ROW_SCALE_COLUMNS, ROW_SCALE_COL_MAP); + +/// Number of leading class (a) ("known") columns: `IS_PAD`, `OPERAND_ROW_INDEX`, `IS_BLOCK_START`, +/// `IS_BLOCK_FINAL`. +pub const NUM_ROW_SCALE_KNOWN_COLUMNS: usize = ROW_SCALE_COL_MAP.is_block_final + 1; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_ROW_SCALE_COLUMNS] = ROW_SCALE_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + assert_eq!(ROW_SCALE_COL_MAP.is_pad, 0); + assert_eq!(ROW_SCALE_COL_MAP.operand_row_index, 1); + assert_eq!(ROW_SCALE_COL_MAP.is_block_start, 2); + assert_eq!(ROW_SCALE_COL_MAP.is_block_final, 3); + assert_eq!(NUM_ROW_SCALE_KNOWN_COLUMNS, 4); + assert_eq!(ROW_SCALE_COL_MAP.beta_code, NUM_ROW_SCALE_COLUMNS - 1); + // The entry-liveness columns are per-element: they must precede the scalar region + // (`sumsq_sig`..), which the scalar-constancy transition pins constant within a block. + assert!(ROW_SCALE_COL_MAP.dead < ROW_SCALE_COL_MAP.sumsq_sig); + assert!(ROW_SCALE_COL_MAP.b_gate_slack_hi < ROW_SCALE_COL_MAP.sumsq_sig); + } +} diff --git a/zk-pow/src/circuit/fp16/row_scale_stark/ctl.rs b/zk-pow/src/circuit/fp16/row_scale_stark/ctl.rs new file mode 100644 index 000000000..cb225e7e8 --- /dev/null +++ b/zk-pow/src/circuit/fp16/row_scale_stark/ctl.rs @@ -0,0 +1,322 @@ +//! Cross-table-lookup declarations for the FP16 RowScaleStark. +//! +//! Two kinds of channel: +//! +//! * **Parameterized hooks** — this AIR proves the per-row norm + scale arithmetic from the raw +//! FP16 operand codes (witness inputs). Binding those codes to the operand commitment and the +//! `(alpha, beta)` outputs to `noisy_quant_stark` is left to later batch integration, so each +//! builder takes the counterparty table's batch index explicitly, exactly like +//! [`crate::circuit::fp16::noisy_quant_stark::ctl`] and [`crate::circuit::fp16::noise_stark::ctl`] +//! (RowScaleStark is not registered in [`crate::circuit::fp16::ctl`]). +//! * The committed-LUT inventory ([`row_scale_lut_lookups`]): the `FP16DECODE` operand decodes, the +//! `WIDTH32` 24-bit normalizations, the `FP16POW2` alignment/rounding shifts, and the `RANGE16` +//! limb/slack range checks that make every ties-to-even bracket sound. No new table is introduced — +//! every fact targets the shared `FP16DECODE`/`RANGE16`/`FP16POW2`/`WIDTH32` tables of the FP16 batch. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::ROW_SCALE_COL_MAP; +use crate::circuit::fp8::luts::LutTable; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// The live-row filter `1 - IS_PAD`. +fn live_filter() -> Filter { + Filter::from_column(Column::linear_combination_with_constant([(ROW_SCALE_COL_MAP.is_pad, -F::ONE)], F::ONE)) +} + +/// `(1 - IS_PAD) * (1 - flag_col)` as a product filter. +fn live_and_not(flag_col: usize) -> Filter { + Filter::new( + vec![( + Column::linear_combination_with_constant([(ROW_SCALE_COL_MAP.is_pad, -F::ONE)], F::ONE), + Column::linear_combination_with_constant([(flag_col, -F::ONE)], F::ONE), + )], + vec![], + ) +} + +/// Hook: the clean FP16 operand code `CODE`, filter `1 - IS_PAD`. Counterparty: the operand +/// commitment (index supplied at integration time). +pub fn ctl_operand_looking(table: usize) -> TableWithColumns { + TableWithColumns::new(TableIdx::from(table), vec![Column::single(ROW_SCALE_COL_MAP.code)], live_filter()) +} + +/// Hook: the per-row `(L2_CODE, LINF_CODE, ALPHA_CODE, BETA_CODE)` outputs (scalar columns, +/// identical on every row). The counterparty (`noisy_quant_stark` for alpha/beta) is wired at batch +/// integration. Filter `1 - IS_PAD`. +pub fn ctl_scales_looking(table: usize) -> TableWithColumns { + let m = &ROW_SCALE_COL_MAP; + TableWithColumns::new( + TableIdx::from(table), + Column::singles([m.l2_code, m.linf_code, m.alpha_code, m.beta_code]).collect(), + live_filter(), + ) +} + +/// RowScaleStark's per-row committed-LUT inventory (FP16DECODE + WIDTH32 + FP16POW2 + RANGE16). +pub fn row_scale_lut_lookups() -> Vec> { + let m = &ROW_SCALE_COL_MAP; + let live = live_filter::(); + let nz_sq = live_and_not::(m.x_is_zero); + let nz_w = live_and_not::(m.w_is_zero); + let nz_q = live_and_not::(m.q_zero); + let nz_sumsq = live_and_not::(m.sumsq_zero); + let nz_max = live_and_not::(m.max_is_zero); + let one_c = Column::constant(F::ONE); + let mut lu: Vec> = Vec::new(); + + let rc = LutLookup::rc16; + let scaled = |col: usize, sh: u64| Column::linear_combination([(col, F::from_canonical_u64(1 << sh))]); + // `(hi - 128) * 2^8` — pins a 24-bit significand's high limb into `[128, 256)`. + let hi_norm = |col: usize| { + Column::linear_combination_with_constant([(col, F::from_canonical_u64(1 << 8))], -F::from_canonical_u64(128 << 8)) + }; + + // ---- FP16DECODE. ---- + lu.push(LutLookup { + table: LutTable::Fp16Decode, + keys: vec![Column::single(m.code)], + values: Column::singles([m.x_sig, m.x_sign, m.x_eps_biased, m.x_is_zero]).collect(), + filter: live.clone(), + }); + lu.push(LutLookup { + table: LutTable::Fp16Decode, + keys: vec![Column::single(m.max_abs_code)], + values: Column::singles([m.max_sig, m.max_sign, m.max_eps_biased, m.max_is_zero]).collect(), + filter: live.clone(), + }); + + // ---- WIDTH32: 24-bit normalizations (trunc is always 1 since each width <= 23). ---- + lu.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.sq_w)], + values: vec![one_c.clone(), Column::single(m.sq_lift)], + filter: nz_sq.clone(), + }); + lu.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.ww)], + values: Column::singles([m.trunc_w, m.lift_w]).collect(), + filter: nz_w.clone(), + }); + lu.push(LutLookup { + table: LutTable::Width32, + keys: vec![Column::single(m.max_w)], + values: vec![one_c.clone(), Column::single(m.max_lift)], + filter: nz_max.clone(), + }); + + // ---- FP16POW2: alignment + rounding shifts. ---- + let pow = |key: Column, val: usize, filter: Filter| LutLookup { + table: LutTable::Fp16Pow2, + keys: vec![key], + values: vec![Column::single(val)], + filter, + }; + lu.push(pow(Column::single(m.rel_sq), m.pow_sq, Filter::from_column(Column::single(m.active_sq)))); + lu.push(pow(Column::single(m.rel_acc), m.pow_acc, Filter::from_column(Column::single(m.active_acc)))); + lu.push(pow(Column::single(m.q_dexp), m.q_pow, nz_q.clone())); + lu.push(pow(Column::single(m.s_dexp), m.s_pow, nz_q.clone())); + lu.push(pow(Column::single(m.nb_shift), m.nb_shiftpow, live.clone())); + lu.push(pow(Column::single(m.nb_gm), m.nb_pow, live.clone())); + // alpha: key A = 286 - nb_exp - alpha_exp. + lu.push(pow( + Column::linear_combination_with_constant( + [(m.nb_exp, -F::ONE), (m.alpha_exp, -F::ONE)], + F::from_canonical_u64(super::stark::DIV_KEY_BASE), + ), + m.alpha_pow, + live.clone(), + )); + lu.push(pow(Column::single(m.m1_gm), m.m1_pow, live.clone())); + lu.push(pow(Column::single(m.beta_gm), m.beta_pow, live.clone())); + + // ---- RANGE16: per-element. ---- + lu.push(rc(Column::single(m.max_slack))); + lu.push(rc(Column::single(m.sq_norm_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.sq_norm_hi), nz_sq.clone())); + lu.push(rc(Column::single(m.rel_sq))); + lu.push(rc(Column::single(m.rel_acc))); + lu.push(rc(Column::single(m.far_sq_slack))); + lu.push(rc(Column::single(m.far_acc_slack))); + lu.push(rc(Column::single(m.aligned_sq_lo))); + lu.push(rc(scaled(m.aligned_sq_hi, 5))); + lu.push(rc(Column::single(m.aligned_acc_lo))); + lu.push(rc(scaled(m.aligned_acc_hi, 5))); + for (lo, hi) in [ + (m.rem_sq_lo, m.rem_sq_hi), + (m.rem_sq_bound_lo, m.rem_sq_bound_hi), + (m.rem_acc_lo, m.rem_acc_hi), + (m.rem_acc_bound_lo, m.rem_acc_bound_hi), + ] { + lu.push(rc(Column::single(lo))); + lu.push(rc(scaled(hi, 6))); + } + lu.push(rc(Column::single(m.w_abs_lo))); + lu.push(rc(scaled(m.w_abs_hi, 4))); + lu.push(rc(Column::single(m.m_rz_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.m_rz_hi), nz_w.clone())); + lu.push(rc(Column::single(m.rz_rem))); + lu.push(rc(Column::single(m.rz_rem_bound))); + lu.push(rc(Column::single(m.rz_half))); + lu.push(rc(Column::single(m.gt_slack))); + + // ---- RANGE16: scalars (sumsq / q / s). ---- + lu.push(rc(Column::single(m.sumsq_sig_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.sumsq_sig_hi), nz_sumsq.clone())); + lu.push(rc(Column::single(m.q_sig_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.q_sig_hi), nz_q.clone())); + lu.push(rc(Column::single(m.q_half))); + for c in [m.q_sl_lo, m.q_sl_mid, m.q_sl_hi, m.q_su_lo, m.q_su_mid, m.q_su_hi] { + lu.push(rc(Column::single(c))); + } + lu.push(rc(Column::single(m.s_sig_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.s_sig_hi), nz_q.clone())); + lu.push(rc(Column::single(m.s_half))); + for c in [m.s_sl_lo, m.s_sl_mid, m.s_sl_hi, m.s_su_lo, m.s_su_mid, m.s_su_hi] { + lu.push(rc(Column::single(c))); + } + + // ---- RANGE16: l2raw / grid / l2 floor. ---- + lu.push(rc(scaled(m.l2raw_mant, 9))); + lu.push(rc(Column::single(m.l2raw_half))); + for c in [m.l2raw_sl_lo, m.l2raw_sl_hi, m.l2raw_su_lo, m.l2raw_su_hi] { + lu.push(rc(Column::single(c))); + } + lu.push(rc(Column::single(m.grid_q))); + lu.push(rc(Column::single(m.l2_floor_slack))); + lu.push(rc(scaled(m.l2_e, 8))); + lu.push(rc(scaled(m.l2_m, 9))); + + // ---- RANGE16: linf. ---- + lu.push(rc(Column::single(m.max_norm_lo))); + lu.push(LutLookup::rc16_filtered(hi_norm(m.max_norm_hi), nz_max.clone())); + lu.push(rc(scaled(m.linf_raw_mant, 9))); + lu.push(rc(Column::single(m.linf_raw_half))); + for c in [m.linf_raw_sl_lo, m.linf_raw_sl_hi, m.linf_raw_su_lo, m.linf_raw_su_hi] { + lu.push(rc(Column::single(c))); + } + lu.push(rc(Column::single(m.linf_floor_slack))); + lu.push(rc(scaled(m.linf_e, 8))); + lu.push(rc(scaled(m.linf_m, 9))); + + // ---- RANGE16: noised_bound / alpha / m1 / beta. ---- + lu.push(rc(Column::single(m.nb_w_lo))); + lu.push(rc(Column::single(m.nb_w_hi))); + lu.push(rc(scaled(m.nb_mant, 9))); + lu.push(rc(Column::single(m.nb_half))); + for c in [m.nb_sl_lo, m.nb_sl_hi, m.nb_su_lo, m.nb_su_hi] { + lu.push(rc(Column::single(c))); + } + lu.push(rc(scaled(m.alpha_mant, 9))); + lu.push(rc(scaled(m.alpha_exp, 8))); + lu.push(rc(Column::single(m.alpha_half))); + lu.push(rc(Column::single(m.alpha_sl))); + lu.push(rc(Column::single(m.alpha_su))); + lu.push(rc(scaled(m.m1_mant, 9))); + lu.push(rc(Column::single(m.m1_half))); + lu.push(rc(Column::single(m.m1_sl))); + lu.push(rc(Column::single(m.m1_su))); + lu.push(rc(scaled(m.beta_mant, 9))); + lu.push(rc(Column::single(m.beta_half))); + lu.push(rc(Column::single(m.beta_sl))); + lu.push(rc(Column::single(m.beta_su))); + + // ---- Entry-liveness gate (group L). ---- + // FP16POW2: the aligned-compare shift `dead_key -> dead_pow = 2^min(dead_key,26)` (live rows; + // membership also bounds `dead_key` to the nonneg key domain, pinning `dead_sign`). + lu.push(pow(Column::single(m.dead_key), m.dead_pow, live.clone())); + // RANGE16: the two-sided compare slack (3 limbs, `< 2^37`) and the side-mask pin slack, live. + lu.push(LutLookup::rc16_filtered(Column::single(m.dead_slack_lo), live.clone())); + lu.push(LutLookup::rc16_filtered(Column::single(m.dead_slack_mid), live.clone())); + lu.push(LutLookup::rc16_filtered(scaled(m.dead_slack_hi, 11), live.clone())); + lu.push(LutLookup::rc16_filtered(Column::single(m.b_side_slack), live.clone())); + // RANGE16: the per-side gate slacks (meaningful on the last row, zero elsewhere; `< 2^23`). + lu.push(rc(Column::single(m.a_gate_slack_lo))); + lu.push(rc(scaled(m.a_gate_slack_hi, 9))); + lu.push(rc(Column::single(m.b_gate_slack_lo))); + lu.push(rc(scaled(m.b_gate_slack_hi, 9))); + + lu +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::PrimeField64; + use starky::util::trace_rows_to_poly_values; + + use super::super::stark::RowScaleProgram; + use super::*; + + type F = GoldilocksField; + + #[test] + fn ctl_halves_are_well_formed() { + ctl_operand_looking::(3); + ctl_scales_looking::(3); + let _ = row_scale_lut_lookups::(); + } + + #[test] + fn lut_inventory_counts() { + let lu = row_scale_lut_lookups::(); + let count = |t: LutTable| lu.iter().filter(|l| l.table == t).count(); + assert_eq!(count(LutTable::Fp16Decode), 2); + assert_eq!(count(LutTable::Width32), 3); + assert_eq!(count(LutTable::Fp16Pow2), 10); // +1: the liveness aligned-compare shift + assert_eq!(count(LutTable::Range16), lu.len() - 15); + } + + /// Every committed-LUT key the honest trace presents lands in its table's domain (RANGE16 keys + /// `< 2^16`, FP16DECODE keys `< 2^16`, FP16POW2 keys `<= 255` with `value = 2^min(key, 26)`, + /// WIDTH32 keys in `[1, 32]`). Checked on the live rows (filtered lookups are inactive elsewhere). + #[test] + fn honest_lut_keys_are_in_domain() { + use crate::api::fp16::dtype::f32_to_fp16; + for (k, seed, scale) in [(64usize, 1u64, 4.0f32), (48, 7, 0.5), (96, 11, 20.0), (32, 3, 1.0)] { + let program = RowScaleProgram::new(k, 32); + let mut s = seed.wrapping_add(0x9E3779B97F4A7C15); + let row: Vec = (0..k) + .map(|_| { + s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + f32_to_fp16(((s >> 40) as i32 % 2000 - 1000) as f32 / 1000.0 * scale).unwrap() + }) + .collect(); + let rows = program.generate_trace::(&row); + let polys = trace_rows_to_poly_values(rows); + let lu = row_scale_lut_lookups::(); + for (li, lookup) in lu.iter().enumerate() { + for r in 0..k { + let active = lookup.filter.eval_table(&polys, r, &[]).to_canonical_u64(); + if active == 0 { + continue; + } + match lookup.table { + LutTable::Range16 => { + let key = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(key < 1 << 16, "RANGE16 lookup {li} key {key} out of range at row {r}"); + } + LutTable::Fp16Decode => { + let key = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(key < 1 << 16, "FP16DECODE lookup {li} key {key} at row {r}"); + } + LutTable::Fp16Pow2 => { + let key = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + let val = lookup.values[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!(key <= 255, "FP16POW2 lookup {li} key {key} at row {r}"); + assert_eq!(val, 1 << key.min(26), "FP16POW2 lookup {li} value {val} != 2^min({key},26) at row {r}"); + } + LutTable::Width32 => { + let key = lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64(); + assert!((1..=32).contains(&key), "WIDTH32 lookup {li} key {key} at row {r}"); + } + other => panic!("unexpected table {other:?}"), + } + } + } + } + } +} diff --git a/zk-pow/src/circuit/fp16/row_scale_stark/mod.rs b/zk-pow/src/circuit/fp16/row_scale_stark/mod.rs new file mode 100644 index 000000000..916f56590 --- /dev/null +++ b/zk-pow/src/circuit/fp16/row_scale_stark/mod.rs @@ -0,0 +1,34 @@ +//! FP16 per-row scale-derivation AIR: proves, in-AIR, the per-row norm + scale arithmetic of the +//! plaintext ground truth [`crate::api::fp16::quantization`]'s `row_norms` + `derive_row_scales` +//! for one operand row of `k` FP16 values: +//! +//! ```text +//! sumsq = Σ (fp16_to_f32(x))^2 // sequential f32 RNE sum of squares +//! l2 = round_l2_to_grid(f32_to_bf16(sqrt(sumsq/k))) +//! linf = f32_to_bf16(max|x|) +//! l2 = bf16_max(l2, floor); linf = bf16_max(linf, floor) // floor = f32_to_bf16(2^-32) +//! noised_bound = bf16_fma(dr, l2, linf) // dr = f32_to_bf16(DELTA*sqrt(r)) +//! alpha = bf16_div(MAX_FP16_bf16, noised_bound) // MAX_FP16_bf16 = 0x4780 = 2^16 +//! beta = bf16_mul(bf16_mul(alpha, l2), dos) // dos = f32_to_bf16(DELTA*sqrt(r)/N^2) +//! ``` +//! +//! `r` is the fixed noise rank 32, so `dr` and `dos` are compile-time constants (asserted in +//! [`stark::RowScaleProgram::new`], mirroring [`crate::circuit::fp16::noise_stark`]'s fixed +//! numerator). The output columns `l2`, `linf`, `alpha`, `beta` (bf16 codes) bind to +//! `noisy_quant_stark` (alpha/beta) and to the operand commitment (raw row codes) via the +//! parameterized CTL hooks in [`ctl`]; this module does NOT wire the batch (it is not registered in +//! [`crate::circuit::fp16::ctl`]), exactly like the other FP16 sub-STARKs built so far. +//! +//! All BF16/f32 roundings are proved with ties-to-even quarter-ulp *bracket* gadgets over the +//! shared FP16-batch LUTs (`FP16DECODE`, `RANGE16`, `FP16POW2`, `WIDTH32`) — no new table and no +//! grinding slack. See [`stark`] for the constraint groups and the documented soundness envelope. + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{ + NUM_ROW_SCALE_COLUMNS, NUM_ROW_SCALE_KNOWN_COLUMNS, NUM_ROW_SCALE_PUBLIC_INPUTS, ROW_SCALE_COL_MAP, + RowScaleColumnsView, +}; +pub use stark::{RowScaleProgram, RowScaleStark}; diff --git a/zk-pow/src/circuit/fp16/row_scale_stark/stark.rs b/zk-pow/src/circuit/fp16/row_scale_stark/stark.rs new file mode 100644 index 000000000..3f8ddedbc --- /dev/null +++ b/zk-pow/src/circuit/fp16/row_scale_stark/stark.rs @@ -0,0 +1,2292 @@ +//! Proves the FP16 per-row norm + scale derivation (see [`super`] module docs). +//! +//! # Constraint groups (see the per-group comments in [`eval_row_scale_constraints`]) +//! +//! * **D / M** — per-element FP16 decode (FP16DECODE) and the running maximum magnitude code. +//! * **Q** — the exact integer square `SQ_SIG = X_SIG^2`, normalized to a 24-bit significand. +//! * **A** — the sequential f32 RNE accumulation `acc_out = RNE_f32(acc_in + sq)` (a windowed, +//! guard+sticky fold mirroring [`crate::circuit::fp16::noisy_quant_fma_stark`], here both terms +//! nonnegative), chained row-to-row; `sumsq` is pinned to the last row's `acc_out`. +//! * **V** — `q = RNE_f32(sumsq / k)` (a divide-by-constant bracket). +//! * **S** — `s = RNE_f32(sqrt(q))` (a squared quarter-ulp bracket). +//! * **C / G / F** — `l2raw = f32_to_bf16(s)`, `l2grid = round_l2_to_grid(l2raw)`, +//! `l2 = bf16_max(l2grid, floor)`. +//! * **L** — `linf = bf16_max(f32_to_bf16(max|x|), floor)`. +//! * **H1/H3/H4/H5** — the scale chain `noised_bound = bf16_fma(dr, l2, linf)`, +//! `alpha = bf16_div(2^16, noised_bound)`, `m1 = bf16_mul(alpha, l2)`, `beta = bf16_mul(m1, dos)`. +//! +//! # Soundness envelope (documented, not an unproved shortcut) +//! +//! `r` is the fixed noise rank 32, so `dr`/`dos` are compile-time constants. The row is in scope +//! when every intermediate stays f32-normal (no subnormal f32 sum/quotient/root — the squares are +//! `>= 2^-48` and `k <= 2^16`, so a nonzero row keeps `sumsq`, `q`, `s` normal) and the final +//! `l2`/`alpha` do not snap into the bf16 infinity code. An out-of-scope row is simply unprovable +//! (the generator asserts the envelope), exactly as [`crate::circuit::fp16::noise_stark`] treats +//! its rejected boundaries. Every ties-to-even rounding carries the full machinery (parity split + +//! binade-bottom `IS_BOTTOM` where the binade is asymmetric) with NO quarter-ulp grinding slack. + +use core::borrow::{Borrow, BorrowMut}; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{NUM_ROW_SCALE_COLUMNS, NUM_ROW_SCALE_PUBLIC_INPUTS, ROW_SCALE_COL_MAP, RowScaleColumnsView}; +use crate::api::fp16::dtype::{fp16_decode_fields, fp16_to_f32}; +use crate::api::fp16::quantization::{DELTA, MAX_FP16, NORM_FLOOR}; +use crate::api::fp8::compute::{bf16_div, bf16_fma, bf16_mul}; +use crate::api::fp8::dtype::f32_to_bf16; +use crate::api::fp8::prequant::round_l2_to_grid; +use crate::api::fp8::quantization::NOISE_TARGET_NORM; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// bf16 unit offset: a finite bf16 is `M * 2^(E* - 134)` (`134 = bias 127 + 7 fraction bits`). +const BF16_UNIT: u64 = 134; +/// `acc_out_exp = eta + ww + carry + ACC_EXP_ADD` (`= 100 - 64`, the `64` being the fold's biased +/// value-MSB offset, which keeps every term's MSB nonnegative since the smallest nonzero square is +/// `2^-48`, so the unbiased MSB bottoms out at `-48`). +const ACC_EXP_ADD: u64 = 36; +/// A term is "far" (contributes only to the sticky bit) when its relative shift reaches this (the +/// 24-bit significand plus 3 guard bits). +const FAR_CAP: u64 = 27; +/// Division-bracket key base for `alpha = RNE(2^16 / nb)`: `2 + 16 + 2*134` (numerator `2^16`). +pub(crate) const DIV_KEY_BASE: u64 = 2 + 16 + 2 * BF16_UNIT; +/// bf16 code of the norm floor `NORM_FLOOR = 2^-32` (exp field 95, mantissa 0). +pub(crate) const FLOOR_CODE: u64 = 0x2F80; + +fn inv_f(x: u64) -> F { + if x == 0 { F::ZERO } else { F::from_canonical_u64(x).inverse() } +} + +fn inv_diff(a: u64, b: u64) -> F { + let d = F::from_canonical_u64(a) - F::from_canonical_u64(b); + if d == F::ZERO { F::ZERO } else { d.inverse() } +} + +fn bit_length(x: u64) -> u64 { + 64 - u64::from(x.leading_zeros()) +} + +/// `x >> shift` rounded to nearest, ties to even. +fn round_shift(x: u64, shift: u64) -> u64 { + if shift == 0 { + return x; + } + let dropped = x & ((1u64 << shift) - 1); + let kept = x >> shift; + let half = 1u64 << (shift - 1); + if dropped > half || (dropped == half && (kept & 1) == 1) { kept + 1 } else { kept } +} + +/// Nonnegative f32 fields `(sig24, biased_exp, is_zero)`: `value = sig24 * 2^(exp - 150)`, +/// `sig24 in [2^23, 2^24)` for normals, `(0, 0, true)` for zero. Panics on subnormal/non-finite +/// (out of the documented envelope). +fn f32_fields(x: f32) -> (u64, u64, bool) { + assert!(x.is_finite() && x >= 0.0, "f32 field extraction expects a finite nonnegative value"); + if x == 0.0 { + return (0, 0, true); + } + let bits = x.to_bits(); + let exp = u64::from((bits >> 23) & 0xFF); + assert!(exp != 0, "envelope: f32 intermediate must be normal (not subnormal)"); + ((1u64 << 23) | u64::from(bits & 0x7F_FFFF), exp, false) +} + +/// The committed geometry: the number of operand rows (A rows then B rows), the row length `k`, the +/// fixed noise rank `r`, and the trace height (a power of two covering `num_operand_rows * k`). +#[derive(Clone, Debug)] +pub struct RowScaleProgram { + /// Number of operand rows proved end to end (`h + w` in the batch; `1` standalone). Each is a + /// self-contained `k`-element block. + pub num_operand_rows: usize, + /// Number of leading A-side operand rows (`h`); the remaining `num_operand_rows - num_a_rows` + /// are B-side (`w`). An AIR compile-time constant (like `k`) — it fixes the per-side liveness + /// thresholds `num_a_rows*k` / `num_b_rows*k`, so it needs NO known column / no public input. + pub num_a_rows: usize, + /// Number of FP16 values in each operand row. + pub k: usize, + /// Noise rank (fixed at 32; `dr`/`dos` are then compile-time constants). + pub r: usize, + /// Trace height (a power of two `>= num_operand_rows * k`). + pub num_rows: usize, +} + +impl RowScaleProgram { + /// Builds a single-operand-row program padded to the next power of two (standalone / unit-test + /// path). The batch uses [`Self::with_rows`] to pin an on-ladder height. + pub fn new(k: usize, r: usize) -> Self { + Self::with_rows(1, k, r, (k).next_power_of_two().max(2)) + } + + /// Builds the program for `num_operand_rows` rows of `k` elements at an explicit `num_rows` + /// height, asserting the compile-time facts the AIR bakes in: `dr`/`dos` are the exact bf16 + /// constants of `DELTA*sqrt(r)` and `DELTA*sqrt(r)/N^2`, `MAX_FP16` rounds to the power of two + /// `2^16` in bf16, and `NORM_FLOOR` is `2^-32`. + pub fn with_rows(num_operand_rows: usize, k: usize, r: usize, num_rows: usize) -> Self { + assert!(k >= 1, "a row has at least one element"); + assert!(num_operand_rows >= 1, "at least one operand row"); + assert!(num_rows.is_power_of_two(), "trace height must be a power of two"); + assert!(num_rows >= num_operand_rows * k, "trace height must cover every live block"); + assert_eq!(f32_to_bf16(MAX_FP16).expect("65504 finite"), 0x4780, "MAX_FP16 rounds to 2^16 in bf16"); + assert_eq!(f32_to_bf16(NORM_FLOOR).expect("2^-32 finite"), FLOOR_CODE as u16, "NORM_FLOOR = 2^-32"); + // dr/dos are structurally normal bf16 constants (used by the scale chain). + let dr = Self::dr_code_for(r); + let dos = Self::dos_code_for(r); + assert!((1..=254).contains(&(dr >> 7)) && (1..=254).contains(&(dos >> 7)), "dr/dos are normal bf16"); + // Standalone / single-side path: every row is A-side (the B gate is then vacuous, `w = 0`). + Self { num_operand_rows, num_a_rows: num_operand_rows, k, r, num_rows } + } + + /// The batch path: `num_a_rows` A rows (`h`) followed by `num_b_rows` B rows (`w`), laid out A + /// then B exactly as the operand commitment / noisy-quant expect. Fixes both per-side liveness + /// thresholds. + pub fn with_rows_ab(num_a_rows: usize, num_b_rows: usize, k: usize, r: usize, num_rows: usize) -> Self { + let mut p = Self::with_rows(num_a_rows + num_b_rows, k, r, num_rows); + p.num_a_rows = num_a_rows; + p + } + + fn dr_code_for(r: usize) -> u16 { + f32_to_bf16((DELTA * (r as f64).sqrt()) as f32).expect("dr finite") + } + + fn dos_code_for(r: usize) -> u16 { + f32_to_bf16((DELTA * (r as f64).sqrt() / (NOISE_TARGET_NORM * NOISE_TARGET_NORM)) as f32).expect("dos finite") + } + + pub fn dr_code(&self) -> u16 { + Self::dr_code_for(self.r) + } + + pub fn dos_code(&self) -> u16 { + Self::dos_code_for(self.r) + } + + pub fn live_rows(&self) -> usize { + self.num_operand_rows * self.k + } + + pub fn num_rows(&self) -> usize { + self.num_rows + } + + /// The live-row -> operand-row index map, `is_block_start`, and `is_block_final` as closures over + /// a trace row (a pure function of the geometry; the trailing padding block starts at the first + /// padding row). + fn block_schedule(&self, i: usize) -> (bool, usize, bool, bool) { + let live = self.live_rows(); + let is_pad = i >= live; + let operand_row_index = if is_pad { self.num_operand_rows - 1 } else { i / self.k }; + // Block starts: the first row of each live k-block, plus the first padding row (one trailing + // padding block). + let is_block_start = (!is_pad && i % self.k == 0) || (is_pad && i == live); + let is_block_final = !is_pad && i % self.k == self.k - 1; + (is_pad, operand_row_index, is_block_start, is_block_final) + } + + /// The class (a) ("known") columns (`IS_PAD`, `OPERAND_ROW_INDEX`, `IS_BLOCK_START`, + /// `IS_BLOCK_FINAL`), pure functions of the geometry. + pub fn known_values(&self) -> Vec> { + let num_rows = self.num_rows(); + let mut is_pad = Vec::with_capacity(num_rows); + let mut ori = Vec::with_capacity(num_rows); + let mut bstart = Vec::with_capacity(num_rows); + let mut bfinal = Vec::with_capacity(num_rows); + for i in 0..num_rows { + let (p, o, bs, bf) = self.block_schedule(i); + is_pad.push(F::from_bool(p)); + ori.push(F::from_canonical_usize(o)); + bstart.push(F::from_bool(bs)); + bfinal.push(F::from_bool(bf)); + } + vec![ + PolynomialValues::new(is_pad), + PolynomialValues::new(ori), + PolynomialValues::new(bstart), + PolynomialValues::new(bfinal), + ] + } + + /// Generates the trace from `num_operand_rows * k` raw FP16 operand codes (A rows then B rows), + /// bit-exact with the reference per-row `row_norms` + the floor + `derive_row_scales`. + pub fn generate_trace(&self, rows_codes: &[u16]) -> Vec<[F; NUM_ROW_SCALE_COLUMNS]> { + assert_eq!(rows_codes.len(), self.live_rows(), "one code per live block element"); + let num_rows = self.num_rows(); + let live = self.live_rows(); + + // ---- Pass 1: the sequential f32 sum of squares and running max, PER BLOCK. The fold resets + // at every block start (`is_block_start`); padding rows carry code 0 and form one trailing + // block whose (unused) scalars are the all-zero-row floor case. `sumsq` pins to each live + // block's final row via `is_block_final`. ---- + let mut acc: f32 = 0.0; + let mut run_max: u16 = 0; + let mut per_elem: Vec> = Vec::with_capacity(num_rows); + // Each block's (start_row, end_row_inclusive, sumsq, max_abs_code); scalars are filled from + // these and overlaid onto every row of the block. + let mut blocks: Vec<(usize, usize, f32, u64)> = Vec::new(); + let mut block_start_idx = 0usize; + for i in 0..num_rows { + let (is_pad, operand_row_index, is_block_start, is_block_final) = self.block_schedule(i); + if is_block_start { + acc = 0.0; + run_max = 0; + block_start_idx = i; + } + let code = if is_pad { 0 } else { rows_codes[i] }; + let mut v = RowScaleColumnsView::::default(); + v.is_pad = F::from_bool(is_pad); + v.operand_row_index = F::from_canonical_usize(operand_row_index); + v.is_block_start = F::from_bool(is_block_start); + v.is_block_final = F::from_bool(is_block_final); + v.code = F::from_canonical_u16(code); + let _ = live; + let (x_sig, x_sign, x_eps_biased, x_is_zero) = fp16_decode_fields(code); + v.x_sig = F::from_canonical_u64(x_sig); + v.x_sign = F::from_canonical_u64(x_sign); + v.x_eps_biased = F::from_canonical_u64(x_eps_biased); + v.x_is_zero = F::from_canonical_u64(x_is_zero); + let abs_code = u64::from(code & 0x7FFF); + v.abs_code = F::from_canonical_u64(abs_code); + + // Running max of the magnitude code. + let prev = u64::from(run_max); + let ge = abs_code >= prev; + v.max_ge = F::from_bool(ge); + v.max_slack = F::from_canonical_u64(if ge { abs_code - prev } else { prev - abs_code - 1 }); + if ge { + run_max = (abs_code) as u16; + } + v.run_max = F::from_canonical_u64(u64::from(run_max)); + + // Exact square significand and its 24-bit normalization. + let sq_sig = x_sig * x_sig; + v.sq_sig = F::from_canonical_u64(sq_sig); + let (sq_w, sq_lift, sq_norm) = if sq_sig == 0 { + (0u64, 0u64, 0u64) + } else { + let w = bit_length(sq_sig); + let lift = 1u64 << (24 - w); + (w, lift, sq_sig * lift) + }; + v.sq_w = F::from_canonical_u64(sq_w); + v.sq_lift = F::from_canonical_u64(sq_lift); + v.sq_norm = F::from_canonical_u64(sq_norm); + v.sq_norm_lo = F::from_canonical_u64(sq_norm & 0xFFFF); + v.sq_norm_hi = F::from_canonical_u64(sq_norm >> 16); + + // acc_in fields. + let (acc_in_sig, acc_in_exp, acc_in_zero) = f32_fields(acc); + v.acc_in_sig = F::from_canonical_u64(acc_in_sig); + v.acc_in_sig_lo = F::from_canonical_u64(acc_in_sig & 0xFFFF); + v.acc_in_sig_hi = F::from_canonical_u64(acc_in_sig >> 16); + v.acc_in_exp = F::from_canonical_u64(acc_in_exp); + v.acc_in_zero = F::from_bool(acc_in_zero); + + // ---- fold: acc_out = RNE_f32(acc_in + sq). Both terms nonnegative. ---- + let sq_zero = x_is_zero == 1; + // Biased value-MSBs: msb_b = exp_field - 127 + ACC_MSB_BIAS = exp_field - 63. + // sq's exp field (if nonzero) = 2*x_eps_biased + sq_w + 76. + let sq_exp_field = 2 * x_eps_biased + sq_w + 76; + let sq_msb = if sq_zero { 0 } else { sq_exp_field - 63 }; + let acc_msb = if acc_in_zero { 0 } else { acc_in_exp - 63 }; + v.sq_msb = F::from_canonical_u64(sq_msb); + v.acc_msb = F::from_canonical_u64(acc_msb); + let eta = sq_msb.max(acc_msb); + v.eta = F::from_canonical_u64(eta); + // rel = eta - msb (msb is already 0 for a zero term, so its rel becomes eta; the term is + // still excluded via `active` below — this matches the eval constraint `rel = eta - msb`). + let rel_sq = eta - sq_msb; + let rel_acc = eta - acc_msb; + v.rel_sq = F::from_canonical_u64(rel_sq); + v.rel_acc = F::from_canonical_u64(rel_acc); + let far_sq = rel_sq >= FAR_CAP; + let far_acc = rel_acc >= FAR_CAP; + v.far_sq = F::from_bool(far_sq); + v.far_sq_slack = F::from_canonical_u64(if far_sq { rel_sq - FAR_CAP } else { FAR_CAP - 1 - rel_sq }); + v.far_acc = F::from_bool(far_acc); + v.far_acc_slack = F::from_canonical_u64(if far_acc { rel_acc - FAR_CAP } else { FAR_CAP - 1 - rel_acc }); + let active_sq = !sq_zero && !far_sq; + let active_acc = !acc_in_zero && !far_acc; + v.active_sq = F::from_bool(active_sq); + v.active_acc = F::from_bool(active_acc); + + let fill_align = |sig: u64, rel: u64, active: bool| -> (u64, u64, u64, u64) { + if active { + let pow = 1u64 << rel; + let a = (sig * 8) / pow; + let rem = sig * 8 - a * pow; + (pow, a, rem, pow - 1 - rem) + } else { + (1, 0, 0, 0) + } + }; + let (pow_sq, aligned_sq, rem_sq, rem_sq_bound) = fill_align(sq_norm, rel_sq, active_sq); + v.pow_sq = F::from_canonical_u64(pow_sq); + v.aligned_sq = F::from_canonical_u64(aligned_sq); + v.aligned_sq_lo = F::from_canonical_u64(aligned_sq & 0xFFFF); + v.aligned_sq_hi = F::from_canonical_u64(aligned_sq >> 16); + v.rem_sq = F::from_canonical_u64(rem_sq); + v.rem_sq_lo = F::from_canonical_u64(rem_sq & 0xFFFF); + v.rem_sq_hi = F::from_canonical_u64(rem_sq >> 16); + v.rem_sq_bound = F::from_canonical_u64(rem_sq_bound); + v.rem_sq_bound_lo = F::from_canonical_u64(rem_sq_bound & 0xFFFF); + v.rem_sq_bound_hi = F::from_canonical_u64(rem_sq_bound >> 16); + let (pow_acc, aligned_acc, rem_acc, rem_acc_bound) = fill_align(acc_in_sig, rel_acc, active_acc); + v.pow_acc = F::from_canonical_u64(pow_acc); + v.aligned_acc = F::from_canonical_u64(aligned_acc); + v.aligned_acc_lo = F::from_canonical_u64(aligned_acc & 0xFFFF); + v.aligned_acc_hi = F::from_canonical_u64(aligned_acc >> 16); + v.rem_acc = F::from_canonical_u64(rem_acc); + v.rem_acc_lo = F::from_canonical_u64(rem_acc & 0xFFFF); + v.rem_acc_hi = F::from_canonical_u64(rem_acc >> 16); + v.rem_acc_bound = F::from_canonical_u64(rem_acc_bound); + v.rem_acc_bound_lo = F::from_canonical_u64(rem_acc_bound & 0xFFFF); + v.rem_acc_bound_hi = F::from_canonical_u64(rem_acc_bound >> 16); + + let rem_sq_nz = rem_sq != 0; + let rem_acc_nz = rem_acc != 0; + v.rem_sq_nz = F::from_bool(rem_sq_nz); + v.rem_sq_nz_inv = inv_f::(rem_sq); + v.rem_acc_nz = F::from_bool(rem_acc_nz); + v.rem_acc_nz_inv = inv_f::(rem_acc); + let or_sq = far_sq || rem_sq_nz; + let or_acc = far_acc || rem_acc_nz; + v.or_sq = F::from_bool(or_sq); + v.or_acc = F::from_bool(or_acc); + let sticky_sq = !sq_zero && or_sq; + let sticky_acc = !acc_in_zero && or_acc; + v.sticky_sq = F::from_bool(sticky_sq); + v.sticky_acc = F::from_bool(sticky_acc); + let far_sticky = sticky_sq || sticky_acc; + v.far_sticky = F::from_bool(far_sticky); + + let w = aligned_sq + aligned_acc; + v.w_abs = F::from_canonical_u64(w); + v.w_abs_lo = F::from_canonical_u64(w & 0xFFFF); + v.w_abs_hi = F::from_canonical_u64(w >> 16); + let w_is_zero = w == 0; + v.w_is_zero = F::from_bool(w_is_zero); + v.w_abs_inv = inv_f::(w); + + let (ww, trunc_w, lift_w, m_rz, rz_rem) = if w_is_zero { + (0, 1, 1, 0, 0) + } else { + let ww = bit_length(w); + let tr = 1u64 << ww.saturating_sub(24); + let lf = 1u64 << 24u64.saturating_sub(ww); + let m = w * lf / tr; + (ww, tr, lf, m, w * lf - m * tr) + }; + v.ww = F::from_canonical_u64(ww); + v.trunc_w = F::from_canonical_u64(trunc_w); + v.lift_w = F::from_canonical_u64(lift_w); + v.m_rz = F::from_canonical_u64(m_rz); + v.m_rz_lo = F::from_canonical_u64(m_rz & 0xFFFF); + v.m_rz_hi = F::from_canonical_u64(m_rz >> 16); + v.rz_rem = F::from_canonical_u64(rz_rem); + v.rz_rem_bound = F::from_canonical_u64(if w_is_zero { 0 } else { trunc_w - 1 - rz_rem }); + let rz_parity = m_rz & 1; + v.rz_parity = F::from_canonical_u64(rz_parity); + v.rz_half = F::from_canonical_u64(((m_rz & 0xFFFF) - rz_parity) / 2); + let gt = 2 * rz_rem > trunc_w; + v.gt = F::from_bool(gt); + v.gt_slack = F::from_canonical_u64(if gt { 2 * rz_rem - trunc_w - 1 } else { trunc_w - 2 * rz_rem }); + let eq = 2 * rz_rem == trunc_w; + v.eq = F::from_bool(eq); + v.eq_inv = inv_diff::(trunc_w, 2 * rz_rem); + let or_rs = far_sticky || rz_parity == 1; + v.or_rs = F::from_bool(or_rs); + let round_up = gt || (eq && or_rs); + v.round_up = F::from_bool(round_up); + let m_out = m_rz + u64::from(round_up); + let carry = m_out == (1 << 24); + v.carry = F::from_bool(carry); + v.carry_inv = inv_diff::(1 << 24, m_out); + let m_out_final = if carry { 1 << 23 } else { m_out }; + + // acc_out. + let (acc_out_sig, acc_out_exp, acc_out_zero) = if w_is_zero { + (0, 0, true) + } else { + (m_out_final, eta + ww + u64::from(carry) + ACC_EXP_ADD, false) + }; + v.acc_out_sig = F::from_canonical_u64(acc_out_sig); + v.acc_out_sig_lo = F::from_canonical_u64(acc_out_sig & 0xFFFF); + v.acc_out_sig_hi = F::from_canonical_u64(acc_out_sig >> 16); + v.acc_out_exp = F::from_canonical_u64(acc_out_exp); + v.acc_out_zero = F::from_bool(acc_out_zero); + + // Advance the real f32 accumulator and cross-check. + let v_f32 = fp16_to_f32(code); + let sq_f32 = v_f32 * v_f32; + let acc_next = acc + sq_f32; + let (want_sig, want_exp, want_zero) = f32_fields(acc_next); + debug_assert_eq!( + (acc_out_sig, acc_out_exp, acc_out_zero), + (want_sig, want_exp, want_zero), + "fold diverged from the reference f32 accumulation at code {code:#06x}" + ); + acc = acc_next; + + per_elem.push(v); + + // A block ends at the last trace row or just before the next block start. + let block_end = i == num_rows - 1 || self.block_schedule(i + 1).2; + if block_end { + blocks.push((block_start_idx, i, acc, u64::from(run_max))); + } + } + + // ---- Assemble rows: per-element columns overlaid with each block's (constant) scalars. + // The per-element entry-liveness `dead` flag is filled here (it needs the block's floored + // `l2`), plus the per-row `is_b_side` mask. ---- + let mut rows: Vec<[F; NUM_ROW_SCALE_COLUMNS]> = Vec::with_capacity(num_rows); + rows.resize(num_rows, [F::ZERO; NUM_ROW_SCALE_COLUMNS]); + for &(start, end, sumsq, max_abs_code) in &blocks { + let scalars = self.fill_scalars::(sumsq, max_abs_code); + let l2_e = scalars.l2_e.to_canonical_u64(); + let l2_m = scalars.l2_m.to_canonical_u64(); + for (r, pe) in per_elem[start..=end].iter().enumerate() { + let mut v = *pe; + copy_scalars(&mut v, &scalars); + let i = start + r; + let (is_pad, operand_row_index, _, _) = self.block_schedule(i); + self.fill_dead::(&mut v, pe.x_sig.to_canonical_u64(), pe.x_eps_biased.to_canonical_u64(), l2_e, l2_m); + // Per-row side mask + its two-sided pin slack (gated live in the AIR). + let b_side = operand_row_index >= self.num_a_rows; + v.is_b_side = F::from_bool(b_side); + let h = self.num_a_rows as u64; + let ori = operand_row_index as u64; + v.b_side_slack = F::from_canonical_u64(if b_side { ori - h } else { h - 1 - ori }); + let _ = is_pad; + rows[i] = v.into(); + } + } + + // ---- Final pass: per-side inclusive dead accumulators + the last-row gate slacks. ---- + let m = &ROW_SCALE_COL_MAP; + let (mut run_a, mut run_b) = (0u64, 0u64); + for i in 0..num_rows { + let (is_pad, operand_row_index, _, _) = self.block_schedule(i); + let dead = rows[i][m.dead].to_canonical_u64(); + if !is_pad { + if operand_row_index >= self.num_a_rows { + run_b += dead; + } else { + run_a += dead; + } + } + rows[i][m.dead_run_a] = F::from_canonical_u64(run_a); + rows[i][m.dead_run_b] = F::from_canonical_u64(run_b); + } + let k = self.k as u64; + let w = (self.num_operand_rows - self.num_a_rows) as u64; + let a_slack = (self.num_a_rows as u64 * k).wrapping_sub(64 * run_a); + let b_slack = (w * k).wrapping_sub(64 * run_b); + let last = num_rows - 1; + rows[last][m.a_gate_slack_lo] = F::from_canonical_u64(a_slack & 0xFFFF); + rows[last][m.a_gate_slack_hi] = F::from_canonical_u64((a_slack >> 16) & 0xFFFF); + rows[last][m.b_gate_slack_lo] = F::from_canonical_u64(b_slack & 0xFFFF); + rows[last][m.b_gate_slack_hi] = F::from_canonical_u64((b_slack >> 16) & 0xFFFF); + rows + } + + /// Fills the per-element entry-liveness witnesses (`dead` and its aligned-compare gadget) for + /// `dead = [ |x| >= 4*l2 ]`, with `|x| = x_sig * 2^(x_eps_biased - 25)` and + /// `4*l2 = (128 + l2_m) * 2^(l2_e - 132)`. Exact-integer, bit-identical to the f64 compare in + /// [`crate::api::fp16::policy::check_shared_gates`]. + fn fill_dead(&self, v: &mut RowScaleColumnsView, x_sig: u64, x_eps_biased: u64, l2_e: u64, l2_m: u64) { + // s = exponent of |x|'s significand minus exponent of 4*l2's significand. + let s = x_eps_biased as i64 - l2_e as i64 + 107; + let sign = s >= 0; + let key = s.unsigned_abs(); + let pow = 1u64 << key.min(26); + let (pow_a, pow_b) = if sign { (pow, 1) } else { (1, pow) }; + let mb = 128 + l2_m; + let lhs = x_sig * pow_a; + let rhs = mb * pow_b; + let dead = lhs >= rhs; + let slack = if dead { lhs - rhs } else { rhs - lhs - 1 }; + v.dead = F::from_bool(dead); + v.dead_sign = F::from_bool(sign); + v.dead_key = F::from_canonical_u64(key); + v.dead_pow = F::from_canonical_u64(pow); + v.dead_pow_a = F::from_canonical_u64(pow_a); + v.dead_lhs = F::from_canonical_u64(lhs); + v.dead_rhs = F::from_canonical_u64(rhs); + v.dead_slack_lo = F::from_canonical_u64(slack & 0xFFFF); + v.dead_slack_mid = F::from_canonical_u64((slack >> 16) & 0xFFFF); + v.dead_slack_hi = F::from_canonical_u64(slack >> 32); + } + + /// Fills the scalar (whole-row) columns from the finished `sumsq` (f32) and `max_abs_code`. + fn fill_scalars(&self, sumsq: f32, max_abs_code: u64) -> RowScaleColumnsView { + let mut v = RowScaleColumnsView::::default(); + let k = self.k as u64; + + let (sumsq_sig, sumsq_exp, sumsq_zero) = f32_fields(sumsq); + v.sumsq_sig = F::from_canonical_u64(sumsq_sig); + v.sumsq_sig_lo = F::from_canonical_u64(sumsq_sig & 0xFFFF); + v.sumsq_sig_hi = F::from_canonical_u64(sumsq_sig >> 16); + v.sumsq_exp = F::from_canonical_u64(sumsq_exp); + v.sumsq_zero = F::from_bool(sumsq_zero); + v.max_abs_code = F::from_canonical_u64(max_abs_code); + + // ---- q = RNE_f32(sumsq / k). ---- + let q = sumsq / self.k as f32; + let (q_sig, q_exp, q_zero) = f32_fields(q); + v.q_sig = F::from_canonical_u64(q_sig); + v.q_sig_lo = F::from_canonical_u64(q_sig & 0xFFFF); + v.q_sig_hi = F::from_canonical_u64(q_sig >> 16); + v.q_exp = F::from_canonical_u64(q_exp); + v.q_zero = F::from_bool(q_zero); + if !q_zero { + let dexp = sumsq_exp - q_exp; // >= 0 (dividing by k >= 1 lowers the exponent) + assert!((0..=26).contains(&dexp), "envelope: division shift out of FP16POW2 domain ({dexp})"); + v.q_dexp = F::from_canonical_u64(dexp); + v.q_pow = F::from_canonical_u64(1u64 << dexp); + let bottom = u64::from(q_sig == (1 << 23)); + let parity = q_sig & 1; + v.q_bottom = F::from_canonical_u64(bottom); + v.q_bottom_inv = inv_diff::(q_sig, 1 << 23); + v.q_parity = F::from_canonical_u64(parity); + v.q_half = F::from_canonical_u64(((q_sig & 0xFFFF) - parity) / 2); + let blo = (4 * q_sig - 2 + bottom) * k; + let bhi = (4 * q_sig + 2) * k; + let target = 4 * sumsq_sig * (1u64 << dexp); + v.q_blo = F::from_canonical_u64(blo); + v.q_bhi = F::from_canonical_u64(bhi); + let sl = target - blo - parity; + let su = bhi - target - parity; + v.q_sl_lo = F::from_canonical_u64(sl & 0xFFFF); + v.q_sl_mid = F::from_canonical_u64((sl >> 16) & 0xFFFF); + v.q_sl_hi = F::from_canonical_u64(sl >> 32); + v.q_su_lo = F::from_canonical_u64(su & 0xFFFF); + v.q_su_mid = F::from_canonical_u64((su >> 16) & 0xFFFF); + v.q_su_hi = F::from_canonical_u64(su >> 32); + } + + // ---- s = RNE_f32(sqrt(q)). ---- + let s = q.sqrt(); + let (s_sig, s_exp, _s_zero) = f32_fields(s); + v.s_sig = F::from_canonical_u64(s_sig); + v.s_sig_lo = F::from_canonical_u64(s_sig & 0xFFFF); + v.s_sig_hi = F::from_canonical_u64(s_sig >> 16); + v.s_exp = F::from_canonical_u64(s_exp); + if !q_zero { + let sdexp = q_exp + 152 - 2 * s_exp; // Ds - 2, in [25, 26] + assert!((0..=26).contains(&sdexp), "envelope: sqrt shift out of FP16POW2 domain ({sdexp})"); + v.s_dexp = F::from_canonical_u64(sdexp); + v.s_pow = F::from_canonical_u64(1u64 << sdexp); + let bottom = u64::from(s_sig == (1 << 23)); + let parity = s_sig & 1; + v.s_bottom = F::from_canonical_u64(bottom); + v.s_bottom_inv = inv_diff::(s_sig, 1 << 23); + v.s_parity = F::from_canonical_u64(parity); + v.s_half = F::from_canonical_u64(((s_sig & 0xFFFF) - parity) / 2); + let blo = (4 * s_sig - 2 + bottom) * (4 * s_sig - 2 + bottom); + let bhi = (4 * s_sig + 2) * (4 * s_sig + 2); + let target = 4 * q_sig * (1u64 << sdexp); + v.s_blo = F::from_canonical_u64(blo); + v.s_bhi = F::from_canonical_u64(bhi); + let sl = target - blo - parity; + let su = bhi - target - parity; + v.s_sl_lo = F::from_canonical_u64(sl & 0xFFFF); + v.s_sl_mid = F::from_canonical_u64((sl >> 16) & 0xFFFF); + v.s_sl_hi = F::from_canonical_u64(sl >> 32); + v.s_su_lo = F::from_canonical_u64(su & 0xFFFF); + v.s_su_mid = F::from_canonical_u64((su >> 16) & 0xFFFF); + v.s_su_hi = F::from_canonical_u64(su >> 32); + } + + // ---- l2raw = f32_to_bf16(s): round the 24-bit significand to 8 bits (shift 16). ---- + let l2raw_code: u64 = if q_zero { + 0 + } else { + fill_round24to8::( + s_sig, s_exp, &mut v.l2raw_mant, &mut v.l2raw_exp, &mut v.l2raw_carry, &mut v.l2raw_bottom, + &mut v.l2raw_bottom_inv, &mut v.l2raw_parity, &mut v.l2raw_half, &mut v.l2raw_blo, &mut v.l2raw_bhi, + &mut v.l2raw_sl_lo, &mut v.l2raw_sl_hi, &mut v.l2raw_su_lo, &mut v.l2raw_su_hi, + ) + }; + v.l2raw_code = F::from_canonical_u64(l2raw_code); + debug_assert_eq!( + l2raw_code as u16, + if sumsq == 0.0 { 0 } else { f32_to_bf16((sumsq / self.k as f32).sqrt()).expect("l2raw finite") }, + "l2raw diverged from f32_to_bf16(sqrt(sumsq/k))" + ); + + // ---- l2grid = round_l2_to_grid(l2raw). ---- + let grid_in = l2raw_code + 2; + let grid_q = grid_in >> 2; + let grid_r = grid_in - 4 * grid_q; + let l2grid_code = 4 * grid_q; + v.grid_q = F::from_canonical_u64(grid_q); + v.grid_r = F::from_canonical_u64(grid_r); + v.grid_r_b0 = F::from_canonical_u64(grid_r & 1); + v.grid_r_b1 = F::from_canonical_u64((grid_r >> 1) & 1); + v.l2grid_code = F::from_canonical_u64(l2grid_code); + debug_assert_eq!(l2grid_code as u16, round_l2_to_grid(l2raw_code as u16), "grid diverged"); + + // ---- l2 = bf16_max(l2grid, floor). ---- + let l2_ge = l2grid_code >= FLOOR_CODE; + v.l2_ge = F::from_bool(l2_ge); + v.l2_floor_slack = + F::from_canonical_u64(if l2_ge { l2grid_code - FLOOR_CODE } else { FLOOR_CODE - l2grid_code - 1 }); + let l2_code = if l2_ge { l2grid_code } else { FLOOR_CODE }; + v.l2_code = F::from_canonical_u64(l2_code); + v.l2_e = F::from_canonical_u64(l2_code >> 7); + v.l2_m = F::from_canonical_u64(l2_code & 0x7F); + + // ---- linf = bf16_max(f32_to_bf16(max|x|), floor). ---- + let (max_sig, _max_sign, max_eps_biased, max_is_zero) = fp16_decode_fields(max_abs_code as u16); + v.max_sig = F::from_canonical_u64(max_sig); + v.max_eps_biased = F::from_canonical_u64(max_eps_biased); + v.max_is_zero = F::from_canonical_u64(max_is_zero); + let linf_raw_code: u64 = if max_is_zero == 1 { + 0 + } else { + let max_w = bit_length(max_sig); + let max_lift = 1u64 << (24 - max_w); + let max_norm = max_sig * max_lift; + v.max_w = F::from_canonical_u64(max_w); + v.max_lift = F::from_canonical_u64(max_lift); + v.max_norm = F::from_canonical_u64(max_norm); + v.max_norm_lo = F::from_canonical_u64(max_norm & 0xFFFF); + v.max_norm_hi = F::from_canonical_u64(max_norm >> 16); + // base exp for round24to8: linf_raw_exp = max_eps_biased + max_w + 101 (+carry). + let base_exp = max_eps_biased + max_w + 101; + fill_round24to8::( + max_norm, base_exp, &mut v.linf_raw_mant, &mut v.linf_raw_exp, &mut v.linf_raw_carry, + &mut v.linf_raw_bottom, &mut v.linf_raw_bottom_inv, &mut v.linf_raw_parity, &mut v.linf_raw_half, + &mut v.linf_raw_blo, &mut v.linf_raw_bhi, &mut v.linf_raw_sl_lo, &mut v.linf_raw_sl_hi, + &mut v.linf_raw_su_lo, &mut v.linf_raw_su_hi, + ) + }; + v.linf_raw_code = F::from_canonical_u64(linf_raw_code); + debug_assert_eq!( + linf_raw_code as u16, + f32_to_bf16(fp16_to_f32(max_abs_code as u16)).expect("linf_raw finite"), + "linf_raw diverged from f32_to_bf16(max|x|)" + ); + let linf_ge = linf_raw_code >= FLOOR_CODE; + v.linf_ge = F::from_bool(linf_ge); + v.linf_floor_slack = + F::from_canonical_u64(if linf_ge { linf_raw_code - FLOOR_CODE } else { FLOOR_CODE - linf_raw_code - 1 }); + let linf_code = if linf_ge { linf_raw_code } else { FLOOR_CODE }; + v.linf_code = F::from_canonical_u64(linf_code); + v.linf_e = F::from_canonical_u64(linf_code >> 7); + v.linf_m = F::from_canonical_u64(linf_code & 0x7F); + + // ---- noised_bound = bf16_fma(dr, l2, linf). ---- + let dr = u64::from(self.dr_code()); + let (dr_m, dr_e) = (128 + (dr & 0x7F), dr >> 7); + let (l2_m, l2_e) = (128 + (l2_code & 0x7F), l2_code >> 7); + let (linf_m, linf_e) = (128 + (linf_code & 0x7F), linf_code >> 7); + let nb_prod = dr_m * l2_m; + v.nb_prod = F::from_canonical_u64(nb_prod); + // linf is the coarser term: shift = E(linf) - E(l2) + 6 >= 0. + assert!(linf_e + 6 >= l2_e, "envelope: noised-bound alignment underflow"); + let nb_shift = linf_e + 6 - l2_e; + assert!(nb_shift <= 26, "envelope: noised-bound shift out of FP16POW2 domain ({nb_shift})"); + v.nb_shift = F::from_canonical_u64(nb_shift); + v.nb_shiftpow = F::from_canonical_u64(1u64 << nb_shift); + let nb_w = nb_prod + linf_m * (1u64 << nb_shift); + v.nb_w = F::from_canonical_u64(nb_w); + v.nb_w_lo = F::from_canonical_u64(nb_w & 0xFFFF); + v.nb_w_hi = F::from_canonical_u64(nb_w >> 16); + // Round W (exact sum) to the 8-bit significand. exp_base = E(dr) + E(l2). + let nb_code = fill_round_sig_to_bf16::( + nb_w, dr_e + l2_e, &mut v.nb_gm, &mut v.nb_pow, &mut v.nb_mant, &mut v.nb_exp, &mut v.nb_bottom, + &mut v.nb_bottom_inv, &mut v.nb_parity, &mut v.nb_half, &mut v.nb_blo, &mut v.nb_bhi, &mut v.nb_sl_lo, + &mut v.nb_sl_hi, &mut v.nb_su_lo, &mut v.nb_su_hi, + ); + v.nb_code = F::from_canonical_u64(nb_code); + debug_assert_eq!( + nb_code as u16, + bf16_fma(self.dr_code(), l2_code as u16, linf_code as u16).expect("nb finite"), + "noised_bound diverged from bf16_fma" + ); + + // ---- alpha = bf16_div(2^16, noised_bound) (power-of-two numerator). ---- + let alpha = u64::from(bf16_div(0x4780, nb_code as u16).expect("alpha finite")); + let (alpha_m, alpha_e) = (128 + (alpha & 0x7F), alpha >> 7); + assert!((1..=254).contains(&alpha_e), "envelope: alpha normal"); + v.alpha_exp = F::from_canonical_u64(alpha_e); + v.alpha_mant = F::from_canonical_u64(alpha & 0x7F); + let a_shift = DIV_KEY_BASE - nb_exp_of(nb_code) - alpha_e; + assert!((0..=26).contains(&a_shift), "envelope: alpha division shift out of FP16POW2 domain ({a_shift})"); + v.alpha_pow = F::from_canonical_u64(1u64 << a_shift); + let bottom = u64::from(alpha_m == 128); + let parity = alpha_m & 1; + v.alpha_bottom = F::from_canonical_u64(bottom); + v.alpha_bottom_inv = inv_diff::(alpha_m, 128); + v.alpha_parity = F::from_canonical_u64(parity); + v.alpha_half = F::from_canonical_u64(((alpha & 0x7F) - parity) / 2); // parity split on the 7-bit mantissa + let nb_m = 128 + (nb_code & 0x7F); + let blo = (4 * alpha_m - 2 + bottom) * nb_m; + let bhi = (4 * alpha_m + 2) * nb_m; + let dpow = 1u64 << a_shift; + v.alpha_blo = F::from_canonical_u64(blo); + v.alpha_bhi = F::from_canonical_u64(bhi); + v.alpha_sl = F::from_canonical_u64(dpow - blo - parity); + v.alpha_su = F::from_canonical_u64(bhi - dpow - parity); + v.alpha_code = F::from_canonical_u64(alpha); + + // ---- m1 = bf16_mul(alpha, l2); beta = bf16_mul(m1, dos). ---- + let m1 = u64::from(bf16_mul(alpha as u16, l2_code as u16).expect("m1 finite")); + fill_bf16_mul::( + alpha_m, alpha_e, l2_m, l2_e, m1, &mut v.m1_prod, &mut v.m1_mant, &mut v.m1_exp, &mut v.m1_bottom, + &mut v.m1_bottom_inv, &mut v.m1_parity, &mut v.m1_half, &mut v.m1_pow, &mut v.m1_gm, &mut v.m1_blo, + &mut v.m1_bhi, &mut v.m1_sl, &mut v.m1_su, + ); + v.m1_code = F::from_canonical_u64(m1); + let dos = u64::from(self.dos_code()); + let (dos_m, dos_e) = (128 + (dos & 0x7F), dos >> 7); + let (m1_m, m1_e) = (128 + (m1 & 0x7F), m1 >> 7); + let beta = u64::from(bf16_mul(m1 as u16, dos as u16).expect("beta finite")); + fill_bf16_mul::( + m1_m, m1_e, dos_m, dos_e, beta, &mut v.beta_prod, &mut v.beta_mant, &mut v.beta_exp, &mut v.beta_bottom, + &mut v.beta_bottom_inv, &mut v.beta_parity, &mut v.beta_half, &mut v.beta_pow, &mut v.beta_gm, + &mut v.beta_blo, &mut v.beta_bhi, &mut v.beta_sl, &mut v.beta_su, + ); + v.beta_code = F::from_canonical_u64(beta); + + v + } +} + +/// bf16 biased exponent field of a code. +fn nb_exp_of(code: u64) -> u64 { + code >> 7 +} + +/// Fills a "round a 24-bit significand `sig24` to the 8-bit bf16 significand" gadget at the fixed +/// shift 16 (with a mantissa-overflow carry). `base_exp` is the output exponent before the carry. +/// Returns the bf16 code. All boundary products use the constant factor `2^16`. +#[allow(clippy::too_many_arguments)] +fn fill_round24to8( + sig24: u64, base_exp: u64, mant: &mut F, exp: &mut F, carry: &mut F, bottom: &mut F, bottom_inv: &mut F, + parity: &mut F, half: &mut F, blo: &mut F, bhi: &mut F, sl_lo: &mut F, sl_hi: &mut F, su_lo: &mut F, su_hi: &mut F, +) -> u64 { + let m_pre = round_shift(sig24, 16); // in [128, 256] + let is_carry = m_pre == 256; + let m_out = if is_carry { 128 } else { m_pre }; + let out_exp = base_exp + u64::from(is_carry); + let out_mant = m_out - 128; + *mant = F::from_canonical_u64(out_mant); + *exp = F::from_canonical_u64(out_exp); + *carry = F::from_bool(is_carry); + let is_bottom = u64::from(m_pre == 128); + *bottom = F::from_canonical_u64(is_bottom); + *bottom_inv = inv_diff::(m_pre, 128); + let par = m_pre & 1; + *parity = F::from_canonical_u64(par); + *half = F::from_canonical_u64((m_pre - par) / 2); + let pow = 1u64 << 16; + let blo_v = (4 * m_pre - 2 + is_bottom) * pow; + let bhi_v = (4 * m_pre + 2) * pow; + *blo = F::from_canonical_u64(blo_v); + *bhi = F::from_canonical_u64(bhi_v); + let sl = 4 * sig24 - blo_v - par; + let su = bhi_v - 4 * sig24 - par; + *sl_lo = F::from_canonical_u64(sl & 0xFFFF); + *sl_hi = F::from_canonical_u64(sl >> 16); + *su_lo = F::from_canonical_u64(su & 0xFFFF); + *su_hi = F::from_canonical_u64(su >> 16); + (out_exp << 7) | out_mant +} + +/// Fills a "round an exact integer significand `w` (with LSB scale `unit`) to a bf16 code" gadget: +/// `gm = bitlen(w) - 8`, `M_out = round_shift(w, gm) in [128, 255]`, `exp = unit + gm + 134`. The +/// shift `2^gm` is an FP16POW2 value and the bracket uses the binade-bottom correction. +#[allow(clippy::too_many_arguments)] +fn fill_round_sig_to_bf16( + w: u64, exp_base: u64, gm: &mut F, pow: &mut F, mant: &mut F, exp: &mut F, bottom: &mut F, bottom_inv: &mut F, + parity: &mut F, half: &mut F, blo: &mut F, bhi: &mut F, sl_lo: &mut F, sl_hi: &mut F, su_lo: &mut F, su_hi: &mut F, +) -> u64 { + let mut g = bit_length(w) - 8; + let mut m_out = round_shift(w, g); + if m_out == 256 { + m_out = 128; + g += 1; + } + assert!((128..256).contains(&m_out), "bf16 significand normalized"); + // out_exp = (E(dr) + E(l2) - 268) + g + 134 = exp_base + g - 134, with exp_base = E(dr)+E(l2). + let out_exp = exp_base + g - BF16_UNIT; + let out_mant = m_out - 128; + *gm = F::from_canonical_u64(g); + *pow = F::from_canonical_u64(1u64 << g); + *mant = F::from_canonical_u64(out_mant); + *exp = F::from_canonical_u64(out_exp); + let is_bottom = u64::from(m_out == 128); + *bottom = F::from_canonical_u64(is_bottom); + *bottom_inv = inv_diff::(m_out, 128); + let par = m_out & 1; + *parity = F::from_canonical_u64(par); + *half = F::from_canonical_u64((out_mant - par) / 2); // parity split is on the 7-bit mantissa + let p = 1u64 << g; + let blo_v = (4 * m_out - 2 + is_bottom) * p; + let bhi_v = (4 * m_out + 2) * p; + *blo = F::from_canonical_u64(blo_v); + *bhi = F::from_canonical_u64(bhi_v); + let sl = 4 * w - blo_v - par; + let su = bhi_v - 4 * w - par; + *sl_lo = F::from_canonical_u64(sl & 0xFFFF); + *sl_hi = F::from_canonical_u64(sl >> 16); + *su_lo = F::from_canonical_u64(su & 0xFFFF); + *su_hi = F::from_canonical_u64(su >> 16); + (out_exp << 7) | out_mant +} + +/// Fills a bf16 RNE multiply `out = RNE_bf16(a*b)` gadget (a/b normal positive). `out` is the +/// reference code (for the exponent); the exact product significand is rounded to 8 bits. +#[allow(clippy::too_many_arguments)] +fn fill_bf16_mul( + a_m: u64, a_e: u64, b_m: u64, b_e: u64, out: u64, prod: &mut F, mant: &mut F, exp: &mut F, bottom: &mut F, + bottom_inv: &mut F, parity: &mut F, half: &mut F, pow: &mut F, gm: &mut F, blo: &mut F, bhi: &mut F, sl: &mut F, + su: &mut F, +) { + let p = a_m * b_m; + *prod = F::from_canonical_u64(p); + let mut g = bit_length(p) - 8; + let mut m_out = round_shift(p, g); + if m_out == 256 { + m_out = 128; + g += 1; + } + let out_exp = a_e + b_e + g - BF16_UNIT; // = a_e + b_e + g - 134 + debug_assert_eq!((out_exp << 7) | (m_out - 128), out, "bf16_mul fill mismatch"); + let out_mant = m_out - 128; + *mant = F::from_canonical_u64(out_mant); + *exp = F::from_canonical_u64(out_exp); + *gm = F::from_canonical_u64(g); + *pow = F::from_canonical_u64(1u64 << g); + let is_bottom = u64::from(m_out == 128); + *bottom = F::from_canonical_u64(is_bottom); + *bottom_inv = inv_diff::(m_out, 128); + let par = m_out & 1; + *parity = F::from_canonical_u64(par); + *half = F::from_canonical_u64((out_mant - par) / 2); // parity split is on the 7-bit mantissa + let pw = 1u64 << g; + let blo_v = (4 * m_out - 2 + is_bottom) * pw; + let bhi_v = (4 * m_out + 2) * pw; + *blo = F::from_canonical_u64(blo_v); + *bhi = F::from_canonical_u64(bhi_v); + *sl = F::from_canonical_u64(4 * p - blo_v - par); + *su = F::from_canonical_u64(bhi_v - 4 * p - par); +} + +/// Overlays the scalar columns of `src` onto `dst` (the whole-row columns that are identical on +/// every trace row). Copies exactly the scalar fields (everything from `sumsq_sig` onward). +fn copy_scalars(dst: &mut RowScaleColumnsView, src: &RowScaleColumnsView) { + let d: &mut [F; NUM_ROW_SCALE_COLUMNS] = dst.borrow_mut(); + let s: &[F; NUM_ROW_SCALE_COLUMNS] = src.borrow(); + let start = super::columns::ROW_SCALE_COL_MAP.sumsq_sig; + d[start..].copy_from_slice(&s[start..]); +} + +// ================================================================================================== +// Constraints (added incrementally; see the module docs for the groups). +// ================================================================================================== + +/// `flag = [x == 0]`, gated: `flag` boolean, `flag*x = 0`, `x*inv = 1 - flag`. +fn is_zero_flag(eval: &mut E, x: V, inv: V, flag: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + eval.constraint_bool(flag); + let fx = eval.mul(flag, x); + let c = eval.mul(gate, fx); + eval.constraint(c); + let xi = eval.mul(x, inv); + let omf = eval.sub(one, flag); + let d = eval.sub(xi, omf); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `a OR b` for booleans, committed to `out` (`out = a + b - a*b`), gated. +fn or_flag(eval: &mut E, a: V, b: V, out: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let ab = eval.mul(a, b); + let apb = eval.add(a, b); + let expect = eval.sub(apb, ab); + let d = eval.sub(out, expect); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `value = 2^16 * hi + lo`. +fn recon2(eval: &mut E, lo: V, hi: V) -> V +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let c = eval.u64(1 << 16); + eval.mad(hi, c, lo) +} + +/// `mant = 2*half + parity` with `parity` boolean (`half` is RANGE16'd in `ctl.rs`), gated. +fn parity_split(eval: &mut E, mant: V, half: V, parity: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + eval.constraint_bool(parity); + let two = eval.u64(2); + let two_half = eval.mul(two, half); + let rec = eval.add(two_half, parity); + let d = eval.sub(mant, rec); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// The committed scale constants passed to [`eval_row_scale_constraints`] (compile-time for the +/// fixed rank `r`). +#[derive(Clone, Copy)] +pub(crate) struct ScaleConsts { + pub k: u64, + pub dr_m: u64, + pub dr_e: u64, + pub dos_m: u64, + pub dos_e: u64, + /// Number of A-side operand rows `h` (the `is_b_side` threshold, as `operand_row_index >= h`). + pub num_a_rows: u64, + /// `h * k` — the A-side liveness gate RHS (`64 * dead_A <= h*k`). + pub a_gate_rhs: u64, + /// `w * k` — the B-side liveness gate RHS (`64 * dead_B <= w*k`). + pub b_gate_rhs: u64, +} + +pub(crate) fn eval_row_scale_constraints( + vars: &StarkFrame, + eval: &mut E, + consts: ScaleConsts, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv_arr: &[V; NUM_ROW_SCALE_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let nv_arr: &[V; NUM_ROW_SCALE_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let lv: &RowScaleColumnsView = lv_arr.borrow(); + let nv: &RowScaleColumnsView = nv_arr.borrow(); + + let one = eval.u64(1); + let two = eval.u64(2); + let c8 = eval.u64(8); + let c2_15 = eval.u64(1 << 15); + let c2_23 = eval.u64(1 << 23); + let c2_24 = eval.u64(1 << 24); + let c26 = eval.u64(26); + let c27 = eval.u64(FAR_CAP); + let c63 = eval.u64(63); + + eval.constraint_bool(lv.is_pad); + + // ============================= GROUP D: decode + pad forcing. ============================= + eval.constraint_bool(lv.x_sign); + eval.constraint_bool(lv.x_is_zero); + // abs_code = code - x_sign*2^15. + let sign_hi = eval.mul(lv.x_sign, c2_15); + let abs_expect = eval.sub(lv.code, sign_hi); + eval.constraint_eq(lv.abs_code, abs_expect); + // Padding rows carry a zero element: code = 0, x_sig = 0, x_sign = 0, x_is_zero = 1. + let c = eval.mul(lv.is_pad, lv.code); + eval.constraint(c); + let c = eval.mul(lv.is_pad, lv.x_sig); + eval.constraint(c); + let c = eval.mul(lv.is_pad, lv.x_sign); + eval.constraint(c); + let one_m_xz = eval.sub(one, lv.x_is_zero); + let c = eval.mul(lv.is_pad, one_m_xz); + eval.constraint(c); + + // ============================= GROUP M: running max of ABS_CODE. ============================= + eval.constraint_bool(lv.max_ge); + // First row (prev = 0): run_max = abs_code; slack = ge*abs - (1-ge)*(abs+1). + { + let not_ge = eval.sub(one, lv.max_ge); + let rm = eval.mul(lv.max_ge, lv.abs_code); // prev = 0 + eval.constraint_first_row_eq(lv.run_max, rm); + let abs_p1 = eval.add(lv.abs_code, one); + let lo = eval.mul(not_ge, abs_p1); + let slack = eval.sub(rm, lo); // ge*abs - (1-ge)*(abs+1) + let d = eval.sub(lv.max_slack, slack); + eval.constraint_first_row(d); + } + // Transition (prev = lv.run_max, but 0 at a block start so the running max resets per block): + // applied to nv's compare. + { + let not_bs = eval.sub(one, nv.is_block_start); + let prev = eval.mul(not_bs, lv.run_max); + let not_ge = eval.sub(one, nv.max_ge); + let hi = eval.mul(nv.max_ge, nv.abs_code); + let rm = eval.mad(not_ge, prev, hi); // ge*abs + (1-ge)*prev + eval.constraint_transition_eq(nv.run_max, rm); + let diff_hi = eval.sub(nv.abs_code, prev); + let a = eval.mul(nv.max_ge, diff_hi); // ge*(abs - prev) + let prev_m_abs = eval.sub(prev, nv.abs_code); + let prev_m_abs_m1 = eval.sub(prev_m_abs, one); + let b = eval.mul(not_ge, prev_m_abs_m1); // (1-ge)*(prev - abs - 1) + let slack = eval.add(a, b); + let d = eval.sub(nv.max_slack, slack); + eval.constraint_transition(d); + } + + // ============================= GROUP Q: square, normalized to 24 bits. ============================= + let sq_expect = eval.mul(lv.x_sig, lv.x_sig); + eval.constraint_eq(lv.sq_sig, sq_expect); + let sq_norm_expect = eval.mul(lv.sq_sig, lv.sq_lift); + eval.constraint_eq(lv.sq_norm, sq_norm_expect); + let sq_norm_rec = recon2(eval, lv.sq_norm_lo, lv.sq_norm_hi); + eval.constraint_eq(lv.sq_norm, sq_norm_rec); + + // ============================= GROUP A: acc chain + fold. ============================= + eval.constraint_bool(lv.acc_in_zero); + eval.constraint_bool(lv.acc_out_zero); + let acc_in_rec = recon2(eval, lv.acc_in_sig_lo, lv.acc_in_sig_hi); + eval.constraint_eq(lv.acc_in_sig, acc_in_rec); + // Per-block reset: on every block start (incl. trace row 0, always a block start), acc_in = 0. + eval.constraint_bool(lv.is_block_start); + eval.constraint_bool(lv.is_block_final); + { + let c = eval.mul(lv.is_block_start, lv.acc_in_sig); + eval.constraint(c); + let c = eval.mul(lv.is_block_start, lv.acc_in_exp); + eval.constraint(c); + let acc_in_z_m1 = eval.sub(lv.acc_in_zero, one); + let c = eval.mul(lv.is_block_start, acc_in_z_m1); + eval.constraint(c); + } + // Transition inside a block (nv NOT a block start): nv.acc_in = lv.acc_out. + { + let not_bs = eval.sub(one, nv.is_block_start); + let d = eval.sub(nv.acc_in_sig, lv.acc_out_sig); + let c = eval.mul(not_bs, d); + eval.constraint_transition(c); + let d = eval.sub(nv.acc_in_exp, lv.acc_out_exp); + let c = eval.mul(not_bs, d); + eval.constraint_transition(c); + let d = eval.sub(nv.acc_in_zero, lv.acc_out_zero); + let c = eval.mul(not_bs, d); + eval.constraint_transition(c); + } + + let nz_sq = eval.sub(one, lv.x_is_zero); + let nz_acc = eval.sub(one, lv.acc_in_zero); + // sq_msb = (1 - x_is_zero)*(2*x_eps_biased + sq_w + 13); acc_msb = (1 - acc_in_zero)*(acc_in_exp - 63). + { + let c13 = eval.u64(13); + let two_eps = eval.mul(two, lv.x_eps_biased); + let s = eval.add(two_eps, lv.sq_w); + let s = eval.add(s, c13); + let e = eval.mul(nz_sq, s); + eval.constraint_eq(lv.sq_msb, e); + let am = eval.sub(lv.acc_in_exp, c63); + let e = eval.mul(nz_acc, am); + eval.constraint_eq(lv.acc_msb, e); + } + // rel = eta - msb; attainment rel_sq*rel_acc = 0. + let rel_sq_expect = eval.sub(lv.eta, lv.sq_msb); + eval.constraint_eq(lv.rel_sq, rel_sq_expect); + let rel_acc_expect = eval.sub(lv.eta, lv.acc_msb); + eval.constraint_eq(lv.rel_acc, rel_acc_expect); + let att = eval.mul(lv.rel_sq, lv.rel_acc); + eval.constraint(att); + // far flags + two-sided slacks: slack = far*(rel - 27) + (1 - far)*(26 - rel). + for (far, rel, slack) in + [(lv.far_sq, lv.rel_sq, lv.far_sq_slack), (lv.far_acc, lv.rel_acc, lv.far_acc_slack)] + { + eval.constraint_bool(far); + let rel_m27 = eval.sub(rel, c27); + let hi = eval.mul(far, rel_m27); + let not_far = eval.sub(one, far); + let c26_m_rel = eval.sub(c26, rel); + let lo = eval.mul(not_far, c26_m_rel); + let expect = eval.add(hi, lo); + let d = eval.sub(slack, expect); + eval.constraint(d); + } + // active = (1 - far)*(1 - is_zero). + let not_far_sq = eval.sub(one, lv.far_sq); + let as_expect = eval.mul(not_far_sq, nz_sq); + eval.constraint_eq(lv.active_sq, as_expect); + let not_far_acc = eval.sub(one, lv.far_acc); + let aa_expect = eval.mul(not_far_acc, nz_acc); + eval.constraint_eq(lv.active_acc, aa_expect); + eval.constraint_bool(lv.active_sq); + eval.constraint_bool(lv.active_acc); + + // Alignment (Euclidean floor) for each term: sig*8 = aligned*pow + rem, rem + rem_bound + 1 = pow. + #[allow(clippy::type_complexity)] + let align: [(V, V, V, V, V, V, V, V, V, V, V, V, V); 2] = [ + ( + lv.active_sq, lv.sq_norm, lv.pow_sq, lv.aligned_sq, lv.aligned_sq_lo, lv.aligned_sq_hi, lv.rem_sq, + lv.rem_sq_lo, lv.rem_sq_hi, lv.rem_sq_bound, lv.rem_sq_bound_lo, lv.rem_sq_bound_hi, lv.pow_sq, + ), + ( + lv.active_acc, lv.acc_in_sig, lv.pow_acc, lv.aligned_acc, lv.aligned_acc_lo, lv.aligned_acc_hi, + lv.rem_acc, lv.rem_acc_lo, lv.rem_acc_hi, lv.rem_acc_bound, lv.rem_acc_bound_lo, lv.rem_acc_bound_hi, + lv.pow_acc, + ), + ]; + for (active, sig, pow, aligned, aligned_lo, aligned_hi, rem, rem_lo, rem_hi, rem_bound, rem_bound_lo, rem_bound_hi, _p) in + align + { + let sig8 = eval.mul(c8, sig); + let ap = eval.mul(aligned, pow); + let floor_e = eval.sub(sig8, ap); + let floor_e = eval.sub(floor_e, rem); + let c = eval.mul(active, floor_e); + eval.constraint(c); + let rs = eval.add(rem, rem_bound); + let rs = eval.add(rs, one); + let rs = eval.sub(rs, pow); + let c = eval.mul(active, rs); + eval.constraint(c); + let not_active = eval.sub(one, active); + let c = eval.mul(not_active, aligned); + eval.constraint(c); + let c = eval.mul(not_active, rem); + eval.constraint(c); + let rec = recon2(eval, aligned_lo, aligned_hi); + eval.constraint_eq(aligned, rec); + let rec = recon2(eval, rem_lo, rem_hi); + eval.constraint_eq(rem, rec); + let rec = recon2(eval, rem_bound_lo, rem_bound_hi); + eval.constraint_eq(rem_bound, rec); + } + + // Sticky bits. + let rem_sq_zero = eval.sub(one, lv.rem_sq_nz); + eval.constraint_bool(lv.rem_sq_nz); + is_zero_flag(eval, lv.rem_sq, lv.rem_sq_nz_inv, rem_sq_zero, one); + let rem_acc_zero = eval.sub(one, lv.rem_acc_nz); + eval.constraint_bool(lv.rem_acc_nz); + is_zero_flag(eval, lv.rem_acc, lv.rem_acc_nz_inv, rem_acc_zero, one); + or_flag(eval, lv.far_sq, lv.rem_sq_nz, lv.or_sq, one); + or_flag(eval, lv.far_acc, lv.rem_acc_nz, lv.or_acc, one); + let st = eval.mul(nz_sq, lv.or_sq); + eval.constraint_eq(lv.sticky_sq, st); + let st = eval.mul(nz_acc, lv.or_acc); + eval.constraint_eq(lv.sticky_acc, st); + or_flag(eval, lv.sticky_sq, lv.sticky_acc, lv.far_sticky, one); + eval.constraint_bool(lv.sticky_sq); + eval.constraint_bool(lv.sticky_acc); + eval.constraint_bool(lv.far_sticky); + + // Window sum W = aligned_sq + aligned_acc. + let w_expect = eval.add(lv.aligned_sq, lv.aligned_acc); + eval.constraint_eq(lv.w_abs, w_expect); + let w_rec = recon2(eval, lv.w_abs_lo, lv.w_abs_hi); + eval.constraint_eq(lv.w_abs, w_rec); + eval.constraint_bool(lv.w_is_zero); + is_zero_flag(eval, lv.w_abs, lv.w_abs_inv, lv.w_is_zero, one); + let nz_w = eval.sub(one, lv.w_is_zero); + + // Renormalize: W*lift = m_rz*trunc + rz_rem, rz_rem + rz_rem_bound + 1 = trunc. + let lifted = eval.mul(lv.w_abs, lv.lift_w); + let trunc = eval.mul(lv.m_rz, lv.trunc_w); + let diff = eval.sub(lifted, trunc); + let diff = eval.sub(diff, lv.rz_rem); + let c = eval.mul(nz_w, diff); + eval.constraint(c); + let rs = eval.add(lv.rz_rem, lv.rz_rem_bound); + let rs = eval.add(rs, one); + let rs = eval.sub(rs, lv.trunc_w); + let c = eval.mul(nz_w, rs); + eval.constraint(c); + let m_rz_rec = recon2(eval, lv.m_rz_lo, lv.m_rz_hi); + eval.constraint_eq(lv.m_rz, m_rz_rec); + parity_split(eval, lv.m_rz_lo, lv.rz_half, lv.rz_parity, one); + // RNE. + eval.constraint_bool(lv.gt); + let two_rem = eval.mul(two, lv.rz_rem); + { + let hi_arg = eval.sub(two_rem, lv.trunc_w); + let hi_arg = eval.sub(hi_arg, one); + let hi = eval.mul(lv.gt, hi_arg); + let not_gt = eval.sub(one, lv.gt); + let lo_arg = eval.sub(lv.trunc_w, two_rem); + let lo = eval.mul(not_gt, lo_arg); + let expect = eval.add(hi, lo); + let d = eval.sub(lv.gt_slack, expect); + eval.constraint(d); + } + eval.constraint_bool(lv.eq); + let eq_arg = eval.sub(lv.trunc_w, two_rem); + is_zero_flag(eval, eq_arg, lv.eq_inv, lv.eq, one); + or_flag(eval, lv.far_sticky, lv.rz_parity, lv.or_rs, one); + eval.constraint_bool(lv.or_rs); + eval.constraint_bool(lv.round_up); + let eqor = eval.mul(lv.eq, lv.or_rs); + let ru = eval.add(lv.gt, eqor); + eval.constraint_eq(lv.round_up, ru); + eval.constraint_bool(lv.carry); + let m_out = eval.add(lv.m_rz, lv.round_up); + let carry_arg = eval.sub(c2_24, m_out); + is_zero_flag(eval, carry_arg, lv.carry_inv, lv.carry, one); + // acc_out. + let carry_term = eval.mul(lv.carry, c2_23); + let m_out_final = eval.sub(m_out, carry_term); + let sig_core = eval.mul(nz_w, m_out_final); + eval.constraint_eq(lv.acc_out_sig, sig_core); + let acc_out_rec = recon2(eval, lv.acc_out_sig_lo, lv.acc_out_sig_hi); + eval.constraint_eq(lv.acc_out_sig, acc_out_rec); + { + let c_add = eval.u64(ACC_EXP_ADD); + let s = eval.add(lv.eta, lv.ww); + let s = eval.add(s, lv.carry); + let s = eval.add(s, c_add); + let e = eval.mul(nz_w, s); + eval.constraint_eq(lv.acc_out_exp, e); + } + // acc_out_zero = w_is_zero. + eval.constraint_eq(lv.acc_out_zero, lv.w_is_zero); + + // ============================= SCALARS: per-block constancy + block-final pins. ============= + // Scalars are constant WITHIN a block (they may jump across a block start). Gating the + // transition equality by `1 - nv.is_block_start` lets each operand row carry its own derivation. + let scalar_start = super::columns::ROW_SCALE_COL_MAP.sumsq_sig; + { + let not_bs = eval.sub(one, nv.is_block_start); + for i in scalar_start..NUM_ROW_SCALE_COLUMNS { + let d = eval.sub(nv_arr[i], lv_arr[i]); + let c = eval.mul(not_bs, d); + eval.constraint_transition(c); + } + } + // On each LIVE block's final row, sumsq = that block's acc_out and max_abs_code = its run_max. + { + let bf = lv.is_block_final; + for (scalar, acc_out) in [ + (lv.sumsq_sig, lv.acc_out_sig), + (lv.sumsq_exp, lv.acc_out_exp), + (lv.sumsq_zero, lv.acc_out_zero), + (lv.max_abs_code, lv.run_max), + ] { + let d = eval.sub(scalar, acc_out); + let c = eval.mul(bf, d); + eval.constraint(c); + } + } + + // ============================= GROUP L: entry-liveness gate. ============================= + // Per element, `dead = [ |x| >= 4*l2 ]` with `|x| = x_sig*2^(x_eps_biased-25)` and + // `4*l2 = (128+l2_m)*2^(l2_e-132)`; the aligned integer compare shifts the lower-exponent side + // up by `|s|` (FP16POW2), with `s = x_eps_biased - l2_e + 107`. The two per-side dead counts are + // then gated `64*dead_side <= rows_side*k` (eps_idle = 1/64) by a nonnegative RANGE16 slack, so + // a tile with too many dead entries on either side has no satisfying witness. + let live = eval.sub(one, lv.is_pad); + eval.constraint_bool(lv.dead); + eval.constraint_bool(lv.dead_sign); + eval.constraint_bool(lv.is_b_side); + + // L2: dead_key = s * (2*dead_sign - 1). With `dead_key` in FP16POW2's nonneg key domain this + // pins dead_key = |s| AND the sign. + let c107 = eval.u64(107); + let s = eval.sub(lv.x_eps_biased, lv.l2_e); + let s = eval.add(s, c107); + let two_sign = eval.mul(two, lv.dead_sign); + let two_sign_m1 = eval.sub(two_sign, one); + let key_expect = eval.mul(s, two_sign_m1); + let d = eval.sub(lv.dead_key, key_expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L3: dead_pow_a = dead_sign ? dead_pow : 1 = dead_sign*(dead_pow-1) + 1. + let pow_m1 = eval.sub(lv.dead_pow, one); + let sel = eval.mul(lv.dead_sign, pow_m1); + let powa_expect = eval.add(sel, one); + let d = eval.sub(lv.dead_pow_a, powa_expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L4: dead_lhs = x_sig * dead_pow_a. + let lhs_expect = eval.mul(lv.x_sig, lv.dead_pow_a); + let d = eval.sub(lv.dead_lhs, lhs_expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L5: dead_rhs = (128 + l2_m) * pow_b, pow_b = dead_pow + 1 - dead_pow_a. + let c128 = eval.u64(128); + let mb = eval.add(c128, lv.l2_m); + let pow_b = eval.add(lv.dead_pow, one); + let pow_b = eval.sub(pow_b, lv.dead_pow_a); + let rhs_expect = eval.mul(mb, pow_b); + let d = eval.sub(lv.dead_rhs, rhs_expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L6: comparison. slack = dead*(lhs-rhs) + (1-dead)*(rhs-lhs-1), slack >= 0 (3 RANGE16 limbs). + let c2_32 = eval.u64(1u64 << 32); + let lo_mid = recon2(eval, lv.dead_slack_lo, lv.dead_slack_mid); + let slack = eval.mad(lv.dead_slack_hi, c2_32, lo_mid); + let lhs_m_rhs = eval.sub(lv.dead_lhs, lv.dead_rhs); + let rhs_m_lhs = eval.sub(lv.dead_rhs, lv.dead_lhs); + let rhs_m_lhs_m1 = eval.sub(rhs_m_lhs, one); + let hi_t = eval.mul(lv.dead, lhs_m_rhs); + let not_dead = eval.sub(one, lv.dead); + let lo_t = eval.mul(not_dead, rhs_m_lhs_m1); + let expect = eval.add(hi_t, lo_t); + let d = eval.sub(slack, expect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L7: is_b_side = [operand_row_index >= num_a_rows], two-sided slack pin. + let h = eval.u64(consts.num_a_rows); + let ori_m_h = eval.sub(lv.operand_row_index, h); + let hi_b = eval.mul(lv.is_b_side, ori_m_h); + let hm1 = eval.u64(consts.num_a_rows.saturating_sub(1)); + let hm1_m_ori = eval.sub(hm1, lv.operand_row_index); + let not_b = eval.sub(one, lv.is_b_side); + let lo_b = eval.mul(not_b, hm1_m_ori); + let bexpect = eval.add(hi_b, lo_b); + let d = eval.sub(lv.b_side_slack, bexpect); + let c = eval.mul(live, d); + eval.constraint(c); + + // L8: per-side inclusive dead accumulators (side-masked global sums; frozen on padding). + // First row (always a live A-side cell start): anchor each to this row's own contribution. + let not_b0 = eval.sub(one, lv.is_b_side); + let contrib_a0 = eval.mul(not_b0, lv.dead); + let d = eval.sub(lv.dead_run_a, contrib_a0); + eval.constraint_first_row(d); + let contrib_b0 = eval.mul(lv.is_b_side, lv.dead); + let d = eval.sub(lv.dead_run_b, contrib_b0); + eval.constraint_first_row(d); + // Transition: add the NEXT row's masked contribution. + let live_next = eval.sub(one, nv.is_pad); + let not_b_next = eval.sub(one, nv.is_b_side); + let mask_a = eval.mul(live_next, not_b_next); + let add_a = eval.mul(mask_a, nv.dead); + let step_a = eval.add(lv.dead_run_a, add_a); + let d = eval.sub(nv.dead_run_a, step_a); + eval.constraint_transition(d); + let mask_b = eval.mul(live_next, nv.is_b_side); + let add_b = eval.mul(mask_b, nv.dead); + let step_b = eval.add(lv.dead_run_b, add_b); + let d = eval.sub(nv.dead_run_b, step_b); + eval.constraint_transition(d); + + // L9: last-row per-side gates `rows_side*k - 64*dead_side = slack >= 0` (RANGE16 limbs). + let c64 = eval.u64(64); + let a_rhs = eval.u64(consts.a_gate_rhs); + let sf_a = eval.mul(c64, lv.dead_run_a); + let gate_a = eval.sub(a_rhs, sf_a); + let a_slack = recon2(eval, lv.a_gate_slack_lo, lv.a_gate_slack_hi); + let d = eval.sub(gate_a, a_slack); + eval.constraint_last_row(d); + let b_rhs = eval.u64(consts.b_gate_rhs); + let sf_b = eval.mul(c64, lv.dead_run_b); + let gate_b = eval.sub(b_rhs, sf_b); + let b_slack = recon2(eval, lv.b_gate_slack_lo, lv.b_gate_slack_hi); + let d = eval.sub(gate_b, b_slack); + eval.constraint_last_row(d); + + eval_scale_chain(lv, eval, consts); +} + +/// The scalar norm + scale chain (groups V/S/C/G/F/L/H). All columns are constant across rows, so +/// these apply on every row (ungated) and reference only scalar columns. +fn eval_scale_chain(lv: &RowScaleColumnsView, eval: &mut E, consts: ScaleConsts) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + let two = eval.u64(2); + let c4 = eval.u64(4); + let c128 = eval.u64(128); + let c2_7 = eval.u64(1 << 7); + let c2_16 = eval.u64(1 << 16); + let c2_23 = eval.u64(1 << 23); + let c6 = eval.u64(6); + let c134 = eval.u64(BF16_UNIT); + let floor = eval.u64(FLOOR_CODE); + let k = eval.u64(consts.k); + let dr_m = eval.u64(consts.dr_m); + let dr_e = eval.u64(consts.dr_e); + let dos_m = eval.u64(consts.dos_m); + let dos_e = eval.u64(consts.dos_e); + + let recon2l = |eval: &mut E, lo: V, hi: V| -> V { + let c = eval.u64(1 << 16); + eval.mad(hi, c, lo) + }; + let recon3l = |eval: &mut E, lo: V, mid: V, hi: V| -> V { + let c16 = eval.u64(1 << 16); + let c32 = eval.u64(1 << 32); + let a = eval.mul(hi, c32); + let b = eval.mul(mid, c16); + let s = eval.add(a, b); + eval.add(s, lo) + }; + + // ---- sumsq / q limb reconstructions + zero flags. ---- + let sumsq_rec = recon2l(eval, lv.sumsq_sig_lo, lv.sumsq_sig_hi); + eval.constraint_eq(lv.sumsq_sig, sumsq_rec); + eval.constraint_bool(lv.sumsq_zero); + eval.constraint_bool(lv.q_zero); + // q_zero = sumsq_zero (q = 0 iff sumsq = 0). + eval.constraint_eq(lv.q_zero, lv.sumsq_zero); + let nz = eval.sub(one, lv.q_zero); + let q_rec = recon2l(eval, lv.q_sig_lo, lv.q_sig_hi); + eval.constraint_eq(lv.q_sig, q_rec); + // Zero branch: q_sig = 0. + let c = eval.mul(lv.q_zero, lv.q_sig); + eval.constraint(c); + + // ============================= GROUP V: q = RNE_f32(sumsq / k). ============================= + // q_dexp = sumsq_exp - q_exp. + { + let d = eval.sub(lv.sumsq_exp, lv.q_exp); + let diff = eval.sub(lv.q_dexp, d); + let c = eval.mul(nz, diff); + eval.constraint(c); + } + eval.constraint_bool(lv.q_bottom); + is_zero_flag_scaled(eval, lv.q_sig, c2_23, lv.q_bottom_inv, lv.q_bottom, nz); + parity_split_scaled(eval, lv.q_sig_lo, lv.q_half, lv.q_parity, nz); + // q_blo = (4*q_sig - 2 + q_bottom)*k; q_bhi = (4*q_sig + 2)*k. + let four_q = eval.mul(c4, lv.q_sig); + { + let lo_coef = eval.sub(four_q, two); + let lo_coef = eval.add(lo_coef, lv.q_bottom); + let blo = eval.mul(lo_coef, k); + let d = eval.sub(lv.q_blo, blo); + let c = eval.mul(nz, d); + eval.constraint(c); + let hi_coef = eval.add(four_q, two); + let bhi = eval.mul(hi_coef, k); + let d = eval.sub(lv.q_bhi, bhi); + let c = eval.mul(nz, d); + eval.constraint(c); + } + // target = 4*sumsq_sig*q_pow; slacks recon3. + { + let four_s = eval.mul(c4, lv.sumsq_sig); + let target = eval.mul(four_s, lv.q_pow); + let sl = recon3l(eval, lv.q_sl_lo, lv.q_sl_mid, lv.q_sl_hi); + let e = eval.sub(target, lv.q_blo); + let e = eval.sub(e, lv.q_parity); + let d = eval.sub(sl, e); + let c = eval.mul(nz, d); + eval.constraint(c); + let su = recon3l(eval, lv.q_su_lo, lv.q_su_mid, lv.q_su_hi); + let e = eval.sub(lv.q_bhi, target); + let e = eval.sub(e, lv.q_parity); + let d = eval.sub(su, e); + let c = eval.mul(nz, d); + eval.constraint(c); + } + + // ============================= GROUP S: s = RNE_f32(sqrt(q)). ============================= + let s_rec = recon2l(eval, lv.s_sig_lo, lv.s_sig_hi); + eval.constraint_eq(lv.s_sig, s_rec); + let c = eval.mul(lv.q_zero, lv.s_sig); + eval.constraint(c); + // s_dexp = q_exp + 152 - 2*s_exp. + { + let c152 = eval.u64(152); + let two_se = eval.mul(two, lv.s_exp); + let d = eval.add(lv.q_exp, c152); + let d = eval.sub(d, two_se); + let diff = eval.sub(lv.s_dexp, d); + let c = eval.mul(nz, diff); + eval.constraint(c); + } + eval.constraint_bool(lv.s_bottom); + is_zero_flag_scaled(eval, lv.s_sig, c2_23, lv.s_bottom_inv, lv.s_bottom, nz); + parity_split_scaled(eval, lv.s_sig_lo, lv.s_half, lv.s_parity, nz); + // s_blo = (4*s_sig - 2 + s_bottom)^2; s_bhi = (4*s_sig + 2)^2. + let four_s_sig = eval.mul(c4, lv.s_sig); + { + let lo_b = eval.sub(four_s_sig, two); + let lo_b = eval.add(lo_b, lv.s_bottom); + let sq = eval.mul(lo_b, lo_b); + let d = eval.sub(lv.s_blo, sq); + let c = eval.mul(nz, d); + eval.constraint(c); + let hi_b = eval.add(four_s_sig, two); + let sq = eval.mul(hi_b, hi_b); + let d = eval.sub(lv.s_bhi, sq); + let c = eval.mul(nz, d); + eval.constraint(c); + } + // target = 4*q_sig*s_pow; slacks recon3. + { + let four_q = eval.mul(c4, lv.q_sig); + let target = eval.mul(four_q, lv.s_pow); + let sl = recon3l(eval, lv.s_sl_lo, lv.s_sl_mid, lv.s_sl_hi); + let e = eval.sub(target, lv.s_blo); + let e = eval.sub(e, lv.s_parity); + let d = eval.sub(sl, e); + let c = eval.mul(nz, d); + eval.constraint(c); + let su = recon3l(eval, lv.s_su_lo, lv.s_su_mid, lv.s_su_hi); + let e = eval.sub(lv.s_bhi, target); + let e = eval.sub(e, lv.s_parity); + let d = eval.sub(su, e); + let c = eval.mul(nz, d); + eval.constraint(c); + } + + // ============================= GROUP C: l2raw = f32_to_bf16(s). ============================= + round24to8_constraints( + eval, lv.s_sig, lv.s_exp, lv.l2raw_mant, lv.l2raw_exp, lv.l2raw_carry, lv.l2raw_bottom, + lv.l2raw_bottom_inv, lv.l2raw_parity, lv.l2raw_half, lv.l2raw_blo, lv.l2raw_bhi, lv.l2raw_sl_lo, + lv.l2raw_sl_hi, lv.l2raw_su_lo, lv.l2raw_su_hi, lv.l2raw_code, nz, + ); + // Zero branch: l2raw_code = 0. + let c = eval.mul(lv.q_zero, lv.l2raw_code); + eval.constraint(c); + + // ============================= GROUP G: l2grid = round_l2_to_grid(l2raw). ============================= + eval.constraint_bool(lv.grid_r_b0); + eval.constraint_bool(lv.grid_r_b1); + let two_b1 = eval.mul(two, lv.grid_r_b1); + let gr = eval.add(two_b1, lv.grid_r_b0); + eval.constraint_eq(lv.grid_r, gr); + // l2raw_code + 2 = 4*grid_q + grid_r. + { + let lhs = eval.add(lv.l2raw_code, two); + let four_q = eval.mul(c4, lv.grid_q); + let rhs = eval.add(four_q, lv.grid_r); + eval.constraint_eq(lhs, rhs); + } + let l2grid = eval.mul(c4, lv.grid_q); + eval.constraint_eq(lv.l2grid_code, l2grid); + + // ============================= GROUP F: l2 = bf16_max(l2grid, floor). ============================= + max_with_floor(eval, lv.l2grid_code, floor, lv.l2_ge, lv.l2_floor_slack, lv.l2_code); + // l2_code = 128*l2_e + l2_m. + let l2_rec = eval.mad(lv.l2_e, c2_7, lv.l2_m); + eval.constraint_eq(lv.l2_code, l2_rec); + + // ============================= GROUP L: linf = bf16_max(f32_to_bf16(max|x|), floor). ============================= + eval.constraint_bool(lv.max_is_zero); + let nz_max = eval.sub(one, lv.max_is_zero); + let max_norm_rec = recon2l(eval, lv.max_norm_lo, lv.max_norm_hi); + eval.constraint_eq(lv.max_norm, max_norm_rec); + // max_norm = max_sig * max_lift (0 when max is zero). + let mn = eval.mul(lv.max_sig, lv.max_lift); + eval.constraint_eq(lv.max_norm, mn); + // base_exp = max_eps_biased + max_w + 101. + let base_exp = { + let c101 = eval.u64(101); + let s = eval.add(lv.max_eps_biased, lv.max_w); + eval.add(s, c101) + }; + round24to8_constraints( + eval, lv.max_norm, base_exp, lv.linf_raw_mant, lv.linf_raw_exp, lv.linf_raw_carry, lv.linf_raw_bottom, + lv.linf_raw_bottom_inv, lv.linf_raw_parity, lv.linf_raw_half, lv.linf_raw_blo, lv.linf_raw_bhi, + lv.linf_raw_sl_lo, lv.linf_raw_sl_hi, lv.linf_raw_su_lo, lv.linf_raw_su_hi, lv.linf_raw_code, nz_max, + ); + let c = eval.mul(lv.max_is_zero, lv.linf_raw_code); + eval.constraint(c); + max_with_floor(eval, lv.linf_raw_code, floor, lv.linf_ge, lv.linf_floor_slack, lv.linf_code); + let linf_rec = eval.mad(lv.linf_e, c2_7, lv.linf_m); + eval.constraint_eq(lv.linf_code, linf_rec); + + // ============================= GROUP H1: noised_bound = bf16_fma(dr, l2, linf). ============================= + let l2_sig = eval.add(c128, lv.l2_m); + let linf_sig = eval.add(c128, lv.linf_m); + // nb_prod = dr_m * l2_sig. + let nb_prod = eval.mul(dr_m, l2_sig); + eval.constraint_eq(lv.nb_prod, nb_prod); + // nb_shift = linf_e - l2_e + 6. + { + let d = eval.sub(lv.linf_e, lv.l2_e); + let d = eval.add(d, c6); + eval.constraint_eq(lv.nb_shift, d); + } + // nb_w = nb_prod + linf_sig * nb_shiftpow. + let add = eval.mul(linf_sig, lv.nb_shiftpow); + let nb_w = eval.add(lv.nb_prod, add); + eval.constraint_eq(lv.nb_w, nb_w); + let nb_w_rec = recon2l(eval, lv.nb_w_lo, lv.nb_w_hi); + eval.constraint_eq(lv.nb_w, nb_w_rec); + // Round W to 8 bits: M_out = 128 + nb_mant, bracket on 4*W with 2^nb_gm. + let nb_m = eval.add(c128, lv.nb_mant); + eval.constraint_bool(lv.nb_bottom); + is_zero_flag(eval, lv.nb_mant, lv.nb_bottom_inv, lv.nb_bottom, one); + parity_split_scaled(eval, lv.nb_mant, lv.nb_half, lv.nb_parity, one); + let four_m = eval.mul(c4, nb_m); + { + let lo_coef = eval.sub(four_m, two); + let lo_coef = eval.add(lo_coef, lv.nb_bottom); + let blo = eval.mul(lo_coef, lv.nb_pow); + eval.constraint_eq(lv.nb_blo, blo); + let hi_coef = eval.add(four_m, two); + let bhi = eval.mul(hi_coef, lv.nb_pow); + eval.constraint_eq(lv.nb_bhi, bhi); + } + { + let four_w = eval.mul(c4, lv.nb_w); + let sl = recon2l(eval, lv.nb_sl_lo, lv.nb_sl_hi); + let e = eval.sub(four_w, lv.nb_blo); + let e = eval.sub(e, lv.nb_parity); + eval.constraint_eq(sl, e); + let su = recon2l(eval, lv.nb_su_lo, lv.nb_su_hi); + let e = eval.sub(lv.nb_bhi, four_w); + let e = eval.sub(e, lv.nb_parity); + eval.constraint_eq(su, e); + } + // nb_exp = (dr_e + l2_e) + nb_gm - 134; nb_code = 128*nb_exp + nb_mant. + { + let base = eval.add(dr_e, lv.l2_e); + let s = eval.add(base, lv.nb_gm); + let s = eval.sub(s, c134); + eval.constraint_eq(lv.nb_exp, s); + } + let nb_code = eval.mad(lv.nb_exp, c2_7, lv.nb_mant); + eval.constraint_eq(lv.nb_code, nb_code); + + // ============================= GROUP H3: alpha = bf16_div(2^16, noised_bound). ============================= + let alpha_m = eval.add(c128, lv.alpha_mant); + eval.constraint_bool(lv.alpha_bottom); + is_zero_flag(eval, lv.alpha_mant, lv.alpha_bottom_inv, lv.alpha_bottom, one); + parity_split_scaled(eval, lv.alpha_mant, lv.alpha_half, lv.alpha_parity, one); + let four_a = eval.mul(c4, alpha_m); + { + let lo_coef = eval.sub(four_a, two); + let lo_coef = eval.add(lo_coef, lv.alpha_bottom); + let blo = eval.mul(lo_coef, nb_m); + eval.constraint_eq(lv.alpha_blo, blo); + let hi_coef = eval.add(four_a, two); + let bhi = eval.mul(hi_coef, nb_m); + eval.constraint_eq(lv.alpha_bhi, bhi); + } + { + // alpha_pow = 2^A; slack sl = alpha_pow - alpha_blo - alpha_parity, su = alpha_bhi - alpha_pow - alpha_parity. + let e = eval.sub(lv.alpha_pow, lv.alpha_blo); + let e = eval.sub(e, lv.alpha_parity); + eval.constraint_eq(lv.alpha_sl, e); + let e = eval.sub(lv.alpha_bhi, lv.alpha_pow); + let e = eval.sub(e, lv.alpha_parity); + eval.constraint_eq(lv.alpha_su, e); + } + let alpha_code = eval.mad(lv.alpha_exp, c2_7, lv.alpha_mant); + eval.constraint_eq(lv.alpha_code, alpha_code); + + // ============================= GROUP H4/H5: m1 = alpha*l2; beta = m1*dos. ============================= + bf16_mul_constraints( + eval, alpha_m, lv.alpha_exp, l2_sig, lv.l2_e, lv.m1_prod, lv.m1_mant, lv.m1_exp, lv.m1_bottom, + lv.m1_bottom_inv, lv.m1_parity, lv.m1_half, lv.m1_pow, lv.m1_gm, lv.m1_blo, lv.m1_bhi, lv.m1_sl, lv.m1_su, + lv.m1_code, + ); + let m1_sig = eval.add(c128, lv.m1_mant); + bf16_mul_constraints( + eval, m1_sig, lv.m1_exp, dos_m, dos_e, lv.beta_prod, lv.beta_mant, lv.beta_exp, lv.beta_bottom, + lv.beta_bottom_inv, lv.beta_parity, lv.beta_half, lv.beta_pow, lv.beta_gm, lv.beta_blo, lv.beta_bhi, + lv.beta_sl, lv.beta_su, lv.beta_code, + ); + + let _ = (c2_16, c2_7); +} + +/// `flag = [x == scaled]` is-zero gadget on the difference `x - scaled` (`scaled` a constant/value). +fn is_zero_flag_scaled(eval: &mut E, x: V, scaled: V, inv: V, flag: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let arg = eval.sub(x, scaled); + is_zero_flag(eval, arg, inv, flag, gate); +} + +/// `mant = 2*half + parity`, parity boolean, gated. +fn parity_split_scaled(eval: &mut E, mant: V, half: V, parity: V, gate: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + parity_split(eval, mant, half, parity, gate); +} + +/// `out = max(x, floor)` by code order: `ge` boolean, two-sided slack, `out = ge*x + (1-ge)*floor`. +fn max_with_floor(eval: &mut E, x: V, floor: V, ge: V, slack: V, out: V) +where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + eval.constraint_bool(ge); + let not_ge = eval.sub(one, ge); + // slack = ge*(x - floor) + (1-ge)*(floor - x - 1). + let x_m_f = eval.sub(x, floor); + let hi = eval.mul(ge, x_m_f); + let f_m_x = eval.sub(floor, x); + let f_m_x_m1 = eval.sub(f_m_x, one); + let lo = eval.mul(not_ge, f_m_x_m1); + let expect = eval.add(hi, lo); + let d = eval.sub(slack, expect); + eval.constraint(d); + // out = ge*x + (1-ge)*floor. + let a = eval.mul(ge, x); + let b = eval.mul(not_ge, floor); + let o = eval.add(a, b); + eval.constraint_eq(out, o); +} + +/// Round a 24-bit significand `sig24` to the 8-bit bf16 significand at the fixed shift 16 (with a +/// mantissa-overflow carry): `M_pre = 128 + mant + 128*carry`, bracket `(4*M_pre -2 +bottom)*2^16 <= +/// 4*sig24 <= (4*M_pre+2)*2^16`, `out_exp = base_exp + carry`, `code = 128*out_exp + mant`. Gated. +#[allow(clippy::too_many_arguments)] +fn round24to8_constraints( + eval: &mut E, sig24: V, base_exp: V, mant: V, exp: V, carry: V, bottom: V, bottom_inv: V, parity: V, half: V, + blo: V, bhi: V, sl_lo: V, sl_hi: V, su_lo: V, su_hi: V, code: V, gate: V, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let two = eval.u64(2); + let c4 = eval.u64(4); + let c128 = eval.u64(128); + let c2_7 = eval.u64(1 << 7); + let c2_16 = eval.u64(1 << 16); + eval.constraint_bool(carry); + // carry => mant = 0. + let cm = eval.mul(carry, mant); + let c = eval.mul(gate, cm); + eval.constraint(c); + // M_pre = 128 + mant + 128*carry. + let c128_carry = eval.mul(c128, carry); + let m_pre = eval.add(c128, mant); + let m_pre = eval.add(m_pre, c128_carry); + // bottom = [M_pre == 128] = [mant + 128*carry == 0]. + let mpre_rel = eval.sub(m_pre, c128); + eval.constraint_bool(bottom); + is_zero_flag(eval, mpre_rel, bottom_inv, bottom, gate); + // parity split on M_pre. + parity_split(eval, m_pre, half, parity, gate); + // blo = (4*M_pre - 2 + bottom)*2^16; bhi = (4*M_pre + 2)*2^16. + let four_m = eval.mul(c4, m_pre); + let lo_coef = eval.sub(four_m, two); + let lo_coef = eval.add(lo_coef, bottom); + let blo_e = eval.mul(lo_coef, c2_16); + let d = eval.sub(blo, blo_e); + let c = eval.mul(gate, d); + eval.constraint(c); + let hi_coef = eval.add(four_m, two); + let bhi_e = eval.mul(hi_coef, c2_16); + let d = eval.sub(bhi, bhi_e); + let c = eval.mul(gate, d); + eval.constraint(c); + // sl = 4*sig24 - blo - parity; su = bhi - 4*sig24 - parity. + let four_s = eval.mul(c4, sig24); + let sl = eval.mad(sl_hi, c2_16, sl_lo); + let e = eval.sub(four_s, blo); + let e = eval.sub(e, parity); + let d = eval.sub(sl, e); + let c = eval.mul(gate, d); + eval.constraint(c); + let su = eval.mad(su_hi, c2_16, su_lo); + let e = eval.sub(bhi, four_s); + let e = eval.sub(e, parity); + let d = eval.sub(su, e); + let c = eval.mul(gate, d); + eval.constraint(c); + // out_exp = base_exp + carry. + let oe = eval.add(base_exp, carry); + let d = eval.sub(exp, oe); + let c = eval.mul(gate, d); + eval.constraint(c); + // code = 128*exp + mant. + let code_e = eval.mad(exp, c2_7, mant); + let d = eval.sub(code, code_e); + let c = eval.mul(gate, d); + eval.constraint(c); +} + +/// `out = RNE_bf16(a*b)` for normal positive operands: `P = a_sig*b_sig`, rounded to the 8-bit +/// significand at `2^gm` (FP16POW2, pinned via `mant in [0,127]`), `out_exp = a_e + b_e + gm - 134`. +#[allow(clippy::too_many_arguments)] +fn bf16_mul_constraints( + eval: &mut E, a_sig: V, a_e: V, b_sig: V, b_e: V, prod: V, mant: V, exp: V, bottom: V, bottom_inv: V, parity: V, + half: V, pow: V, gm: V, blo: V, bhi: V, sl: V, su: V, code: V, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let one = eval.u64(1); + let two = eval.u64(2); + let c4 = eval.u64(4); + let c128 = eval.u64(128); + let c2_7 = eval.u64(1 << 7); + let c134 = eval.u64(BF16_UNIT); + let p = eval.mul(a_sig, b_sig); + eval.constraint_eq(prod, p); + let m_out = eval.add(c128, mant); + eval.constraint_bool(bottom); + is_zero_flag(eval, mant, bottom_inv, bottom, one); + parity_split(eval, mant, half, parity, one); + let four_m = eval.mul(c4, m_out); + let lo_coef = eval.sub(four_m, two); + let lo_coef = eval.add(lo_coef, bottom); + let blo_e = eval.mul(lo_coef, pow); + eval.constraint_eq(blo, blo_e); + let hi_coef = eval.add(four_m, two); + let bhi_e = eval.mul(hi_coef, pow); + eval.constraint_eq(bhi, bhi_e); + let four_p = eval.mul(c4, prod); + let e = eval.sub(four_p, blo); + let e = eval.sub(e, parity); + eval.constraint_eq(sl, e); + let e = eval.sub(bhi, four_p); + let e = eval.sub(e, parity); + eval.constraint_eq(su, e); + // out_exp = a_e + b_e + gm - 134 (gm is the FP16POW2 key tying `pow = 2^gm` in ctl). + let base = eval.add(a_e, b_e); + let base = eval.add(base, gm); + let base = eval.sub(base, c134); + eval.constraint_eq(exp, base); + // code = 128*exp + mant. + let code_e = eval.mad(exp, c2_7, mant); + eval.constraint_eq(code, code_e); +} + +/// FP16 RowScaleStark. A CTL party (`requires_ctls`): the FP16-batch LUT facts and the +/// operand/scales hooks are CTL-bound in later stages, so the batch driver is the only supported +/// proving path. +#[derive(Clone, Debug)] +pub struct RowScaleStark, const D: usize> { + pub program: RowScaleProgram, + _phantom: PhantomData, +} + +impl, const D: usize> RowScaleStark { + pub fn new(program: RowScaleProgram) -> Self { + Self { program, _phantom: PhantomData } + } + + fn scale_consts(&self) -> ScaleConsts { + let dr = u64::from(self.program.dr_code()); + let dos = u64::from(self.program.dos_code()); + let h = self.program.num_a_rows as u64; + let w = (self.program.num_operand_rows - self.program.num_a_rows) as u64; + let k = self.program.k as u64; + ScaleConsts { + k, + dr_m: 128 + (dr & 0x7F), + dr_e: dr >> 7, + dos_m: 128 + (dos & 0x7F), + dos_e: dos >> 7, + num_a_rows: h, + a_gate_rhs: h * k, + b_gate_rhs: w * k, + } + } +} + +impl, const D: usize> Stark for RowScaleStark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_ROW_SCALE_COLUMNS, NUM_ROW_SCALE_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_row_scale_constraints(vars, &mut evaluator, self.scale_consts()); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_row_scale_constraints(vars, &mut evaluator, self.scale_consts()); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + + use super::super::columns::ROW_SCALE_COL_MAP; + use super::*; + use crate::api::fp16::dtype::f32_to_fp16; + use crate::api::fp16::quantization::{derive_row_scales, row_norms}; + use crate::api::fp8::compute::bf16_max; + + const D: usize = 2; + type F = GoldilocksField; + type Stk = RowScaleStark; + + const R: usize = 32; + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + fn constraints_violated(stark: &Stk, rows: &[[F; NUM_ROW_SCALE_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().iter().any(|&acc| acc != F::ZERO) + }) + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + for (k, seed, scale) in [(64usize, 1u64, 4.0f32), (48, 7, 0.5), (96, 11, 20.0), (32, 3, 1.0), (16, 9, 0.01)] { + let program = RowScaleProgram::new(k, R); + let row = sample_row(k, seed, scale); + let rows = program.generate_trace::(&row); + assert!( + !constraints_violated(&Stk::new(program), &rows), + "honest trace violated a constraint (k={k} seed={seed} scale={scale})" + ); + } + } + + #[test] + fn degree_is_at_most_three() { + use starky::stark_testing::test_stark_low_degree; + let program = RowScaleProgram::new(32, R); + test_stark_low_degree::(Stk::new(program)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::test_stark_circuit_constraints; + let program = RowScaleProgram::new(32, R); + test_stark_circuit_constraints::(Stk::new(program)).unwrap(); + } + + #[test] + fn honest_floor_trace_satisfies_constraints() { + let k = 32; + let program = RowScaleProgram::new(k, R); + let rows = program.generate_trace::(&vec![0u16; k]); + assert!(!constraints_violated(&Stk::new(program), &rows), "all-zero row trace must pass"); + } + + #[test] + fn tampered_traces_fail() { + let k = 48; + let program = RowScaleProgram::new(k, R); + let row = sample_row(k, 7, 3.0); + let rows = program.generate_trace::(&row); + let stark = Stk::new(program); + assert!(!constraints_violated(&stark, &rows), "baseline honest trace must pass"); + let m = &ROW_SCALE_COL_MAP; + for (name, col) in [ + ("code", m.code), + ("abs_code", m.abs_code), + ("run_max", m.run_max), + ("sq_sig", m.sq_sig), + ("sq_norm", m.sq_norm), + ("acc_out_sig", m.acc_out_sig), + ("acc_out_exp", m.acc_out_exp), + ("w_abs", m.w_abs), + ("m_rz", m.m_rz), + ("round_up", m.round_up), + ("eta", m.eta), + ("sumsq_sig", m.sumsq_sig), + ("q_sig", m.q_sig), + ("q_blo", m.q_blo), + ("s_sig", m.s_sig), + ("s_blo", m.s_blo), + ("l2raw_code", m.l2raw_code), + ("l2grid_code", m.l2grid_code), + ("l2_code", m.l2_code), + ("linf_raw_code", m.linf_raw_code), + ("linf_code", m.linf_code), + ("nb_prod", m.nb_prod), + ("nb_w", m.nb_w), + ("nb_code", m.nb_code), + ("alpha_code", m.alpha_code), + ("alpha_blo", m.alpha_blo), + ("m1_code", m.m1_code), + ("beta_code", m.beta_code), + ] { + let mut forged = rows.clone(); + forged[0][col] += F::ONE; + assert!(constraints_violated(&stark, &forged), "{name} tamper undetected"); + } + } + + /// Binade-bottom uniqueness: find a trace with a power-of-two bf16 multiply (`m1_bottom` or + /// `beta_bottom` set), then show (a) clearing the flag violates the is-zero gadget and (b) + /// reverting the lower boundary to the uncorrected `(4*M - 2)*pow` (one `pow` below the honest + /// `+ BOTTOM` value) is rejected — the ties-to-even rounding is pinned with no quarter-ulp slack. + #[test] + fn binade_bottom_correction_pins_the_rounding() { + let m = &ROW_SCALE_COL_MAP; + // An all-ones row: mean square = 1, sqrt = 1, so l2raw = f32_to_bf16(1.0) = 0x3F80, a power + // of two (significand 2^23 -> M_pre = 128). The round24to8 binade bottom fires. + let k = 32; + let program = RowScaleProgram::new(k, R); + let row = vec![f32_to_fp16(1.0).unwrap(); k]; + let rows = program.generate_trace::(&row); + let stark = Stk::new(RowScaleProgram::new(k, R)); + assert!(!constraints_violated(&stark, &rows), "honest power-of-two trace must pass"); + assert_eq!(to_u64(rows[0][m.l2raw_bottom]), 1, "l2raw is a power of two"); + assert_eq!(to_u64(rows[0][m.l2raw_code]) as u16, 0x3F80, "l2raw = 1.0"); + + // (a) Clear the bottom flag on every row (scalar column) -> is-zero gadget rejects it. + let mut f = rows.clone(); + for rr in f.iter_mut() { + rr[m.l2raw_bottom] = F::ZERO; + } + assert!(constraints_violated(&stark, &f), "clearing l2raw_bottom must be rejected"); + + // (b) Revert the lower boundary to the uncorrected `(4*M_pre - 2)*2^16` (one 2^16 below the + // honest `+ BOTTOM` value): the AIR's `blo = (... + bottom)*2^16` now rejects it. + let mut f = rows.clone(); + let factor = F::from_canonical_u64(1 << 16); + for rr in f.iter_mut() { + rr[m.l2raw_blo] -= factor; + } + assert!(constraints_violated(&stark, &f), "uncorrected half-ulp lower boundary must be rejected"); + } + + fn sample_row(k: usize, seed: u64, scale: f32) -> Vec { + let mut s = seed.wrapping_add(0x9E3779B97F4A7C15); + (0..k) + .map(|_| { + s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + let v = ((s >> 40) as i32 % 2000 - 1000) as f32 / 1000.0 * scale; + f32_to_fp16(v).unwrap() + }) + .collect() + } + + #[test] + fn trace_is_bit_exact_vs_reference() { + for (k, seed, scale) in [(64usize, 1u64, 4.0f32), (48, 7, 0.5), (96, 11, 20.0), (32, 3, 1.0)] { + let row = sample_row(k, seed, scale); + let program = RowScaleProgram::new(k, R); + let rows = program.generate_trace::(&row); + assert_eq!(rows.len(), k.next_power_of_two().max(2)); + + let (ref_l2grid, ref_linf_raw) = row_norms(&row).unwrap(); + let floor = f32_to_bf16(NORM_FLOOR).unwrap(); + let l2 = bf16_max(ref_l2grid, floor); + let linf = bf16_max(ref_linf_raw, floor); + let (alpha, beta) = derive_row_scales(l2, linf, R).unwrap(); + + let v: &RowScaleColumnsView = rows[0].borrow(); + assert_eq!(to_u64(v.l2grid_code) as u16, ref_l2grid, "l2grid k={k} seed={seed}"); + assert_eq!(to_u64(v.linf_raw_code) as u16, ref_linf_raw, "linf_raw k={k} seed={seed}"); + assert_eq!(to_u64(v.l2_code) as u16, l2, "l2 k={k} seed={seed}"); + assert_eq!(to_u64(v.linf_code) as u16, linf, "linf k={k} seed={seed}"); + assert_eq!(to_u64(v.alpha_code) as u16, alpha, "alpha k={k} seed={seed}"); + assert_eq!(to_u64(v.beta_code) as u16, beta, "beta k={k} seed={seed}"); + } + } + + #[test] + fn floor_case_all_zero_row() { + let k = 32; + let row = vec![0u16; k]; + let program = RowScaleProgram::new(k, R); + let rows = program.generate_trace::(&row); + let (ref_l2grid, ref_linf_raw) = row_norms(&row).unwrap(); + let floor = f32_to_bf16(NORM_FLOOR).unwrap(); + let l2 = bf16_max(ref_l2grid, floor); + let linf = bf16_max(ref_linf_raw, floor); + let (alpha, beta) = derive_row_scales(l2, linf, R).unwrap(); + let v: &RowScaleColumnsView = rows[0].borrow(); + assert_eq!(to_u64(v.l2_code) as u16, l2, "floored l2"); + assert_eq!(to_u64(v.linf_code) as u16, linf, "floored linf"); + assert_eq!(to_u64(v.alpha_code) as u16, alpha, "alpha"); + assert_eq!(to_u64(v.beta_code) as u16, beta, "beta"); + assert_eq!(l2, floor); + assert_eq!(linf, floor); + } + + #[test] + fn known_column_matches_fill() { + let k = 48; + let program = RowScaleProgram::new(k, R); + let row = sample_row(k, 5, 2.0); + let rows = program.generate_trace::(&row); + let known = program.known_values::(); + assert_eq!(known.len(), 4); + for (r, row) in rows.iter().enumerate() { + for (j, col) in [ + ROW_SCALE_COL_MAP.is_pad, + ROW_SCALE_COL_MAP.operand_row_index, + ROW_SCALE_COL_MAP.is_block_start, + ROW_SCALE_COL_MAP.is_block_final, + ] + .into_iter() + .enumerate() + { + assert_eq!(known[j].values[r], row[col], "known col {j} row {r}"); + } + } + } + + /// The extended multi-operand-row path: several rows of `k` elements proved end to end, each a + /// self-contained per-row derivation bit-exact with the reference, plus a trailing padding block. + #[test] + fn multi_row_trace_is_bit_exact_and_satisfies_constraints() { + use crate::api::fp16::quantization::{derive_row_scales, row_norms}; + use crate::api::fp8::compute::bf16_max; + let k = 32usize; + let num_operand_rows = 6usize; // e.g. h=2, w=4 + let num_rows = (num_operand_rows * k).next_power_of_two(); // 192 -> 256 + let program = RowScaleProgram::with_rows(num_operand_rows, k, R, num_rows); + let mut codes = Vec::new(); + for i in 0..num_operand_rows { + codes.extend(sample_row(k, 1 + i as u64, 0.25 + i as f32)); + } + let rows = program.generate_trace::(&codes); + assert_eq!(rows.len(), num_rows); + assert!(!constraints_violated(&Stk::new(program), &rows), "multi-row honest trace must pass"); + + let floor = f32_to_bf16(NORM_FLOOR).unwrap(); + for i in 0..num_operand_rows { + let row = &codes[i * k..(i + 1) * k]; + let (ref_l2grid, ref_linf_raw) = row_norms(row).unwrap(); + let l2 = bf16_max(ref_l2grid, floor); + let linf = bf16_max(ref_linf_raw, floor); + let (alpha, beta) = derive_row_scales(l2, linf, R).unwrap(); + // Every live row of block i carries that row's scalars. + let v: &RowScaleColumnsView = rows[i * k].borrow(); + assert_eq!(to_u64(v.alpha_code) as u16, alpha, "alpha row {i}"); + assert_eq!(to_u64(v.beta_code) as u16, beta, "beta row {i}"); + assert_eq!(to_u64(v.operand_row_index) as usize, i, "operand_row_index row {i}"); + } + } + + // ---- Entry-liveness gate (group L) ---- + + /// Build the A-then-B row_scale program + trace for an `h x w x k` tile. + fn liveness_trace(h: usize, w: usize, k: usize, a: &[u16], b: &[u16]) -> (Stk, Vec<[F; NUM_ROW_SCALE_COLUMNS]>) { + let num_rows = ((h + w) * k).next_power_of_two(); + let program = RowScaleProgram::with_rows_ab(h, w, k, R, num_rows); + let mut codes = a.to_vec(); + codes.extend_from_slice(b); + let rows = program.generate_trace::(&codes); + (Stk::new(program), rows) + } + + /// The oracle decision from the plaintext `check_shared_gates` (noise irrelevant to the scales). + fn oracle_accepts(h: usize, w: usize, k: usize, a: &[u16], b: &[u16]) -> bool { + use crate::api::fp16::policy::check_shared_gates; + use crate::api::fp16::quantization::{noisy_quantize, row_norms}; + let norms_a: Vec<_> = (0..h).map(|i| row_norms(&a[i * k..i * k + k]).unwrap()).collect(); + let norms_b: Vec<_> = (0..w).map(|j| row_norms(&b[j * k..j * k + k]).unwrap()).collect(); + let ba = noisy_quantize(a, &vec![0u16; h * R], &vec![0u16; k * R], &norms_a, R).unwrap(); + let bb = noisy_quantize(b, &vec![0u16; w * R], &vec![0u16; k * R], &norms_b, R).unwrap(); + check_shared_gates(a, &ba, b, &bb, k).is_ok() + } + + /// The circuit gate accepts EXACTLY the tiles `check_shared_gates` accepts: an honest + /// spread-magnitude tile (no dead entries) passes, and a spike-dominated tile (dead fraction + /// above eps_idle = 1/64 on the A side) makes the gate unsatisfiable. + #[test] + fn liveness_gate_matches_check_shared_gates() { + let (h, w, k) = (4usize, 16usize, 64usize); + + // Honest: spread magnitudes, |x| < 4*rms everywhere -> 0 dead. + let a: Vec = (0..h).flat_map(|i| sample_row(k, 100 + i as u64, 3.0)).collect(); + let b: Vec = (0..w).flat_map(|j| sample_row(k, 500 + j as u64, 3.0)).collect(); + assert!(oracle_accepts(h, w, k, &a, &b), "honest tile must be oracle-admissible"); + let (stk, rows) = liveness_trace(h, w, k, &a, &b); + assert!(!constraints_violated(&stk, &rows), "the circuit gate must ACCEPT an honest tile"); + + // Spike-dominated A: each A row has two large spikes among tiny values -> two dead entries + // per row -> 8 dead > h*k/64 = 4, so side A fails liveness. + let big = f32_to_fp16(60000.0).unwrap(); + let tiny = f32_to_fp16(0.001).unwrap(); + let mut a_spike = vec![tiny; h * k]; + for i in 0..h { + a_spike[i * k] = big; + a_spike[i * k + 1] = big; + } + assert!(!oracle_accepts(h, w, k, &a_spike, &b), "spike-dominated tile must be oracle-rejected"); + let (stk, rows) = liveness_trace(h, w, k, &a_spike, &b); + assert!(constraints_violated(&stk, &rows), "the circuit gate must REJECT a spike-dominated tile"); + } + + /// A prover cannot clear the gate by understating the dead count (the inclusive accumulator and + /// the RANGE16 gate slack have no satisfying witness for a failing tile), nor by tampering the + /// per-element dead flag, the running accumulator, or the gate slack on an honest tile. + #[test] + fn tampered_liveness_witnesses_break_constraints() { + let (h, w, k) = (4usize, 16usize, 64usize); + let a: Vec = (0..h).flat_map(|i| sample_row(k, 11 + i as u64, 3.0)).collect(); + let b: Vec = (0..w).flat_map(|j| sample_row(k, 71 + j as u64, 3.0)).collect(); + let (stk, rows) = liveness_trace(h, w, k, &a, &b); + assert!(!constraints_violated(&stk, &rows), "baseline honest tile must pass"); + let m = &ROW_SCALE_COL_MAP; + let last = rows.len() - 1; + // Flipping a per-element dead flag, the running accumulators, or the side mask on a live + // row breaks the compare slack (L6) / the accumulator transition (L8) / the side pin (L7). + for col in [m.dead, m.dead_run_a, m.dead_run_b, m.is_b_side] { + let mut t = rows.clone(); + t[k][col] += F::ONE; // row k is the start of operand row 1 (a live row) + assert!(constraints_violated(&stk, &t), "tampering column {col} must break a constraint"); + } + // Inflating the final A gate slack (claiming more headroom than the count allows) breaks L9. + let mut t = rows.clone(); + t[last][m.a_gate_slack_lo] += F::ONE; + assert!(constraints_violated(&stk, &t), "a forged gate slack must break the last-row gate"); + } +} diff --git a/zk-pow/src/circuit/fp16/verifier_cache.rs b/zk-pow/src/circuit/fp16/verifier_cache.rs new file mode 100644 index 000000000..ec09e4f4f --- /dev/null +++ b/zk-pow/src/circuit/fp16/verifier_cache.rs @@ -0,0 +1,238 @@ +//! Pre-compiled FP16 wrapper verifier setups, keyed by the batch degree profile. +//! +//! The per-shape FP16 wrapper circuit ([`super::wrapper::Fp16WrapperCircuits`]) is a +//! pure function of the batch degree profile ([`super::driver::Fp16System::degree_bits`]) +//! and the consensus LUT cap (fixed across every geometry), so two tiles that snap to +//! the same on-ladder degree profile share one compiled circuit. This cache stores one +//! compiled stage-2 verifier circuit per distinct profile; the node verifier LOADS the +//! setup for a proof's geometry instead of rebuilding it, making verification cost +//! constant and geometry-independent — closing the attacker-chosen-geometry DoS (the +//! proof's `(h, w, k)` no longer forces a multi-minute circuit compilation). +//! +//! It mirrors the FP8 trusted-setup cache ([`crate::circuit::fp8::circuit_utils`]'s +//! `Fp8VerifierCache`), with two differences: (1) FP8's wrapper is *universal* (one +//! circuit per device), so it keys by device; FP16's wrapper is per-degree-profile +//! (the universal variant is deferred — see [`super::wrapper`] docs), so it keys by the +//! degree-bits profile, and because the profile space is small (every table height +//! snaps to [`super::driver::FP16_REACHABLE_DEGREE_BITS`]) one entry per reachable +//! profile covers the whole envelope; (2) the header-bound FP16 verifier takes a full +//! [`plonky2::plonk::proof::ProofWithPublicInputs`] (not the compact form), so a setup +//! is just the [`VerifierCircuitData`] — no constants/sigmas polynomials. +//! +//! Verification never compiles circuits: a profile missing from the cache rejects the +//! proof (fail-closed). A stale or incomplete cache is a deployment error — surfaced by +//! the lookup — not a soundness hole (a wrong/absent setup makes the proof fail to +//! verify, never falsely accept). + +use anyhow::{Context, Result, ensure}; +use bincode::Options; +use hashbrown::HashMap; +use plonky2::plonk::circuit_data::VerifierCircuitData; +use plonky2::util::serialization::DefaultGateSerializer; + +use super::ctl::NUM_FP16_TABLES; +use super::wrapper::{D, F, OuterC}; + +/// The batch degree profile selecting one compiled wrapper: the per-table +/// `degree_bits` from [`super::driver::Fp16System::degree_bits`]. Every geometry with +/// this profile shares the compiled circuit. +pub type Fp16VerifierKey = [usize; NUM_FP16_TABLES]; + +/// One compiled FP16 wrapper verifier setup (the stage-2 ZK verifier circuit). +#[derive(Clone)] +pub struct Fp16Verifier { + pub(crate) circuit: VerifierCircuitData, +} + +impl Fp16Verifier { + /// Wraps a freshly compiled stage-2 wrapper verifier circuit (build tooling). + pub fn new(circuit: VerifierCircuitData) -> Self { + Self { circuit } + } + + /// Serializes the trusted verifier setup for embedding / distribution. + pub fn to_bytes(&self) -> Result> { + self.circuit + .to_bytes(&DefaultGateSerializer) + .map_err(|error| anyhow::anyhow!("serializing the fp16 wrapper verifier circuit: {error:?}")) + } + + /// Loads a setup previously produced by [`Self::to_bytes`]. Consensus / + /// trusted-setup data, not proof-controlled input. + pub fn from_bytes(bytes: Vec) -> Result { + let circuit = VerifierCircuitData::from_bytes(bytes, &DefaultGateSerializer) + .map_err(|error| anyhow::anyhow!("deserializing the fp16 wrapper verifier circuit: {error}"))?; + ensure!( + circuit.common.config.zero_knowledge, + "the fp16 verifier setup must contain the ZK wrapper (stage 2)" + ); + Ok(Self { circuit }) + } + + /// The verifier circuit data for `verify_wrapped_proof_with_headers`. + pub fn circuit(&self) -> &VerifierCircuitData { + &self.circuit + } +} + +/// A read-only store of FP16 wrapper verifier setups keyed by degree profile. Deployments +/// preload [`crate::api::fp16::embedded_cache::CACHE_DATA`], built offline by `build_cache`. +#[derive(Default)] +pub struct Fp16VerifierCache { + verifiers: HashMap, +} + +fn verifier_setup_codec_options() -> impl Options { + bincode::options().with_fixint_encoding().reject_trailing_bytes() +} + +impl Fp16VerifierCache { + /// Loads a cache previously produced by [`Self::to_bytes`]. An empty blob — the + /// embedded default when no cache has been built — loads as an empty cache. + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.is_empty() { + return Ok(Self::default()); + } + let entries: Vec<(Vec, Vec)> = verifier_setup_codec_options() + .deserialize(bytes) + .context("deserializing the fp16 verifier cache")?; + let mut verifiers = HashMap::new(); + for (key_vec, serialized_verifier) in entries { + ensure!( + key_vec.len() == NUM_FP16_TABLES, + "fp16 verifier cache key has {} entries, expected {NUM_FP16_TABLES}", + key_vec.len() + ); + let mut key: Fp16VerifierKey = [0; NUM_FP16_TABLES]; + for (slot, value) in key.iter_mut().zip(&key_vec) { + *slot = *value as usize; + } + let verifier = Fp16Verifier::from_bytes(serialized_verifier)?; + ensure!(verifiers.insert(key, verifier).is_none(), "duplicate fp16 verifier cache entry"); + } + Ok(Self { verifiers }) + } + + /// Serializes the cache (canonical, profile-sorted, so equal caches share bytes). + pub fn to_bytes(&self) -> Result> { + let mut entries = self + .verifiers + .iter() + .map(|(key, verifier)| Ok((key.iter().map(|&bits| bits as u64).collect::>(), verifier.to_bytes()?))) + .collect::>>()?; + entries.sort_by(|a, b| a.0.cmp(&b.0)); + verifier_setup_codec_options() + .serialize(&entries) + .context("serializing the fp16 verifier cache") + } + + /// Registers a pre-built setup under its degree profile (build tooling). + pub fn insert(&mut self, key: Fp16VerifierKey, verifier: Fp16Verifier) { + self.verifiers.insert(key, verifier); + } + + /// Looks up a pre-built setup by degree profile; never compiles on a miss. + pub fn get(&self, key: &Fp16VerifierKey) -> Option<&Fp16Verifier> { + self.verifiers.get(key) + } + + pub fn len(&self) -> usize { + self.verifiers.len() + } + + pub fn is_empty(&self) -> bool { + self.verifiers.is_empty() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Loads a REAL prebuilt cache blob (e.g. the `build_cache` sample output) from + /// `$FP16_SAMPLE_CACHE`, confirming a non-empty cache decodes, holds its entries, + /// and re-serializes byte-stably. Cheap (no circuit build); `#[ignore]` since it + /// needs a path. Run: `FP16_SAMPLE_CACHE=/path/fp16_sample.bin cargo test -p zk-pow + /// --lib circuit::fp16::verifier_cache::tests::loads_a_prebuilt_sample -- --ignored --nocapture`. + #[test] + #[ignore = "needs a prebuilt cache at $FP16_SAMPLE_CACHE"] + fn loads_a_prebuilt_sample_cache() { + let path = std::env::var("FP16_SAMPLE_CACHE").expect("set FP16_SAMPLE_CACHE"); + let bytes = std::fs::read(&path).expect("read sample cache"); + let cache = Fp16VerifierCache::from_bytes(&bytes).expect("decode real cache"); + assert!(!cache.is_empty(), "a built cache must have >= 1 profile"); + println!("loaded fp16 cache: {} profile(s) from {} bytes", cache.len(), bytes.len()); + // Re-serialization is byte-stable (canonical, profile-sorted). + assert_eq!(cache.to_bytes().unwrap(), bytes, "cache re-serialization must be byte-stable"); + } + + #[test] + fn empty_cache_round_trips_and_misses() { + let cache = Fp16VerifierCache::default(); + assert!(cache.is_empty()); + // Empty blob and a serialized-empty cache both load to an empty cache. + assert!(Fp16VerifierCache::from_bytes(&[]).unwrap().is_empty()); + let bytes = cache.to_bytes().unwrap(); + assert!(Fp16VerifierCache::from_bytes(&bytes).unwrap().is_empty()); + // A lookup on an empty cache misses (fail-closed): the verifier rejects. + assert!(cache.get(&[0usize; NUM_FP16_TABLES]).is_none()); + } + + /// Cache mechanism end-to-end: compile a wrapper for a small geometry, store it in + /// the cache under its degree profile, serialize + deserialize the cache, look the + /// setup up by profile, and assert the deserialized setup is BYTE-IDENTICAL to a + /// freshly built one. Because a [`VerifierCircuitData`] fully determines + /// verification, byte-identity proves the cache-loaded setup verifies exactly as a + /// rebuilt one — i.e. load-by-profile faithfully replaces the verify-time rebuild + /// (the existing `wrapper::tests` cover the proof/verify path itself). Also builds + /// a SECOND distinct geometry that snaps to the SAME profile and asserts it reuses + /// the one cached circuit, and that a different profile misses (fail-closed). + /// `#[ignore]` (compiles 1-2 wrappers, ~minutes); run explicitly: + /// `cargo test -p zk-pow --lib circuit::fp16::verifier_cache::tests::cache_round_trips -- --ignored --nocapture`. + #[test] + #[ignore = "compiles wrapper circuit(s) (~minutes); run explicitly"] + fn cache_round_trips_and_is_byte_identical_to_a_rebuild() { + use crate::api::fp8::public_params::HashId; + use crate::circuit::fp16::driver::Fp16System; + use crate::circuit::fp16::wrapper::{Fp16WrapperCircuits, InnerC}; + use plonky2::util::timing::TimingTree; + + let hash = HashId::Blake3Chunk1024; + let mut timing = TimingTree::default(); + + // Smallest consensus-legal tile (h*w = 256, k = 8). + let system = Fp16System::::new(4, 64, 8, hash, hash); + let preprocessed = system.preprocessed_data::(&mut timing); + let circuits = Fp16WrapperCircuits::build(&system, &preprocessed.cap(), &mut timing).unwrap(); + let built = Fp16Verifier::new(circuits.verifier_data()); + let built_bytes = built.to_bytes().unwrap(); + + // Cache it, round-trip the cache bytes, look it up by profile. + let mut cache = Fp16VerifierCache::default(); + cache.insert(*system.degree_bits(), built); + let loaded = Fp16VerifierCache::from_bytes(&cache.to_bytes().unwrap()).unwrap(); + assert_eq!(loaded.len(), 1); + let verifier = loaded.get(system.degree_bits()).expect("profile present in the loaded cache"); + assert_eq!( + verifier.to_bytes().unwrap(), + built_bytes, + "cache-loaded verifier must be byte-identical to the freshly built one" + ); + + // A wrong profile misses (fail-closed → the consensus verifier rejects). + let mut wrong = *system.degree_bits(); + wrong[0] = wrong[0].wrapping_add(1); + assert!(loaded.get(&wrong).is_none(), "a different profile must miss the cache"); + + // A SECOND, distinct geometry that snaps to the SAME profile reuses the one + // cached circuit — the property that makes the profile-keyed cache small and + // geometry-independent. (k=16 keeps the smallest tile on the same ladder rung.) + let system2 = Fp16System::::new(4, 64, 16, hash, hash); + if system2.degree_bits() == system.degree_bits() { + assert!( + loaded.get(system2.degree_bits()).is_some(), + "a same-profile geometry must hit the one cached circuit" + ); + } + } +} diff --git a/zk-pow/src/circuit/fp16/wrapper.rs b/zk-pow/src/circuit/fp16/wrapper.rs new file mode 100644 index 000000000..ebecaa940 --- /dev/null +++ b/zk-pow/src/circuit/fp16/wrapper.rs @@ -0,0 +1,644 @@ +//! The two-stage recursive wrapper for the FP16 / A100 batch proof — the FP16 analogue of +//! [`crate::circuit::fp8::wrapper`]. +//! +//! **Why wrap.** [`Fp16System`]'s native batched multi-STARK proof grows with the table set and is +//! not zero-knowledge as a published object. The wrapper encodes the whole batch verification +//! inside a plonky2 circuit and publishes a constant-size recursive proof instead: +//! +//! - **Stage 1** (Poseidon recursion, no ZK): the in-circuit batch verifier +//! ([`verify_batch_stark_proof_circuit`]) re-runs the full batch verification — every AIR's +//! constraints, the four committed-LUT channels and the census-import CTL, the setup-time LUT cap +//! (baked in as a constant) and the batched FRI argument. Its public inputs are, in order: +//! +//! ```text +//! every table's STARK public inputs (batch order — all empty for FP16) +//! | known-column digest (4) +//! | zeta (2) +//! | known-column evals at zeta (2 per column, batch order) +//! | known-column evals at g_t*zeta (2 per column, batch order) +//! ``` +//! +//! The class (a) ("known") columns cannot be evaluated in-circuit (they are full-height per-job +//! columns), so the circuit *exposes* the challenge point `zeta` (connected to the in-circuit +//! Fiat-Shamir challenge) and the claimed evaluations (connected to the proof's trace openings), +//! and the native gateway [`verify_wrapped_proof`] recomputes those evaluations at `zeta` from its +//! own statement-derived known values and pins every slot. A prover therefore cannot lie about +//! any class (a) column without breaking the in-circuit FRI binding or failing the gateway's +//! public-input equality. +//! +//! - **Stage 2** (ZK wrap): a plonky2 circuit with `zero_knowledge: true` that verifies the stage-1 +//! proof and forwards its public inputs unchanged. Stage 1's verifier data is baked into stage 2 +//! as circuit constants, so a stage-2 proof attests to exactly this statement's stage-1 circuit. +//! The published artifact is the stage-2 proof only. +//! +//! Like the FP8 wrapper, stage 1 proves under [`PoseidonGoldilocksConfig`] and stage 2 under +//! [`Blake3GoldilocksConfig`]. FP16 has no device variants and its main tables carry no public +//! inputs, so the wrapper omits the FP8 wrapper's compiled-device and geometry public inputs. +//! +//! **Scope — universality (the FP8 D1 redesign).** This wrapper is compiled for one degree profile +//! (one tile shape); a different tile size needs a separately compiled circuit (and may emit a +//! different-length proof). FP8 compresses *every* envelope-legal job to one compiled, constant-size +//! circuit via starky's *universal* batch verifier. The FP16 driver already ships the consensus +//! ladder, envelope and statement-digest machinery that path needs +//! ([`crate::circuit::fp16::driver::fp16_universal_envelope`]), but +//! `starky::batch_universal::verify_universal_batch_stark_proof_circuit` over-determines a witness +//! wire for FP16's table shape — two *equal-height* variable main tables (matmul and policy share +//! one row grid) linked by a direct CTL (census-import), a configuration FP8 never produces (its +//! variable tables always differ in height) and the universal verifier's own tests do not cover. +//! Closing that is the documented residual (`docs/fp16_scheme/stark_feasibility.md §8`). + +use anyhow::{Result, ensure}; +use hashbrown::HashMap; +use plonky2::field::extension::FieldExtension; +use plonky2::field::extension::quadratic::QuadraticExtension; +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::{HashOutTarget, NUM_HASH_OUT_ELTS}; +use plonky2::hash::merkle_tree::MerkleCap; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitData, VerifierCircuitData}; +use plonky2::plonk::config::{Blake3GoldilocksConfig, GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; +use plonky2::timed; +use plonky2::util::timing::TimingTree; +use plonky2_maybe_rayon::{MaybeIntoParIter, ParallelIterator}; +use starky::batch_proof::{BatchStarkProofWithPublicInputs, BatchStarkProofWithPublicInputsTarget}; +use starky::batch_recursive_verifier::{ + BatchKnownColumnsTarget, add_virtual_batch_stark_proof_with_pis, set_batch_stark_proof_with_pis_target, + verify_batch_stark_proof_circuit, +}; +use starky::verifier::eval_columns_at_zeta_and_next; + +use super::ctl::NUM_FP16_TABLES; +use super::blake3_fp16_stark::columns::NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS; +use crate::circuit::fp8::blake3_stark::columns::NUM_BLAKE3_PUBLIC_INPUTS; +use super::driver::{FP16_GROUPED_TABLES, FP16_REACHABLE_DEGREE_BITS, Fp16System, hash_jackpot, statement_digest_to_hash_out}; +use crate::api::fp16::plain_proof::Fp16JobParams; +use crate::api::primitives::{Hash256, IncompleteBlockHeader}; +use crate::api::proof_utils::check_jackpot_difficulty; +use crate::circuit::fp8::circuit_utils::build_recursion_config; + +/// The wrapper's field, extension degree and per-stage hasher configurations. +pub type F = GoldilocksField; +pub const D: usize = 2; +/// Stage-1 configuration: the batch proof's own config (Poseidon caps for the in-circuit +/// Fiat-Shamir replay) and the cheap recursion hasher. +pub type InnerC = PoseidonGoldilocksConfig; +/// Stage-2 (published) configuration: Blake3 outer hashing. +pub type OuterC = Blake3GoldilocksConfig; + +/// Sanctioned FRI parameters of the two wrapper stages (the same consensus combinations as the +/// FP8 wrapper). Rate `2^-3` is the floor for both stages: the recursion gates carry degree-7 +/// constraints, so the quotient needs an LDE blowup of at least `2^3`. +pub const STAGE_1_RATE_BITS: usize = 3; +pub const STAGE_1_POW_BITS: usize = 18; +pub const STAGE_2_RATE_BITS: usize = 7; +pub const STAGE_2_POW_BITS: usize = 22; + +/// Flat offset of the exposed challenge point `zeta`. The batch's STARK public inputs come first +/// (only the Blake3 table carries any — its 64 hash/key limbs), then the known-column digest, then +/// `zeta`. +pub fn zeta_offset(_system: &Fp16System) -> usize { + // Both PI-bearing tables are published before the known-column digest: the operand/jackpot Blake3 + // table (64 limbs) and, since 6e-3c, the noise-BLAKE3 derivation table (64 limbs, the pinned + // seeds + inert lottery digest). Every other table registers an empty public-input vector. + NUM_BLAKE3_PUBLIC_INPUTS + NUM_FP16_RAW_BLAKE3_PUBLIC_INPUTS + NUM_HASH_OUT_ELTS +} + +/// Total public-input count of a wrapper proof for this batch shape. +fn num_wrapper_public_inputs(system: &Fp16System) -> usize { + let num_known: usize = system.known().columns_per_table.iter().map(Vec::len).sum(); + zeta_offset(system) + D + 2 * D * num_known +} + +/// The two compiled wrapper circuits, plus the witness targets the prover fills. These are compiled +/// for one degree profile (tile shape); see the module docs on universality. +pub struct Fp16WrapperCircuits { + /// Stage 1: the in-circuit batch verifier (Poseidon recursion, no ZK). + stage1: CircuitData, + proof_target: BatchStarkProofWithPublicInputsTarget, + known_digest_target: HashOutTarget, + /// Stage 2: the ZK wrap publishing stage 1's public inputs. + stage2: CircuitData, + stage1_proof_target: ProofWithPublicInputsTarget, +} + +/// A virtual extension target registered (component-wise) as the next public inputs. +fn add_ext_public_input(builder: &mut CircuitBuilder) -> ExtensionTarget { + let et = builder.add_virtual_extension_target(); + builder.register_public_inputs(&et.0); + et +} + +impl Fp16WrapperCircuits { + /// Compiles both stages for `system`'s degree profile, baking `lut_cap` (the consensus LUT + /// commitment) into stage 1 as constants. + pub fn build( + system: &Fp16System, + lut_cap: &MerkleCap>::Hasher>, + timing: &mut TimingTree, + ) -> Result { + let known = system.known(); + ensure!( + system + .degree_bits() + .iter() + .all(|bits| FP16_REACHABLE_DEGREE_BITS.contains(bits)), + "wrapper: the degree profile {:?} must lie on the consensus ladder", + system.degree_bits() + ); + + // ---- Stage 1: the in-circuit batch verifier. ---- + let config_1 = build_recursion_config(STAGE_1_RATE_BITS, STAGE_1_POW_BITS, 1, false); + let mut builder = CircuitBuilder::::new(config_1); + let starks = system.batch_starks(); + let preprocessed = system.preprocessed_verifier_data::(lut_cap); + let prep_columns = preprocessed.columns_per_table.clone(); + let preprocessed_target = preprocessed.constant_target(&mut builder); + + let proof_target = add_virtual_batch_stark_proof_with_pis::( + &mut builder, + &starks, + system.config(), + system.degree_bits(), + &prep_columns, + system.ctls(), + &FP16_GROUPED_TABLES, + )?; + + // The known-column surface: a digest slot and one claimed evaluation per column per point. + let known_digest_target = builder.add_virtual_hash(); + let evals_at_zeta: Vec>> = known + .columns_per_table + .iter() + .map(|columns| (0..columns.len()).map(|_| builder.add_virtual_extension_target()).collect()) + .collect(); + let evals_at_g_zeta: Vec>> = known + .columns_per_table + .iter() + .map(|columns| (0..columns.len()).map(|_| builder.add_virtual_extension_target()).collect()) + .collect(); + let known_target = BatchKnownColumnsTarget:: { + digest: Some(known_digest_target), + columns_per_table: known.columns_per_table.clone(), + evals_at_zeta, + evals_at_g_zeta, + }; + + let zeta = verify_batch_stark_proof_circuit::( + &mut builder, + &starks, + system.config(), + &proof_target, + system.ctls(), + &FP16_GROUPED_TABLES, + Some(&preprocessed_target), + Some(&known_target), + &HashMap::new(), + )?; + + // Public-input layout (see module docs): table public inputs (all empty for FP16), the + // known-column digest, zeta, then the claimed evaluations. + for pis in &proof_target.public_inputs { + builder.register_public_inputs(pis); + } + builder.register_public_inputs(&known_digest_target.elements); + let zeta_pi = add_ext_public_input(&mut builder); + builder.connect_extension(zeta_pi, zeta); + for evals in known_target.evals_at_zeta.iter().chain(&known_target.evals_at_g_zeta) { + for eval in evals { + builder.register_public_inputs(&eval.0); + } + } + + let stage1_gates = builder.num_gates(); + let stage1 = timed!(timing, "build the stage-1 FP16 wrapper circuit", builder.build::()); + log::info!( + "stage-1 FP16 wrapper circuit: {stage1_gates} gates -> 2^{} rows", + stage1.common.degree_bits(), + ); + + // ---- Stage 2: the ZK wrap. ---- + let config_2 = build_recursion_config(STAGE_2_RATE_BITS, STAGE_2_POW_BITS, 2, true); + debug_assert!(config_2.zero_knowledge); + let mut builder = CircuitBuilder::::new(config_2); + let stage1_proof_target = builder.add_virtual_proof_with_pis(&stage1.common); + builder.register_public_inputs(&stage1_proof_target.public_inputs); + let stage1_verifier_target = builder.constant_verifier_data(&stage1.verifier_only); + builder.verify_proof::(&stage1_proof_target, &stage1_verifier_target, &stage1.common); + let stage2 = timed!(timing, "build the stage-2 (ZK) FP16 wrapper circuit", builder.build::()); + log::info!("stage-2 FP16 wrapper circuit: 2^{} gates", stage2.common.degree_bits()); + + Ok(Self { + stage1, + proof_target, + known_digest_target, + stage2, + stage1_proof_target, + }) + } + + /// Wraps one batch proof: proves stage 1 (the in-circuit batch verification), then stage 2 (the + /// ZK wrap). Returns the publishable stage-2 proof. `batch_proof` must be a proof of `system`'s + /// statement; `statement_digest` is the Fiat-Shamir salt the inner batch proof absorbed. + pub fn prove( + &self, + system: &Fp16System, + batch_proof: &BatchStarkProofWithPublicInputs, + statement_digest: Hash256, + timing: &mut TimingTree, + ) -> Result> { + system.ensure_statement_digest_binding(statement_digest)?; + let mut pw = PartialWitness::new(); + set_batch_stark_proof_with_pis_target(&mut pw, &self.proof_target, batch_proof)?; + pw.set_hash_target(self.known_digest_target, statement_digest_to_hash_out(statement_digest))?; + let stage1_proof = timed!(timing, "prove the stage-1 FP16 wrapper", self.stage1.prove(pw))?; + + let mut pw = PartialWitness::new(); + pw.set_proof_with_pis_target(&self.stage1_proof_target, &stage1_proof)?; + timed!(timing, "prove the stage-2 (ZK) FP16 wrapper", self.stage2.prove(pw)) + } + + /// The verifier's view: stage 2's verifier data (the only circuit a verifier needs). + pub fn verifier_data(&self) -> VerifierCircuitData { + self.stage2.verifier_data() + } +} + +/// Verifies a wrapped (stage-2) proof against the statement: it pins *every* public-input slot — +/// the known-column digest to `statement_digest`, and the known-column evaluations to the verifier's +/// native recomputation at the proof's `zeta` from the statement's known values (`zeta` is the one +/// prover-supplied slot; the stage-1 circuit constrains it to the inner batch proof's Fiat-Shamir +/// challenge) — then verifies the plonky2 proof against `verifier_data` (which must be the ZK stage). +/// Together with the in-circuit batch verification this gives exactly the guarantees of +/// [`Fp16System::verify`]. +pub fn verify_wrapped_proof( + system: &Fp16System, + verifier_data: &VerifierCircuitData, + proof: &ProofWithPublicInputs, + statement_digest: Hash256, +) -> Result<()> { + ensure!( + verifier_data.common.config.zero_knowledge, + "the wrapped verifier circuit must be the ZK stage" + ); + system.ensure_statement_digest_binding(statement_digest)?; + let total = num_wrapper_public_inputs(system); + ensure!( + proof.public_inputs.len() == total, + "wrapped proof: wrong public input count (got {}, statement expects {})", + proof.public_inputs.len(), + total + ); + let z = zeta_offset(system); + let zeta = QuadraticExtension([proof.public_inputs[z], proof.public_inputs[z + 1]]); + // The batch public inputs are the wrapper vector's prefix (Blake3's 64 limbs; every other + // table empty), read back from the proof to rebuild the expected layout. + let blake3_pis = &proof.public_inputs[..NUM_BLAKE3_PUBLIC_INPUTS]; + let expected = expected_wrapper_public_inputs(system, statement_digest, zeta, blake3_pis)?; + ensure!( + proof.public_inputs == expected, + "wrapped proof: public inputs do not match the statement's expectations" + ); + verifier_data.verify(proof.clone()) +} + +/// The header-bound consensus gateway for a wrapped (stage-2) FP16 proof — the wrapper-level analogue +/// of [`Fp16System::verify_with_headers`], and the sound entry the consensus layer calls. +/// +/// Unlike [`verify_wrapped_proof`] (which trusts a caller-supplied `statement_digest` and the +/// proof's own key public inputs), this derives EVERYTHING header-bound, exactly as the plaintext +/// certificate [`crate::api::fp16::verify::verify_fp16_plain_proof`] does: +/// 1. reads the proof's committed operand-Blake3 PIs (`HASH_A`/`HASH_B`/`HASH_JACKPOT`) from the +/// wrapper vector's prefix, and overwrites the three keys with their header/root-derived values +/// via [`Fp16System::header_bound_blake3_pis`] (`KEY_A=key_a(proposed)`, `KEY_B=key_b(ancestor)`, +/// `JACKPOT_KEY=jackpot_key(seed_a)`), so a proof whose opening keys, noise seeds, or jackpot +/// key are not header-derived fails the pin; +/// 2. DERIVES `statement_digest` from the (header-bound) `HASH_JACKPOT` — it is not caller-supplied; +/// 3. pins the whole stage-2 public-input vector to that header-bound expectation and runs the ZK +/// verification, then checks `check_jackpot_difficulty` on the proven jackpot against `nbits`. +/// +/// The one remaining consensus boundary is inherent (as for the plaintext FFI): the caller supplies +/// the proposed header + `nbits` and must authenticate `job.ancestor_header` as a state-window member +/// (the hash-walk) before calling. +pub fn verify_wrapped_proof_with_headers( + system: &mut Fp16System, + verifier_data: &VerifierCircuitData, + proof: &ProofWithPublicInputs, + proposed_header: &IncompleteBlockHeader, + job: &Fp16JobParams, + nbits: u32, +) -> Result<()> { + ensure!( + verifier_data.common.config.zero_knowledge, + "the wrapped verifier circuit must be the ZK stage" + ); + // Consensus / wrapper-legal envelope gate (defense in depth; the FFI also gates + // before building the system). Rejects any out-of-envelope geometry cleanly. + { + let (h, w, k) = system.tile_geometry(); + crate::api::fp16::params::Fp16Params { device: job.device, h, w, k, r: job.r as usize }.validate()?; + } + // Fold THIS job's `p` into the system exactly as the prover did + // (`Fp16Prover::prove`): `Fp16System::new` installs only a placeholder `p` + // (zero ancestor), so without this the recomputed seed / known-column public + // inputs would not match a proof whose job carries a real ancestor header. + system.set_noise_seed_params(crate::api::primitives::Sides { + a: job.encode_p_a(), + b: job.encode_p_b(), + }); + let system = &*system; + let total = num_wrapper_public_inputs(system); + ensure!( + proof.public_inputs.len() == total, + "wrapped proof: wrong public input count (got {}, statement expects {})", + proof.public_inputs.len(), + total + ); + let z = zeta_offset(system); + let zeta = QuadraticExtension([proof.public_inputs[z], proof.public_inputs[z + 1]]); + + // Header-bind the operand-Blake3 PIs: the proof's committed roots/jackpot with the three keys + // overwritten by their header/root-derived values (the noise seeds follow from the roots+keys). + let proof_blake3_pis = &proof.public_inputs[..NUM_BLAKE3_PUBLIC_INPUTS]; + let (expected_blake3, _seeds) = system.header_bound_blake3_pis(proof_blake3_pis, proposed_header, job); + + // The statement digest is DERIVED from the header-bound jackpot (not caller-supplied), closing + // the output-to-header binding. (The HASH_JACKPOT slot is unchanged by the key overwrite.) + let statement_digest = Fp16System::::statement_digest(&expected_blake3); + system.ensure_statement_digest_binding(statement_digest)?; + let expected = expected_wrapper_public_inputs(system, statement_digest, zeta, &expected_blake3)?; + ensure!( + proof.public_inputs == expected, + "wrapped proof: public inputs do not match the header-bound statement" + ); + + // Native difficulty on the proven, now header-key-bound jackpot — exactly as the plaintext + // `verify_tile_proof` and `Fp16System::verify_with_headers` do. + let jackpot = hash_jackpot::(&expected_blake3); + let (h, w, k) = system.tile_geometry(); + check_jackpot_difficulty(&jackpot, nbits, h as u32, w as u32, k as u32)?; + + verifier_data.verify(proof.clone()) +} + +/// The full stage-2 public-input vector a statement expects, given the proof's `zeta`. +pub fn expected_wrapper_public_inputs( + system: &Fp16System, + statement_digest: Hash256, + zeta: QuadraticExtension, + blake3_pis: &[F], +) -> Result> { + ensure!( + !FieldExtension::::is_in_basefield(&zeta), + "wrapped proof: zeta must lie strictly in the extension field" + ); + let total = num_wrapper_public_inputs(system); + let known = system.known(); + let mut expected: Vec = Vec::with_capacity(total); + // Only the Blake3 table carries STARK public inputs; the digest follows them. + for pis in system.batch_public_inputs(blake3_pis) { + expected.extend(pis); + } + expected.extend(statement_digest_to_hash_out::(statement_digest).elements); + expected.extend(zeta.0); + // The class (a) recompute: evaluate the statement's own known columns at the proof's zeta and + // g_t * zeta — the same binding `batch_verify` performs natively. Each table is independent. + type TableEvals = ( + Vec>, + Vec>, + ); + let per_table: Vec = (0..NUM_FP16_TABLES) + .into_par_iter() + .map(|t| { + if known.columns_per_table[t].is_empty() { + (vec![], vec![]) + } else { + let columns: Vec<&PolynomialValues> = known.values_per_table[t].iter().collect(); + eval_columns_at_zeta_and_next::(&columns, zeta, system.degree_bits()[t]) + } + }) + .collect(); + let mut evals_at_zeta = Vec::new(); + let mut evals_at_g_zeta = Vec::new(); + for (at_zeta, at_g_zeta) in per_table { + evals_at_zeta.extend(at_zeta); + evals_at_g_zeta.extend(at_g_zeta); + } + expected.extend(evals_at_zeta.iter().flat_map(|e| e.0)); + expected.extend(evals_at_g_zeta.iter().flat_map(|e| e.0)); + ensure!( + expected.len() == total, + "wrapped proof: internal public-input layout mismatch (built {}, layout says {})", + expected.len(), + total + ); + Ok(expected) +} + +#[cfg(test)] +mod tests { + use plonky2::util::timing::TimingTree; + + use super::*; + use crate::api::fp16::accumulate::GROUP; + use crate::api::fp16::policy::replay_and_evaluate; + + const VECTORS: &str = include_str!("../../api/fp16/testdata/a100_dot_vectors.txt"); + + /// Builds an `h x w` tile (one reference cell replicated into every A row and B col) whose NOISED + /// quantization — the operands the batch's matmul/policy actually multiply — clears the policy + /// gate. Picks the smallest `k` (`k >= 16`, `k % GROUP == 0`) that qualifies for this shape. + fn accepting_tile(h: usize, w: usize) -> (usize, Vec, Vec) { + use crate::circuit::fp16::driver::fp16_noised_operands; + let mut best: Option<(usize, Vec, Vec)> = None; + for line in VECTORS.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let t: Vec<&str> = line.split_whitespace().collect(); + let k: usize = t[0].parse().unwrap(); + if k % GROUP != 0 || k < 16 { + continue; + } + if best.as_ref().is_some_and(|(bk, _, _)| k >= *bk) { + continue; + } + let a0: Vec = t[1..1 + k].iter().map(|x| x.parse().unwrap()).collect(); + let b0: Vec = t[1 + k..1 + 2 * k].iter().map(|x| x.parse().unwrap()).collect(); + let (a, b) = (a0.repeat(h), b0.repeat(w)); + let Ok((noised_a, noised_b)) = fp16_noised_operands(h, w, k, &a, &b, KEY_A, KEY_B, OP_HASH_ID, OP_HASH_ID) else { continue }; + if replay_and_evaluate(&noised_a, &noised_b, h, w, k).1.accept { + best = Some((k, a, b)); + } + } + best.expect("reference vectors must contain a cell whose noised tile accepts for this shape") + } + + /// Task A capstone: an honest FP16 tile -> batch proof -> recursive wrapped proof VERIFIES, and + /// a tampered statement or proof is REJECTED. The wrapped (stage-2) proof is a constant-size + /// recursive artifact whose length is independent of the tile's inner dimension. (This wrapper + /// is compiled per degree profile; the universal, one-circuit-for-all-sizes variant is the + /// documented residual — see the module docs and `stark_feasibility.md §8`.) + // + // The batch's Blake3 table now runs the full FP16 program (operand-A tree -> HASH_A, operand-B + // tree -> HASH_B, plus the jackpot compression). Under `Blake3Chunk512` the `4x4` and `4x16` + // operand trees each stand at `2^8` live-row height — on `FP16_REACHABLE_DEGREE_BITS` — so the + // table clears the ladder floor the jackpot-only program (`2^3`) sat below, and the wrapper + // compiles and wraps. The operand-bytes (6c) and operand-codes (6d) CTLs now bind the committed + // operand bytes to the quant `raw` and the matmul operands to the noised `out`, so the wrapped + // proof attests the matmul multiplies the noised quantization of the committed operands. + const KEY_A: Hash256 = [0x11; 32]; + const KEY_B: Hash256 = [0x22; 32]; + /// Keeps both tiles' Blake3 operand trees on the consensus ladder (`2^8`). + const OP_HASH_ID: crate::api::fp8::public_params::HashId = + crate::api::fp8::public_params::HashId::Blake3Chunk512; + + #[test] + #[ignore = "builds + proves two recursive wrappers (~13 min each); run explicitly"] + fn wrapped_fp16_proof_verifies_and_rejects_tampering() { + let _ = env_logger::builder().format_timestamp(None).try_init(); + let mut timing = TimingTree::default(); + + let (k, a, b) = accepting_tile(4, 4); // 16 output cells, one per lottery lane. + let jk = crate::api::fp8::transcript::jackpot_key(&[0x5a; 32]); + let mut system = Fp16System::::new(4, 4, k, OP_HASH_ID, OP_HASH_ID); + let preprocessed = system.preprocessed_data::(&mut timing); + let lut_cap = preprocessed.cap(); + + let circuits = Fp16WrapperCircuits::build(&system, &lut_cap, &mut timing).expect("wrapper compiles"); + let vd = circuits.verifier_data(); + assert!(vd.common.config.zero_knowledge, "the published stage carries ZK blinding"); + + let bp = system.prove::(&a, &b, KEY_A, KEY_B, jk, &preprocessed, &mut timing).expect("batch proof"); + let bp_blake3_pis = bp.public_inputs[crate::circuit::fp16::ctl::BLAKE3_A100_TABLE].clone(); + // The statement digest is now DERIVED from the proof's own HASH_JACKPOT (not a caller-opaque + // salt); `prove` bound it, and the wrapper pins it through to the known-column digest PI. + let digest = Fp16System::::statement_digest(&bp_blake3_pis); + system.verify::(&bp, &bp_blake3_pis, &lut_cap).expect("native batch verify"); + let wrapped = circuits.prove(&system, &bp, digest, &mut timing).expect("wrap"); + + // Honest wrapped proof verifies, and is a constant-size recursive artifact. + verify_wrapped_proof(&system, &vd, &wrapped, digest).expect("honest wrapped proof verifies"); + let len = wrapped.to_bytes().len(); + log::info!("wrapped FP16 proof size: {len} bytes"); + + // A second, larger tile (4x8 -> main tables at 2^6 vs the 4x4 tile's 2^5, both on the main + // range [4,6]; its Blake3 operand trees are still 2^8) wraps to a proof of the SAME length: + // the recursive artifact's size is independent of the tile's row count (it is a function only + // of the wrapper circuits, which share the dominating 2^16 committed-LUT shape). + let (k3, a3, b3) = accepting_tile(4, 8); + let mut system3 = Fp16System::::new(4, 8, k3, OP_HASH_ID, OP_HASH_ID); + assert_ne!(system3.degree_bits()[0], system.degree_bits()[0], "tiles must differ in main height"); + let preprocessed3 = system3.preprocessed_data::(&mut timing); + let circuits3 = Fp16WrapperCircuits::build(&system3, &preprocessed3.cap(), &mut timing).expect("wrapper 4x8"); + let bp3 = system3.prove::(&a3, &b3, KEY_A, KEY_B, jk, &preprocessed3, &mut timing).expect("batch proof 4x8"); + // A different tile folds to a different jackpot, hence a different derived statement digest. + let digest3 = Fp16System::::statement_digest(&bp3.public_inputs[crate::circuit::fp16::ctl::BLAKE3_A100_TABLE]); + let wrapped3 = circuits3.prove(&system3, &bp3, digest3, &mut timing).expect("wrap 4x8"); + verify_wrapped_proof(&system3, &circuits3.verifier_data(), &wrapped3, digest3).expect("4x8 wrapped verifies"); + assert_eq!(wrapped3.to_bytes().len(), len, "the wrapped proof size must be constant across tile sizes"); + + // Tamper (statement): a different statement digest must be rejected. + let other_digest: Hash256 = [9u8; 32]; + assert!( + verify_wrapped_proof(&system, &vd, &wrapped, other_digest).is_err(), + "a wrong statement digest must be rejected" + ); + + // Tamper (proof): flipping any public-input slot — the exposed zeta or a known-column eval — + // breaks the pinned-public-input equality or the plonky2 verification. + for &slot in &[ + zeta_offset(&system), // the exposed zeta + zeta_offset(&system) + D, // the first known-column eval + wrapped.public_inputs.len() - 1, // the last known-column eval + ] { + let mut bad = wrapped.clone(); + bad.public_inputs[slot] += F::ONE; + assert!( + verify_wrapped_proof(&system, &vd, &bad, digest).is_err(), + "tampered wrapped public-input slot {slot} must be rejected" + ); + } + } + + /// The header-bound consensus gateway [`verify_wrapped_proof_with_headers`]: the committed + /// honest ZK-cert fixture verifies under its header; a different proposed header, an impossible + /// difficulty, or any tampered public-input slot is rejected. Nothing feeding the keys/seeds/ + /// jackpot key is test-supplied — it is all re-derived from the block header + job params. + /// + /// FAST (no proving): loads the committed fixture (`node/zkpow/testdata/fp16_zk_cert_a100.bin`, + /// a wrapper-legal 4x64 tile) and the production verifier cache (`src/api/fp16/fp16_cache.bin`) + /// and verifies through the cache exactly as the FFI does. Skips if either (gitignored cache / + /// committed fixture) is absent. Regenerate the fixture + cache with + /// `api::fp16::zk::fixture::regenerate_zk_cert_fixture` and `build_cache`. + #[test] + fn wrapped_fp16_proof_header_binding() { + use crate::api::fp16::zk_cert::Fp16ZkCertificate; + use crate::api::primitives::IncompleteBlockHeader; + use crate::circuit::fp16::verifier_cache::Fp16VerifierCache; + use plonky2::plonk::proof::ProofWithPublicInputs; + use std::path::Path; + + const EASY_NBITS: u32 = 0x207fffff; + let manifest = Path::new(env!("CARGO_MANIFEST_DIR")); + let (cache_bytes, fixture) = match ( + std::fs::read(manifest.join("src/api/fp16/fp16_cache.bin")), + std::fs::read(manifest.join("../node/zkpow/testdata/fp16_zk_cert_a100.bin")), + ) { + (Ok(c), Ok(f)) => (c, f), + _ => { + eprintln!("skip: fp16_cache.bin / ZK-cert fixture absent (run build_cache + regenerate_zk_cert_fixture)"); + return; + } + }; + + // The asymmetric honest header the fixture was keyed under (matches `honest_fixture` / + // the `regenerate_zk_cert_fixture` generator); the fixture's own 76-byte header prefix. + let proposed = IncompleteBlockHeader { + version: 0, + prev_block: std::array::from_fn(|i| i as u8), + merkle_root: std::array::from_fn(|i| 0x40u8 + i as u8), + timestamp: 0x6666_6666, + nbits: EASY_NBITS, + }; + let cert_len = u32::from_le_bytes(fixture[76..80].try_into().unwrap()) as usize; + let cert = Fp16ZkCertificate::from_bytes(&fixture[80..80 + cert_len]).expect("parse ZK cert"); + let (h, w, k) = cert.tile_geometry(); + let (ah, bh) = (cert.job.operands.a.hash_id, cert.job.operands.b.hash_id); + + let cache = Fp16VerifierCache::from_bytes(&cache_bytes).expect("parse production cache"); + let mut system = Fp16System::::new(h, w, k, ah, bh); + let vd = cache.get(system.degree_bits()).expect("production cache covers the fixture profile").circuit(); + let proof = ProofWithPublicInputs::from_bytes(cert.proof_bytes.clone(), &vd.common).expect("deserialize proof"); + + // (accept) the header-bound gateway verifies the honest wrapped proof. + verify_wrapped_proof_with_headers(&mut system, vd, &proof, &proposed, &cert.job, EASY_NBITS) + .expect("the honest header-bound wrapped proof verifies"); + + // (reject) a different proposed header re-derives keyA/seedA/jackpot key -> pin fails. + let wrong = IncompleteBlockHeader { timestamp: proposed.timestamp ^ 0x5A5A, ..proposed }; + assert!( + verify_wrapped_proof_with_headers(&mut system, vd, &proof, &wrong, &cert.job, EASY_NBITS).is_err(), + "a different proposed header must be rejected by the header-bound pin" + ); + + // (reject) an impossible difficulty target fails the native epilogue. + assert!( + verify_wrapped_proof_with_headers(&mut system, vd, &proof, &proposed, &cert.job, 0).is_err(), + "an impossible nbits must be rejected" + ); + + // (reject) a tampered public-input slot breaks the pinned equality / plonky2 verification. + let mut bad = proof.clone(); + bad.public_inputs[zeta_offset(&system)] += F::ONE; + assert!( + verify_wrapped_proof_with_headers(&mut system, vd, &bad, &proposed, &cert.job, EASY_NBITS).is_err(), + "a tampered wrapped public-input slot must be rejected" + ); + } +} diff --git a/zk-pow/src/circuit/fp16/xor_fold_stark/columns.rs b/zk-pow/src/circuit/fp16/xor_fold_stark/columns.rs new file mode 100644 index 000000000..914945c0b --- /dev/null +++ b/zk-pow/src/circuit/fp16/xor_fold_stark/columns.rs @@ -0,0 +1,110 @@ +//! Columns for one FP16 XorFold step: +//! `fold_out = rotl32(low32(fold_state_in * 0x9E3779B1 + cell_word), 13)`. +//! +//! The FP16 analogue of [`crate::circuit::fp8::xor_fold_stark::columns`], stripped of the FP8 +//! consolidated-policy skip-gate: the FP16 scheme scores its jackpot in the separate +//! [`crate::circuit::fp16::policy_stark`] (breakpoint density / rho), so this table carries no +//! `cell_skips` / `running_skips` / `skip_gate_slack` columns and has no public inputs. It only +//! proves the 32-bit lottery mixer that folds the matmul output cells into the 16 lottery words. +//! +//! Each live row folds one matmul cell. The leading class-(a) columns `cell_id`, `lane_id`, +//! `is_lane_final`, and `is_pad` bind the committed lane layout; the rest hold the raw f32 cell +//! word, the input fold state, the exact 64-bit multiply-add limbs, and the rotation split. +//! `0x9E3779B1` and the rotation distance 13 are fixed protocol mixing constants (shared with the +//! plaintext extractor [`crate::api::fp8::utils::xor_fold_extract`]). + +use crate::circuit::fp8::columns_view::columns_view; + +/// View of one FP16 XorFoldStark trace row. The folded output (the next fold state) is not a +/// column — it is the affine expression +/// `FOLD_OUT = (ROTATION_INPUT_BOTTOM19_LIMB_0 + 2^16*ROTATION_INPUT_BOTTOM19_LIMB_1)*2^13 +/// + ROTATION_INPUT_TOP13`. +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct XorFoldColumnsView { + /// The matmul output cell this row folds, per the committed `lane_assignment`; key of the + /// cell-results CTL. Class (a), verifier-recomputed from the committed lane layout. + pub cell_id: T, + /// Which of the 16 lottery words this lane produces; key of the Blake3 channel. Class (a). + pub lane_id: T, + /// 1 on each lane's last row: filter of the Blake3 channel, resets the fold chain. Class (a). + pub is_lane_final: T, + /// 1 on the all-zero trailing padding rows (`h*w` live rows padded to a power of two); + /// excludes them from the cell-results channel. Class (a). + pub is_pad: T, + /// The cell's f32 word as two 16-bit limbs (RC16'd), CTL-received from the matmul. + pub cell_result_f32_lo: T, + pub cell_result_f32_hi: T, + /// The lane's running fold state entering this row (0 at lane start). + pub fold_state_in: T, + /// 16-bit limbs of the 64-bit multiply-add `FOLD_STATE_IN*0x9E3779B1 + W`, where + /// `W = CELL_RESULT_F32_LO + 2^16*CELL_RESULT_F32_HI` is the folded cell word: low half + /// (the pre-rotation u32) ... + pub muladd_low_limb_0: T, + pub muladd_low_limb_1: T, + /// ... and high half (the discarded overflow). The cap `MULADD_HIGH_LIMB_1 <= 0xFFFE` + /// (RC16 of `MULADD_HIGH_LIMB_1 + 1`) keeps the recomposition below the Goldilocks modulus + /// `p = 2^64 - 2^32 + 1`, preventing a `+p` limb alias (the honest top limb is at most + /// `0x9E38`). + pub muladd_high_limb_0: T, + pub muladd_high_limb_1: T, + /// Split of the pre-rotation low u32 as `ROTATION_INPUT_TOP13*2^19 + /// + (ROTATION_INPUT_BOTTOM19_LIMB_1*2^16 + ROTATION_INPUT_BOTTOM19_LIMB_0)`: rotating + /// left by 13 moves the bottom 19 bits up and the top 13 bits down. + pub rotation_input_top13: T, + pub rotation_input_bottom19_limb_0: T, + pub rotation_input_bottom19_limb_1: T, +} + +/// Total number of committed XorFoldStark columns. +pub const NUM_XOR_FOLD_COLUMNS: usize = size_of::>(); + +// Committed-column count: 10 main + 4 class (a). +const _: () = assert!(NUM_XOR_FOLD_COLUMNS == 14); + +/// The FP16 XorFold AIR has no public inputs (the skip-budget gate of the FP8 table is gone). +pub const NUM_XOR_FOLD_PUBLIC_INPUTS: usize = 0; + +columns_view!(XorFoldColumnsView, NUM_XOR_FOLD_COLUMNS, XOR_FOLD_COL_MAP); + +/// Number of leading class (a) ("known") columns: `CELL_ID`, `LANE_ID`, `IS_LANE_FINAL`, +/// `IS_PAD` — pure functions of the committed lane layout (`XorFoldProgram::known_values`), +/// re-checked by the batch verifier against the trace openings. +pub const NUM_XOR_FOLD_KNOWN_COLUMNS: usize = XOR_FOLD_COL_MAP.is_pad + 1; + +#[cfg(test)] +mod tests { + use core::borrow::Borrow; + + use super::*; + + #[test] + fn col_map_is_the_identity_layout() { + let as_array: [usize; NUM_XOR_FOLD_COLUMNS] = XOR_FOLD_COL_MAP.into(); + for (i, &c) in as_array.iter().enumerate() { + assert_eq!(c, i); + } + // Class (a) columns come first (their indices feed `preprocessed_indices`). + assert_eq!(XOR_FOLD_COL_MAP.cell_id, 0); + assert_eq!(XOR_FOLD_COL_MAP.lane_id, 1); + assert_eq!(XOR_FOLD_COL_MAP.is_lane_final, 2); + assert_eq!(XOR_FOLD_COL_MAP.is_pad, 3); + assert_eq!(XOR_FOLD_COL_MAP.rotation_input_bottom19_limb_1, NUM_XOR_FOLD_COLUMNS - 1); + } + + #[test] + fn view_array_roundtrip() { + let mut arr = [0u64; NUM_XOR_FOLD_COLUMNS]; + for (i, v) in arr.iter_mut().enumerate() { + *v = i as u64 * 3 + 1; + } + let view: XorFoldColumnsView = arr.into(); + assert_eq!(view.cell_id, 1); + assert_eq!(view.fold_state_in, XOR_FOLD_COL_MAP.fold_state_in as u64 * 3 + 1); + let back: [u64; NUM_XOR_FOLD_COLUMNS] = view.into(); + assert_eq!(back, arr); + + let borrowed: &XorFoldColumnsView = arr.borrow(); + assert_eq!(borrowed.rotation_input_top13, arr[XOR_FOLD_COL_MAP.rotation_input_top13]); + } +} diff --git a/zk-pow/src/circuit/fp16/xor_fold_stark/ctl.rs b/zk-pow/src/circuit/fp16/xor_fold_stark/ctl.rs new file mode 100644 index 000000000..ab1e6f00e --- /dev/null +++ b/zk-pow/src/circuit/fp16/xor_fold_stark/ctl.rs @@ -0,0 +1,112 @@ +//! Connects each FP16 XorFold step's `cell_word` input and `fold_out` output. +//! +//! Live rows receive `(cell_id, cell_result_f32_lo, cell_result_f32_hi)` from the matmul (the +//! FP16 analogue drops the FP8 `cell_skips` census tuple field — FP16 scores its jackpot in the +//! policy AIR, and the matmul->policy census-import CTL already carries the per-step census). +//! Lane-final rows send `(lane_id, fold_out)` to Blake3. RC16 lookups bound the mixer arithmetic. +//! +//! The two [`TableWithColumns`] builders take the XorFold table's batch index explicitly: the +//! table is not yet registered in [`crate::circuit::fp16::ctl`], so the index is supplied by the +//! batch-integration step rather than baked in here. + +use plonky2::field::types::Field; +use starky::cross_table_lookup::{TableIdx, TableWithColumns}; +use starky::lookup::{Column, Filter}; + +use super::columns::XOR_FOLD_COL_MAP; +use crate::circuit::fp8::luts::ctl::LutLookup; + +/// XorFold's looking side of the **cell results** channel: `(CELL_ID, CELL_RESULT_F32_LO, +/// CELL_RESULT_F32_HI)`, filter `1 - IS_PAD` — every live row folds one finished matmul cell. +/// The matmul's looked side is the FP16 analogue of +/// `crate::circuit::fp8::matmul_b200_stark::ctl::ctl_cell_results_looked_matmul_b200`. +pub fn ctl_cell_results_looking_xor_fold(xor_fold_table: usize) -> TableWithColumns { + let m = &XOR_FOLD_COL_MAP; + TableWithColumns::new( + TableIdx::from(xor_fold_table), + Column::singles([m.cell_id, m.cell_result_f32_lo, m.cell_result_f32_hi]).collect(), + Filter::from_column(Column::linear_combination_with_constant([(m.is_pad, -F::ONE)], F::ONE)), + ) +} + +/// XorFold's looked side of the **lottery words** channel: `(LANE_ID, FOLD_OUT)` with the affine +/// `FOLD_OUT = (ROTATION_INPUT_BOTTOM19_LIMB_0 + 2^16*ROTATION_INPUT_BOTTOM19_LIMB_1)*2^13 +/// + ROTATION_INPUT_TOP13`, filter `IS_LANE_FINAL`. Blake3's looking side sends 16 tuples pairing +/// each word position with the corresponding jackpot message word on the lottery message-load row. +pub fn ctl_lottery_words_looked_xor_fold(xor_fold_table: usize) -> TableWithColumns { + let m = &XOR_FOLD_COL_MAP; + TableWithColumns::new( + TableIdx::from(xor_fold_table), + vec![ + Column::single(m.lane_id), + Column::linear_combination([ + (m.rotation_input_top13, F::ONE), + (m.rotation_input_bottom19_limb_0, F::from_canonical_u64(1 << 13)), + (m.rotation_input_bottom19_limb_1, F::from_canonical_u64(1 << 29)), + ]), + ], + Filter::from_column(Column::single(m.is_lane_final)), + ) +} + +/// FP16 XorFoldStark's per-row LUT inventory: RC16 x10 — the four mul-add limbs, the +/// rotation-split bounds, and the canonicity cap `MULADD_HIGH_LIMB_1 + 1` that kills X1's `+p` +/// limb alias. (The FP8 table's two skip-budget-slack RC16 lookups are gone.) +/// +/// Both sub-16-bit splits use the unshifted + shifted RC16 pair, because a scaled RC16 alone +/// never bounds a Goldilocks column (`2^k` divides `v + j*p` for suitable `j`, producing huge +/// canonical aliases whose scaled key is still `< 2^16`): +/// - `ROTATION_INPUT_TOP13`: the unshifted check prevents wrap, then the `2^3`-scaled check gives +/// the 13-bit bound. +/// - `ROTATION_INPUT_BOTTOM19_LIMB_1`: the unshifted check plus the `2^13`-scaled check gives the +/// 3-bit bound. Without the unshifted half, an alias can satisfy X2's split while moving +/// `FOLD_OUT`, enabling free lottery grinding. +pub fn xor_fold_lut_lookups() -> Vec> { + let m = &XOR_FOLD_COL_MAP; + vec![ + LutLookup::rc16(Column::single(m.muladd_low_limb_0)), + LutLookup::rc16(Column::single(m.muladd_low_limb_1)), + LutLookup::rc16(Column::single(m.muladd_high_limb_0)), + LutLookup::rc16(Column::single(m.muladd_high_limb_1)), + LutLookup::rc16(Column::single(m.rotation_input_bottom19_limb_0)), + LutLookup::rc16(Column::single(m.rotation_input_top13)), + LutLookup::rc16(Column::linear_combination([( + m.rotation_input_top13, + F::from_canonical_u64(1 << 3), + )])), + LutLookup::rc16(Column::single(m.rotation_input_bottom19_limb_1)), + LutLookup::rc16(Column::linear_combination([( + m.rotation_input_bottom19_limb_1, + F::from_canonical_u64(1 << 13), + )])), + LutLookup::rc16(Column::linear_combination_with_constant( + [(m.muladd_high_limb_1, F::ONE)], + F::ONE, + )), + ] +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use super::*; + use crate::circuit::fp8::luts::LutTable; + + type F = GoldilocksField; + + #[test] + fn xor_fold_ctl_halves_are_well_formed() { + // The table index is supplied at batch-integration time; any placeholder is fine here. + ctl_cell_results_looking_xor_fold::(7); + ctl_lottery_words_looked_xor_fold::(7); + } + + #[test] + fn xor_fold_lut_inventory_matches_documented_counts() { + // Documented inventory: 10 RC16 instances, nothing else. + let lookups = xor_fold_lut_lookups::(); + assert_eq!(lookups.len(), 10); + assert!(lookups.iter().all(|l| l.table == LutTable::Range16)); + } +} diff --git a/zk-pow/src/circuit/fp16/xor_fold_stark/mod.rs b/zk-pow/src/circuit/fp16/xor_fold_stark/mod.rs new file mode 100644 index 000000000..0e04ee4cb --- /dev/null +++ b/zk-pow/src/circuit/fp16/xor_fold_stark/mod.rs @@ -0,0 +1,20 @@ +//! FP16 lottery mixer: for each assigned f32 result word, proves +//! `fold_out = rotl32(low32(fold_state_in * 0x9E3779B1 + cell_word), 13)`. +//! The hexadecimal multiplier and 13-bit rotation are fixed protocol mixing constants (shared +//! with the plaintext extractor [`crate::api::fp8::utils::xor_fold_extract`]). Sixteen independent +//! lanes produce the sixteen words of Blake3's jackpot message block. +//! +//! The FP16 analogue of [`crate::circuit::fp8::xor_fold_stark`], without the FP8 consolidated +//! skip-gate (FP16 scores its jackpot in [`crate::circuit::fp16::policy_stark`]). +//! +//! Status: the AIR and its constraint/LUT tests are complete; wiring the cell-results and +//! lottery-words CTL channels into the batch driver is the next increment (it needs the Blake3 +//! commitment/jackpot table as the lottery-words counterparty — see +//! `docs/fp16_scheme/zk_binding_design.md`). + +pub mod columns; +pub mod ctl; +pub mod stark; + +pub use columns::{NUM_XOR_FOLD_COLUMNS, NUM_XOR_FOLD_PUBLIC_INPUTS, XOR_FOLD_COL_MAP, XorFoldColumnsView}; +pub use stark::{XorFoldProgram, XorFoldStark}; diff --git a/zk-pow/src/circuit/fp16/xor_fold_stark/stark.rs b/zk-pow/src/circuit/fp16/xor_fold_stark/stark.rs new file mode 100644 index 000000000..916febfcb --- /dev/null +++ b/zk-pow/src/circuit/fp16/xor_fold_stark/stark.rs @@ -0,0 +1,478 @@ +//! Proves the protocol's 32-bit XorFold lottery mixer for FP16, one matmul-output cell per live +//! row: +//! +//! ```text +//! cell_word = cell_result_f32_lo + 2^16*cell_result_f32_hi +//! mixed = fold_state_in*0x9E3779B1 + cell_word +//! fold_out = rotate_left_32(low_32_bits(mixed), 13) +//! ``` +//! +//! `cell_word` is the raw f32 bit pattern emitted by the matmul (`cell_result_f32_lo/hi`). +//! `0x9E3779B1` and the 13-bit rotation are fixed protocol mixing constants, shared with the +//! plaintext extractor [`crate::api::fp8::utils::xor_fold_extract`]. +//! +//! This is the FP16 analogue of [`crate::circuit::fp8::xor_fold_stark`] with the FP8 +//! consolidated-policy skip census removed (FP16 scores its jackpot in +//! [`crate::circuit::fp16::policy_stark`]). Only three constraint groups remain: +//! +//! * **X1** — multiply-add split: `FOLD_STATE_IN*0x9E3779B1 + W = HI*2^32 + LO` over the integers. +//! The honest value is `< 2^63.5` (no field wrap); the `MULADD_HIGH_LIMB_1 <= 0xFFFE` cap +//! (RC16 inventory) keeps the limb side below `p` too, ruling out the `+p` limb alias. +//! * **X2** — `rotl32` by 13 is a pure re-split of the low word: `LO = TOP13*2^19 + BOT19`, so +//! `FOLD_OUT = BOT19*2^13 + TOP13`. +//! * **X3** — lane chaining: state 0 entering the first row, a lane-final row resets the next +//! row's state, otherwise the state chains `FOLD_OUT`. +//! +//! The verifier recomputes `cell_id`, `lane_id`, `is_lane_final`, and `is_pad` from the public +//! lane assignment and checks their openings. The 10 RC16 facts (limbs, split bounds, the +//! `MULADD_HIGH_LIMB_1` canonicity cap) live in [`super::ctl::xor_fold_lut_lookups`]. + +use core::borrow::Borrow; +use std::marker::PhantomData; + +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::packed::PackedField; +use plonky2::field::polynomial::PolynomialValues; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use starky::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; +use starky::stark::Stark; + +use super::columns::{NUM_XOR_FOLD_COLUMNS, NUM_XOR_FOLD_PUBLIC_INPUTS, XorFoldColumnsView}; +use crate::api::layout::JACKPOT_ENTRIES as XOR_FOLD_LANES; +use crate::circuit::utils::evaluator::Evaluator; +use crate::circuit::utils::native_evaluator::NativeEvaluator; +use crate::circuit::utils::symbolic_evaluator::SymbolicEvaluator; + +/// The protocol's fixed odd mixing multiplier (the golden-ratio-derived XorFold constant). +const GOLDEN: u64 = 0x9E3779B1; + +/// The committed lane layout: `lanes[j]` lists lane `j`'s cell ids in fold order +/// (`crate::api::layout::lane_assignment`). +#[derive(Clone, Debug)] +pub struct XorFoldProgram { + pub lanes: Vec>, +} + +impl XorFoldProgram { + /// One row per folded cell (`h*w` live rows). + pub fn live_rows(&self) -> usize { + self.lanes.iter().map(Vec::len).sum() + } + + /// Trace height: the live rows padded to the next power of two with all-zero `IS_PAD = 1` + /// rows. + pub fn num_rows(&self) -> usize { + self.live_rows().next_power_of_two() + } + + /// `cell_words[c]` is cell `c`'s f32 bit pattern. The matmul exposes it on its + /// `IS_CELL_FINAL` row via the cell-results CTL. + pub fn generate_trace(&self, cell_words: &[u32]) -> Vec<[F; NUM_XOR_FOLD_COLUMNS]> { + assert_eq!(self.lanes.len(), XOR_FOLD_LANES, "the lottery block has 16 lanes"); + // Each cell folded exactly once; no lane empty (an empty lane has no IS_LANE_FINAL row + // and the Blake3 lottery channel cannot balance). + let mut seen = vec![false; cell_words.len()]; + for lane in &self.lanes { + assert!(!lane.is_empty(), "empty lane"); + for &c in lane { + assert!(!std::mem::replace(&mut seen[c], true), "cell {c} folded twice"); + } + } + assert!(seen.iter().all(|&s| s), "not every cell is folded"); + + let mut rows: Vec<[F; NUM_XOR_FOLD_COLUMNS]> = Vec::with_capacity(self.num_rows()); + for (j, lane) in self.lanes.iter().enumerate() { + let mut state = 0u32; + for (step, &cell) in lane.iter().enumerate() { + // The leading four columns are class (a) — keep in sync with known_values. + let w = cell_words[cell]; + let t = state as u64 * GOLDEN + w as u64; // < 2^63.5: exact in the field too + let (lo, hi) = (t as u32, (t >> 32) as u32); + debug_assert!(hi >> 16 <= 0x9E38, "honest top limb under the 0xFFFE cap"); + let row = XorFoldColumnsView:: { + cell_id: F::from_canonical_usize(cell), + lane_id: F::from_canonical_usize(j), + is_lane_final: F::from_bool(step == lane.len() - 1), + is_pad: F::ZERO, + cell_result_f32_lo: F::from_canonical_u32(w & 0xFFFF), + cell_result_f32_hi: F::from_canonical_u32(w >> 16), + fold_state_in: F::from_canonical_u32(state), + muladd_low_limb_0: F::from_canonical_u32(lo & 0xFFFF), + muladd_low_limb_1: F::from_canonical_u32(lo >> 16), + muladd_high_limb_0: F::from_canonical_u32(hi & 0xFFFF), + muladd_high_limb_1: F::from_canonical_u32(hi >> 16), + rotation_input_top13: F::from_canonical_u32(lo >> 19), + rotation_input_bottom19_limb_0: F::from_canonical_u32(lo & 0xFFFF), + rotation_input_bottom19_limb_1: F::from_canonical_u32((lo >> 16) & 0x7), + }; + rows.push(row.into()); + state = lo.rotate_left(13); + } + } + // Pad to the next power of two: all-zero IS_PAD rows. X1-X3 hold on zeros (the last live + // row is lane-final, so the pad chain starts and stays at state 0). + let pad_row = XorFoldColumnsView:: { + is_pad: F::ONE, + ..XorFoldColumnsView::default() + }; + rows.resize(self.num_rows(), pad_row.into()); + rows + } + + /// The class (a) ("known") column values — the leading + /// [`NUM_XOR_FOLD_KNOWN_COLUMNS`](super::columns::NUM_XOR_FOLD_KNOWN_COLUMNS) trace columns + /// in their `columns.rs` order (`CELL_ID`, `LANE_ID`, `IS_LANE_FINAL`, `IS_PAD`), pure + /// functions of the committed lane layout. Bit-exact with [`Self::generate_trace`]'s fill. + pub fn known_values(&self) -> Vec> { + let num_rows = self.num_rows(); + let mut cell_id = Vec::with_capacity(num_rows); + let mut lane_id = Vec::with_capacity(num_rows); + let mut is_lane_final = Vec::with_capacity(num_rows); + for (j, lane) in self.lanes.iter().enumerate() { + for (step, &cell) in lane.iter().enumerate() { + cell_id.push(F::from_canonical_usize(cell)); + lane_id.push(F::from_canonical_usize(j)); + is_lane_final.push(F::from_bool(step == lane.len() - 1)); + } + } + let mut is_pad = vec![F::ZERO; cell_id.len()]; + for col in [&mut cell_id, &mut lane_id, &mut is_lane_final] { + col.resize(num_rows, F::ZERO); + } + is_pad.resize(num_rows, F::ONE); + [cell_id, lane_id, is_lane_final, is_pad] + .into_iter() + .map(PolynomialValues::new) + .collect() + } +} + +/// Evaluates the X1-X3 constraint groups (module docs). The 10 RC16 facts (limbs, split bounds, +/// the `MULADD_HIGH_LIMB_1` canonicity cap) live in `super::ctl::xor_fold_lut_lookups`. +pub(crate) fn eval_xor_fold_constraints( + vars: &StarkFrame, + eval: &mut E, +) where + V: Copy + Default, + S: Copy + Default, + E: Evaluator, +{ + let lv: &[V; NUM_XOR_FOLD_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let lv: &XorFoldColumnsView = lv.borrow(); + let nv: &[V; NUM_XOR_FOLD_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let nv: &XorFoldColumnsView = nv.borrow(); + + let one = eval.u64(1); + let two16 = eval.u64(1 << 16); + + // X1 — multiply-add split: FOLD_STATE_IN*0x9E3779B1 + W = HI*2^32 + LO over the integers. + // The honest value is < 2^63.5 (no field wrap); the MULADD_HIGH_LIMB_1 <= 0xFFFE cap + // (RC16 inventory) keeps the limb side below p too — without it every row with value + // < 2^32 (all lane starts) would admit the `+p` limb alias, forging the folded word. + let golden = eval.u64(GOLDEN); + let two32 = eval.u64(1 << 32); + let w_hi = eval.mul(two16, lv.cell_result_f32_hi); + let w = eval.add(lv.cell_result_f32_lo, w_hi); + let muladd = eval.mad(lv.fold_state_in, golden, w); + let lo_1 = eval.mul(two16, lv.muladd_low_limb_1); + let lo = eval.add(lv.muladd_low_limb_0, lo_1); + let hi_1 = eval.mul(two16, lv.muladd_high_limb_1); + let hi = eval.add(lv.muladd_high_limb_0, hi_1); + let limbs = eval.mad(hi, two32, lo); + eval.constraint_eq(muladd, limbs); + + // X2 — rotl32 by 13 is a pure re-split of the low word: LO = TOP13*2^19 + BOT19. + let two19 = eval.u64(1 << 19); + let bot19_1 = eval.mul(two16, lv.rotation_input_bottom19_limb_1); + let bot19 = eval.add(lv.rotation_input_bottom19_limb_0, bot19_1); + let split = eval.mad(lv.rotation_input_top13, two19, bot19); + eval.constraint_eq(lo, split); + + // The rotated word: FOLD_OUT = BOT19*2^13 + TOP13 (affine, not a column). + let two13 = eval.u64(1 << 13); + let fold_out = eval.mad(bot19, two13, lv.rotation_input_top13); + + // X3 — chaining: 0 entering the first row; a lane-final row resets the next row's state; + // otherwise the state chains. The next-row constraints are plain (cyclic): on the wrap pair + // the last row is lane-final (a class (a) fact carried by the known-column binding), so the + // wrap instance is row 0's reset. + eval.constraint_first_row(lv.fold_state_in); + let reset = eval.mul(lv.is_lane_final, nv.fold_state_in); + eval.constraint(reset); + let not_final = eval.sub(one, lv.is_lane_final); + let chain_diff = eval.sub(nv.fold_state_in, fold_out); + let chain = eval.mul(not_final, chain_diff); + eval.constraint(chain); +} + +/// FP16 XorFoldStark. A CTL party of the FP16 batch (`requires_ctls()`): its proofs carry the +/// cross-table openings of the channels declared in `super::ctl`, so the batch driver is the only +/// supported proving path — there is no standalone uni-STARK proof object. +#[derive(Clone, Debug)] +pub struct XorFoldStark, const D: usize> { + pub program: XorFoldProgram, + _phantom: PhantomData, +} + +impl, const D: usize> XorFoldStark { + pub fn new(program: XorFoldProgram) -> Self { + Self { + program, + _phantom: PhantomData, + } + } +} + +impl, const D: usize> Stark for XorFoldStark { + type EvaluationFrame + = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = + StarkFrame, ExtensionTarget, NUM_XOR_FOLD_COLUMNS, NUM_XOR_FOLD_PUBLIC_INPUTS>; + + fn eval_packed_generic( + &self, + vars: &Self::EvaluationFrame, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + let mut evaluator = NativeEvaluator::new(yield_constr); + eval_xor_fold_constraints(vars, &mut evaluator); + } + + fn eval_ext_circuit( + &self, + builder: &mut CircuitBuilder, + vars: &Self::EvaluationFrameTarget, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + let mut evaluator = SymbolicEvaluator::new(builder, yield_constr); + eval_xor_fold_constraints(vars, &mut evaluator); + } + + fn constraint_degree(&self) -> usize { + 3 + } + + // Party to the cell-results and lottery-words channels plus the committed LUT channels + // (declared in `super::ctl`). + fn requires_ctls(&self) -> bool { + true + } +} + +// ================================================================================================== +// Tests +// ================================================================================================== + +#[cfg(test)] +mod tests { + use core::borrow::BorrowMut; + + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::field::types::{Field, PrimeField64}; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + use starky::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; + use starky::util::trace_rows_to_poly_values; + + use super::super::columns::XOR_FOLD_COL_MAP; + use super::super::ctl::xor_fold_lut_lookups; + use super::*; + use crate::api::fp8::utils::xor_fold_extract; + use crate::api::layout::{AxisPattern, DimType, lane_assignment}; + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = GoldilocksField; + type S = XorFoldStark; + + fn to_u64(x: F) -> u64 { + x.to_canonical_u64() + } + + /// The committed layout of `utils.rs`'s reference-vector test: an 8x8 merged tile, 16 lanes + /// of 4 cells each (per axis: fold offsets `{0, 1}`, blake offsets `{0, 2, 4, 6}`). + fn test_layout() -> (Vec, Vec>) { + let axis = AxisPattern::new(&[(2, DimType::Fold), (4, DimType::Blake)]).unwrap(); + let base = [1.0f32, -2.5, 0.0, 3.171875, 1e-3, -0.0, 448.0, 2.0, 0.5, -1.0]; + let tile: Vec = (0..64).map(|i| base[i % base.len()]).collect(); + (tile, lane_assignment(&axis, &axis)) + } + + fn test_trace() -> (XorFoldProgram, Vec<[F; NUM_XOR_FOLD_COLUMNS]>) { + let (tile, lanes) = test_layout(); + let program = XorFoldProgram { lanes }; + let words: Vec = tile.iter().map(|x| x.to_bits()).collect(); + let rows = program.generate_trace::(&words); + (program, rows) + } + + fn constraints_violated(stark: &S, rows: &[[F; NUM_XOR_FOLD_COLUMNS]]) -> bool { + let n = rows.len(); + (0..n).any(|i| { + let frame = StarkFrame::from_values(&rows[i], &rows[(i + 1) % n], &[]); + let mut consumer = ConstraintConsumer::new( + vec![F::from_canonical_u64(2), F::from_canonical_u64(0x876543210)], + F::from_bool(i != n - 1), + F::from_bool(i == 0), + F::from_bool(i == n - 1), + ); + stark.eval_packed_generic(&frame, &mut consumer); + consumer.accumulators().iter().any(|&acc| acc != F::ZERO) + }) + } + + fn lut_keys_are_in_domain(rows: &[[F; NUM_XOR_FOLD_COLUMNS]]) -> bool { + let polys = trace_rows_to_poly_values(rows.to_vec()); + xor_fold_lut_lookups::() + .iter() + .all(|lookup| (0..rows.len()).all(|r| lookup.keys[0].eval_table(&polys, r, &[]).to_canonical_u64() < 1 << 16)) + } + + #[test] + fn honest_trace_satisfies_all_constraints() { + let (program, rows) = test_trace(); + assert!(!constraints_violated(&S::new(program), &rows)); + } + + #[test] + fn padded_trace_satisfies_all_constraints() { + // A non-power-of-two live count: 16 lanes x 3 cells = 48 live rows, padded to 64. + let program = XorFoldProgram { + lanes: (0..16).map(|j| vec![3 * j, 3 * j + 1, 3 * j + 2]).collect(), + }; + let words: Vec = (0..48u32).map(|i| f32::to_bits(i as f32 - 20.5)).collect(); + let rows = program.generate_trace::(&words); + assert_eq!(rows.len(), 64, "48 live rows pad to 64"); + let known = program.known_values::(); + assert!(known.iter().all(|c| c.len() == 64)); + // The known columns are bit-exact with the trace fill (the batch verifier's check). + for (c, col) in known.iter().enumerate() { + for (r, row) in rows.iter().enumerate() { + assert_eq!(col.values[r], row[c], "known column {c} row {r}"); + } + } + assert!(!constraints_violated(&S::new(program), &rows)); + } + + #[test] + fn trace_is_bit_exact_vs_native_xor_fold_extract() { + let (tile, lanes) = test_layout(); + let (program, rows) = test_trace(); + let extracted = xor_fold_extract(&tile, &lanes); + let mut finals = 0; + for row in &rows { + let v: &XorFoldColumnsView = row.borrow(); + if v.is_lane_final != F::ONE { + continue; + } + finals += 1; + // FOLD_OUT recomposed from the rotation split = the extractor's LE lane word. + let bot19 = to_u64(v.rotation_input_bottom19_limb_0) + (to_u64(v.rotation_input_bottom19_limb_1) << 16); + let fold_out = (bot19 << 13) + to_u64(v.rotation_input_top13); + let lane = to_u64(v.lane_id) as usize; + let expected = u32::from_le_bytes(extracted[lane * 4..lane * 4 + 4].try_into().unwrap()); + assert_eq!(fold_out as u32, expected, "lane {lane}"); + } + assert_eq!(finals, XOR_FOLD_LANES); + drop(program); + } + + #[test] + fn lut_inventory_holds_on_honest_trace_and_catches_the_alias() { + let (_, rows) = test_trace(); + assert!(lut_keys_are_in_domain(&rows), "honest trace has an out-of-range RC16 key"); + + // The `+p` limb alias: at a lane start (state 0, t = W < 2^32) rewrite the limbs as + // t + p = (t + 1) + 0xFFFFFFFF*2^32 and re-split consistently. X1/X2 still vanish in the + // field — only the RC16(MULADD_HIGH_LIMB_1 + 1) canonicity cap catches the forgery. + let (tile, lanes) = test_layout(); + let words: Vec = tile.iter().map(|x| x.to_bits()).collect(); + let mut forged = rows.clone(); + { + let v: &mut XorFoldColumnsView = forged[0].borrow_mut(); + assert_eq!(v.fold_state_in, F::ZERO); + let t = to_u64(v.cell_result_f32_lo) | (to_u64(v.cell_result_f32_hi) << 16); + let lo = (t + 1) as u32; + v.muladd_low_limb_0 = F::from_canonical_u32(lo & 0xFFFF); + v.muladd_low_limb_1 = F::from_canonical_u32(lo >> 16); + v.muladd_high_limb_0 = F::from_canonical_u32(0xFFFF); + v.muladd_high_limb_1 = F::from_canonical_u32(0xFFFF); + v.rotation_input_top13 = F::from_canonical_u32(lo >> 19); + v.rotation_input_bottom19_limb_0 = F::from_canonical_u32(lo & 0xFFFF); + v.rotation_input_bottom19_limb_1 = F::from_canonical_u32((lo >> 16) & 0x7); + } + // Rewrite the rest of lane 0 so the chain stays consistent and only the alias row differs. + let lane0 = &lanes[0]; + let mut state = ((words[lane0[0]] as u64 + 1) as u32).rotate_left(13); + for (step, &cell) in lane0.iter().enumerate().skip(1) { + let t = state as u64 * GOLDEN + words[cell] as u64; + let (lo, hi) = (t as u32, (t >> 32) as u32); + let v: &mut XorFoldColumnsView = forged[step].borrow_mut(); + v.fold_state_in = F::from_canonical_u32(state); + v.muladd_low_limb_0 = F::from_canonical_u32(lo & 0xFFFF); + v.muladd_low_limb_1 = F::from_canonical_u32(lo >> 16); + v.muladd_high_limb_0 = F::from_canonical_u32(hi & 0xFFFF); + v.muladd_high_limb_1 = F::from_canonical_u32(hi >> 16); + v.rotation_input_top13 = F::from_canonical_u32(lo >> 19); + v.rotation_input_bottom19_limb_0 = F::from_canonical_u32(lo & 0xFFFF); + v.rotation_input_bottom19_limb_1 = F::from_canonical_u32((lo >> 16) & 0x7); + state = lo.rotate_left(13); + } + let (program, _) = test_trace(); + assert!( + !constraints_violated(&S::new(program), &forged), + "the alias must satisfy X1-X3 — it is the RC16 cap's job" + ); + assert!( + !lut_keys_are_in_domain(&forged), + "the RC16(MULADD_HIGH_LIMB_1 + 1) cap must catch the +p alias" + ); + } + + #[test] + fn tampered_traces_fail() { + let (program, rows) = test_trace(); + let stark = S::new(program); + let cases = [ + // A lane's chain: the next row's state no longer matches FOLD_OUT. + ("fold_state_in", XOR_FOLD_COL_MAP.fold_state_in), + // The folded word itself (X1 breaks). + ("cell_result_f32_lo", XOR_FOLD_COL_MAP.cell_result_f32_lo), + // The rotation split (X2 breaks). + ("rotation_input_top13", XOR_FOLD_COL_MAP.rotation_input_top13), + // A mid-lane final flag (0 -> 1): the reset forces the next state to 0 (false here). + ("is_lane_final", XOR_FOLD_COL_MAP.is_lane_final), + ]; + for (name, col) in cases { + let mut forged = rows.clone(); + // Row 1 is mid-lane (lanes have 4 cells) and has a nonzero next state. + forged[1][col] += F::ONE; + assert!(constraints_violated(&stark, &forged), "{name} tamper undetected"); + } + } + + #[test] + fn degree_is_at_most_three() { + let (program, _) = test_trace(); + test_stark_low_degree::(S::new(program)).unwrap(); + } + + #[test] + fn circuit_constraints_match_native() { + let (program, _) = test_trace(); + test_stark_circuit_constraints::(S::new(program)).unwrap(); + } + + // No standalone prove/verify smoke test: this table is a CTL party (`requires_ctls`), so a + // proof without the cross-table argument is not a supported object. The end-to-end proving + // path is covered once the table is wired into `fp16::driver`. +} diff --git a/zk-pow/src/circuit/fp8/luts/columns.rs b/zk-pow/src/circuit/fp8/luts/columns.rs index 29ff29d04..88692e8f0 100644 --- a/zk-pow/src/circuit/fp8/luts/columns.rs +++ b/zk-pow/src/circuit/fp8/luts/columns.rs @@ -20,15 +20,20 @@ pub const fn num_slots(table: LutTable) -> usize { /// Live rows per slot (the key-domain size; [`lut_height`] rounds it up to the AIR height). pub const fn slot_height(table: LutTable) -> usize { match table { - LutTable::Range16 | LutTable::Bytes2 | LutTable::Qcast | LutTable::Div448 | LutTable::Width16 | LutTable::Log16 => { - 1 << 16 - } + LutTable::Range16 + | LutTable::Bytes2 + | LutTable::Qcast + | LutTable::Div448 + | LutTable::Width16 + | LutTable::Log16 + | LutTable::Fp16Decode => 1 << 16, LutTable::Pair128 => 1 << 14, LutTable::Int8Dec => 256, LutTable::ExpInfo => 255, // keys [0, 254]; the inf/NaN field 255 has no row LutTable::Clamp22 => 601, // keys x + 400, x in [-400, 200] LutTable::Pow2D => 20, // keys [0, 19]; the FMA's gap cap of 19 sets the domain LutTable::Pow2G | LutTable::Pow2Gb => 64, + LutTable::Fp16Pow2 => 256, // keys [0, 255]; FP16's relative-shift span (see mod docs) LutTable::Width32 => 32, // keys [1, 32] — a shifted ramp, no key 0 (see `generate`) LutTable::RneRnd => 1 << 17, LutTable::ProdAlign15 | LutTable::B200Align | LutTable::WidthNorm => 1 << 16, @@ -61,9 +66,10 @@ const fn num_value_columns(table: LutTable) -> usize { | LutTable::Clamp22 | LutTable::Pow2D | LutTable::Pow2Gb + | LutTable::Fp16Pow2 | LutTable::Log16 => 1, LutTable::Width32 | LutTable::Width16 => 2, - LutTable::Int8Dec => 4, + LutTable::Int8Dec | LutTable::Fp16Decode => 4, LutTable::WidthNorm => 6, // slot-zero outputs and four right-shifted ramps LutTable::Pow2G => 7, // two saturated keys and five values LutTable::ProdAlign15 | LutTable::B200Align => 11, // eight truncations and three decode fields @@ -152,9 +158,10 @@ pub fn lut_slot_layout(table: LutTable, slot: usize) -> LutSlotLayout< | LutTable::Clamp22 | LutTable::Pow2D | LutTable::Pow2Gb + | LutTable::Fp16Pow2 | LutTable::Log16 => (0, vec![Column::single(nk)]), LutTable::Width32 | LutTable::Width16 => (0, Column::singles([nk, nk + 1]).collect()), - LutTable::Int8Dec => (0, Column::singles(nk..nk + 4).collect()), + LutTable::Int8Dec | LutTable::Fp16Decode => (0, Column::singles(nk..nk + 4).collect()), LutTable::ProdAlign15 | LutTable::B200Align => { let shift = if table == LutTable::ProdAlign15 { 7 } else { 19 }; let aligned = if slot <= shift { diff --git a/zk-pow/src/circuit/fp8/luts/mod.rs b/zk-pow/src/circuit/fp8/luts/mod.rs index 8e3797999..eb6c19341 100644 --- a/zk-pow/src/circuit/fp8/luts/mod.rs +++ b/zk-pow/src/circuit/fp8/luts/mod.rs @@ -59,9 +59,10 @@ pub use columns::{ }; pub use ctl::ctl_looked_lut_slot; pub use stark::{ - B200AlignStark, Bytes2Stark, Clamp22Stark, Div448Stark, ExpInfoStark, Int8DecStark, Log16Stark, LutStark, Pair128Stark, - Pow2DStark, Pow2GStark, Pow2GbStark, ProdAlign15Stark, QcastStark, Range16Stark, RneRndStark, Width16Stark, Width32Stark, - WidthNormStark, generate, lut_precommitted_values, lut_preprocessed_data, lut_preprocessed_inputs, lut_trace, + B200AlignStark, Bytes2Stark, Clamp22Stark, Div448Stark, ExpInfoStark, Fp16DecodeStark, Fp16Pow2Stark, Int8DecStark, + Log16Stark, LutStark, Pair128Stark, Pow2DStark, Pow2GStark, Pow2GbStark, ProdAlign15Stark, QcastStark, Range16Stark, + RneRndStark, Width16Stark, Width32Stark, WidthNormStark, generate, lut_precommitted_values, lut_preprocessed_data, + lut_preprocessed_inputs, lut_trace, }; pub use witness::{LutChecker, LutMultiplicities}; @@ -153,6 +154,24 @@ pub enum LutTable { /// (0 at the key-0 sentinel). InputQuant binds it on the summand's sum of squares to /// build the lambda scores. Log16, + /// FP16 operand decode for the A100 matmul ([`crate::circuit::fp16::matmul_a100_stark`]), + /// keyed by the 16-bit FP16 code (`2^16` rows), tuple value + /// `(SIG, SIGN, EPS_BIASED, IS_ZERO)` = [`crate::api::fp16::dtype::fp16_decode_fields`]: + /// the integer significand `m`, the raw sign bit, the biased stored exponent `eps + 15`, + /// and `[m == 0]`. Two lookups per lane (A and B operand) pin the per-operand decode a + /// lane's in-AIR product/sign/exponent are derived from; FP16 operand pairs span `2^32`, so + /// (unlike FP8's `B200Align`) the product itself cannot be a single keyed lookup. This table + /// is **not** part of any FP8 device's committed inventory; it is used only by the FP16 + /// batch ([`crate::circuit::fp16::ctl`]). + Fp16Decode, + /// A100 matmul alignment power-of-two, keyed `d in [0, 255]`, value `2^min(d, 26)`. Same + /// shape as [`LutTable::Pow2Gb`] but with the wider key domain FP16's exponent span needs: + /// a lane/carry relative shift `GROUP_MAX_BIASED_EXPONENT - PRODUCT_BIASED_EXPONENT` can + /// reach ~155 when a large carry (or product) dominates a tiny term (which the 2^26 cap + /// floors to zero, exactly as the window drops it). The missing negative keys prove + /// `GROUP_MAX_BIASED_EXPONENT >= PRODUCT_BIASED_EXPONENT` (the eta ">=" side). FP16 batch + /// only ([`crate::circuit::fp16::ctl`]). + Fp16Pow2, } #[cfg(test)] diff --git a/zk-pow/src/circuit/fp8/luts/stark.rs b/zk-pow/src/circuit/fp8/luts/stark.rs index aac7d3219..e5f1dc707 100644 --- a/zk-pow/src/circuit/fp8/luts/stark.rs +++ b/zk-pow/src/circuit/fp8/luts/stark.rs @@ -28,6 +28,7 @@ use super::super::unpredictability::{log2_fixed, sig_nonzero, sig_width}; use super::LutTable; use super::columns::{lut_height, lut_num_columns, num_precommitted_columns, num_slots, rnernd_stored_values, slot_height}; use crate::api::fp8::compute::bf16_div; +use crate::api::fp16::dtype::fp16_decode_fields; /// Generates one slot's semantic values before fixed-column factoring, in the order /// the consumers' `LutLookup::values` bind them. @@ -45,7 +46,7 @@ pub fn generate(table: LutTable, slot: usize) -> Vec> { | LutTable::Width32 | LutTable::Width16 | LutTable::Pow2G => 2, - LutTable::Int8Dec | LutTable::RneRnd => 4, + LutTable::Int8Dec | LutTable::RneRnd | LutTable::Fp16Decode => 4, LutTable::ProdAlign15 | LutTable::B200Align => 5, _ => 1, }; @@ -206,6 +207,16 @@ pub fn generate(table: LutTable, slot: usize) -> Vec> { } // Jackpot check 4's fixed-point log: `floor(64 * log2 key)` (0 at key 0). LutTable::Log16 => columns[0].push(f(log2_fixed(key))), + // A100 matmul alignment: 2^min(d, 26), floor a far term to zero (P*16 < 2^26). + LutTable::Fp16Pow2 => columns[0].push(f(1 << key.min(26))), + // FP16 operand decode (A100 matmul): (SIG, SIGN, EPS_BIASED, IS_ZERO). + LutTable::Fp16Decode => { + let (sig, sign, eps_biased, is_zero) = fp16_decode_fields(key as u16); + columns[0].push(f(sig)); + columns[1].push(f(sign)); + columns[2].push(f(eps_biased)); + columns[3].push(f(is_zero)); + } } } columns @@ -224,7 +235,7 @@ pub fn lut_precommitted_values(table: LutTable) -> Vec> { LutTable::Bytes2 | LutTable::Pair128 => cols.extend(generate::(table, 0)), // Sub-height (or exactly-full) small tables: a saturated key column `min(i, live - 1)` // and the value columns padded alike — padding repeats the last live row's fact. - LutTable::Int8Dec | LutTable::ExpInfo | LutTable::Clamp22 | LutTable::Pow2D | LutTable::Pow2Gb => { + LutTable::Int8Dec | LutTable::ExpInfo | LutTable::Clamp22 | LutTable::Pow2D | LutTable::Pow2Gb | LutTable::Fp16Pow2 => { cols.push((0..height).map(|i| F::from_canonical_usize(i.min(live - 1))).collect()); for mut col in generate::(table, 0) { let last = *col.last().unwrap(); @@ -243,7 +254,9 @@ pub fn lut_precommitted_values(table: LutTable) -> Vec> { cols.push((0..height).map(F::from_canonical_usize).collect()); match table { LutTable::Range16 => {} // the ramp is the whole table - LutTable::Qcast | LutTable::Div448 | LutTable::Width16 | LutTable::Log16 => cols.extend(generate::(table, 0)), + LutTable::Qcast | LutTable::Div448 | LutTable::Width16 | LutTable::Log16 | LutTable::Fp16Decode => { + cols.extend(generate::(table, 0)) + } // Eight signed truncations span every alignment shift; decode fields are shared. LutTable::ProdAlign15 | LutTable::B200Align => { let shift = if table == LutTable::ProdAlign15 { 7 } else { 19 }; @@ -390,6 +403,8 @@ pub type Pow2GbStark = LutStark = LutStark; pub type Width16Stark = LutStark; pub type Log16Stark = LutStark; +pub type Fp16DecodeStark = LutStark; +pub type Fp16Pow2Stark = LutStark; /// One LUT AIR at its table's exact width (the width is a compile-time constant per table, /// so the dispatch is a static match). @@ -413,6 +428,8 @@ pub(crate) fn boxed_lut_stark, const D: usize>(tabl LutTable::Width32 => Box::new(Width32Stark::::new(table)), LutTable::Width16 => Box::new(Width16Stark::::new(table)), LutTable::Log16 => Box::new(Log16Stark::::new(table)), + LutTable::Fp16Decode => Box::new(Fp16DecodeStark::::new(table)), + LutTable::Fp16Pow2 => Box::new(Fp16Pow2Stark::::new(table)), } } diff --git a/zk-pow/src/circuit/mod.rs b/zk-pow/src/circuit/mod.rs index 14986488b..e22450740 100644 --- a/zk-pow/src/circuit/mod.rs +++ b/zk-pow/src/circuit/mod.rs @@ -3,5 +3,6 @@ pub mod chip; pub mod fp8; +pub mod fp16; pub mod pearl_program; pub mod utils; diff --git a/zk-pow/src/ffi/plain_proof.rs b/zk-pow/src/ffi/plain_proof.rs index b027db27f..8a3b166e0 100644 --- a/zk-pow/src/ffi/plain_proof.rs +++ b/zk-pow/src/ffi/plain_proof.rs @@ -175,6 +175,14 @@ pub enum CertificateVersion { ZkV3 = 3, /// V4: FP8 proofs (dense or MoE). PlainFp8 = 4, + /// V5: FP16 (A100) certificate. NOTE the `PlainFp16` name is historical: the + /// wired V5 consensus artifact is the header-bound ZK certificate + /// (`verify_fp16_zk_cert_ffi`), NOT a plaintext proof. The plaintext + /// [`crate::api::fp16::plain_proof::Fp16PlainProof`] is retired as a consensus + /// path and now serves only as the prover's operand-opener bundle. The wire + /// value (5) is what consensus binds; the symbol is kept to avoid a + /// cross-language (Rust/pyo3/Go/gateway) rename churn. + PlainFp16 = 5, } impl CertificateVersion { @@ -182,7 +190,10 @@ impl CertificateVersion { /// single version→derivation mapping; the `api` layer only sees [`SeedDerivation`]. pub fn seed_derivation(self) -> SeedDerivation { match self { - Self::ZkDense | Self::ZkMoe | Self::PlainFp8 => SeedDerivation::Legacy, + // PlainFp16 derives its own B-then-A noise-seed chain + // (`crate::api::fp16::noise`); this Int7/FP8-layer mapping is inert + // for it, so it takes the Legacy default alongside PlainFp8. + Self::ZkDense | Self::ZkMoe | Self::PlainFp8 | Self::PlainFp16 => SeedDerivation::Legacy, Self::ZkV3 => SeedDerivation::Salted, } } @@ -197,6 +208,7 @@ impl TryFrom for CertificateVersion { v if v == Self::ZkMoe as u32 => Ok(Self::ZkMoe), v if v == Self::ZkV3 as u32 => Ok(Self::ZkV3), v if v == Self::PlainFp8 as u32 => Ok(Self::PlainFp8), + v if v == Self::PlainFp16 as u32 => Ok(Self::PlainFp16), v => bail!("unknown certificate version: {v}"), } } @@ -294,13 +306,20 @@ impl PlainProof { /// Checks that this Int7 proof can be certified at `cert_version` and /// returns the parsed version. Certificate version 4 (PlainFp8) requires - /// [`crate::api::fp8::plain_proof::PlainProofV4`]. + /// [`crate::api::fp8::plain_proof::PlainProofV4`]; version 5 (PlainFp16) + /// requires [`crate::api::fp16::plain_proof::Fp16PlainProof`]. Both carry a + /// different witness type than the Int7 `PlainProof`, so neither is eligible + /// here. pub fn check_cert_version_eligible(&self, cert_version: u32) -> Result { let version = CertificateVersion::try_from(cert_version)?; ensure!( version != CertificateVersion::PlainFp8, "Int7 PlainProof is not eligible at certificate version 4 (PlainFp8); use PlainProofV4" ); + ensure!( + version != CertificateVersion::PlainFp16, + "Int7 PlainProof is not eligible at certificate version 5 (PlainFp16); use Fp16PlainProof" + ); let min_version = self.min_cert_version() as u32; ensure!( min_version <= cert_version, diff --git a/zk-pow/src/ffi/pybind.rs b/zk-pow/src/ffi/pybind.rs index 26840775a..3c94857d8 100644 --- a/zk-pow/src/ffi/pybind.rs +++ b/zk-pow/src/ffi/pybind.rs @@ -13,6 +13,8 @@ use crate::v2::api::proof::{MMAType, MiningConfiguration, MoEConfig, PeriodicPat #[cfg(feature = "pyo3")] pub use fp8::{PyFp8Prover, PyFp8Verifier}; +#[cfg(feature = "pyo3")] +pub use fp16::PyFp16Prover; // ============================================================================= // Python bindings (constructors for core types with #[pyclass] attribute) @@ -334,3 +336,96 @@ mod fp8 { } } } + +// ============================================================================= +// FP16 ZK prove bindings +// ============================================================================= + +/// Python `Fp16Prover` over [`crate::api::fp16::zk`]. Turns a winning A100 tile +/// (opened operand codes + the public [`Fp16JobParams`]) into the serialized +/// [`Fp16ZkCertificate`] bytes the node's `CertificateV5.ProofData` carries. +/// +/// There is no FP16 verifier binding here: FP16 consensus verification is the +/// node's job via the `verify_fp16_zk_cert_ffi` FFI (the header-bound gateway), +/// not a Python entry point. +/// +/// [`Fp16JobParams`]: crate::api::fp16::plain_proof::Fp16JobParams +/// [`Fp16ZkCertificate`]: crate::api::fp16::zk_cert::Fp16ZkCertificate +#[cfg(feature = "pyo3")] +mod fp16 { + use pyo3::prelude::*; + use pyo3::types::PyBytes; + + use crate::api::fp16::plain_proof::{Fp16JobParams, Fp16PlainProof}; + use crate::api::fp16::zk::Fp16Prover; + use crate::api::primitives::IncompleteBlockHeader; + + fn runtime_err(context: &str, error: impl core::fmt::Display) -> PyErr { + pyo3::exceptions::PyRuntimeError::new_err(format!("{context}: {error}")) + } + + /// Reusable FP16 prover. Retains one compiled wrapper per tile geometry + /// (the FP16 wrapper is per-shape; see [`crate::api::fp16::zk`]). + #[pyclass(name = "Fp16Prover")] + pub struct PyFp16Prover { + inner: Fp16Prover, + } + + #[pymethods] + impl PyFp16Prover { + /// A fresh prover; geometries compile lazily on first `prove`. + #[new] + fn new() -> Self { + Self { inner: Fp16Prover::new() } + } + + /// Eagerly compiles the wrapper for one tile geometry so a later `prove` + /// of that shape does not pay the (minutes-long) compilation cost. `(h, w)` + /// are the tile sizes (`P_A.tile_size()` / `P_B.tile_size()`); `hash_id` + /// is the operand Merkle chunk id (both sides use it here). + fn setup_geometry(&mut self, h: usize, w: usize, k: usize, hash_id: crate::api::fp8::public_params::HashId) -> PyResult<()> { + self.inner + .setup_geometry(h, w, k, hash_id, hash_id) + .map_err(|e| runtime_err("fp16 wrapper compilation failed", e)) + } + + /// Proves one winning tile and returns the serialized `Fp16ZkCertificate` + /// bytes (`CertificateV5.ProofData`). `a_codes`/`b_codes` are the opened + /// `h x k` / `w x k` FP16 operand bit patterns; `job` fixes the geometry + /// and the noise-seed `p` encodings; `proposed_header` keys the A side. + fn prove<'py>( + &mut self, + py: Python<'py>, + proposed_header: IncompleteBlockHeader, + job: Fp16JobParams, + a_codes: Vec, + b_codes: Vec, + ) -> PyResult> { + let cert = self + .inner + .prove(&proposed_header, &job, &a_codes, &b_codes) + .map_err(|e| runtime_err("fp16 prove failed", e))?; + let bytes = cert.to_bytes().map_err(|e| runtime_err("serializing fp16 certificate failed", e))?; + Ok(PyBytes::new(py, &bytes)) + } + + /// Proves directly from the `Fp16PlainProof` opener bundle the miner + /// already assembles for a winning tile: it authenticates + re-opens the + /// tile codes under `proposed_header` (catching a malformed opening before + /// the minutes-long prove), then proves. Returns the serialized + /// `Fp16ZkCertificate` bytes (`CertificateV5.ProofData`). + fn prove_from_plain_proof<'py>( + &mut self, + py: Python<'py>, + proposed_header: IncompleteBlockHeader, + plain_proof: Fp16PlainProof, + ) -> PyResult> { + let cert = self + .inner + .prove_from_plain_proof(&proposed_header, &plain_proof) + .map_err(|e| runtime_err("fp16 prove failed", e))?; + let bytes = cert.to_bytes().map_err(|e| runtime_err("serializing fp16 certificate failed", e))?; + Ok(PyBytes::new(py, &bytes)) + } + } +} diff --git a/zk-pow/tests/fp16_gpu_zk_verify.rs b/zk-pow/tests/fp16_gpu_zk_verify.rs new file mode 100644 index 000000000..0d4c86f2d --- /dev/null +++ b/zk-pow/tests/fp16_gpu_zk_verify.rs @@ -0,0 +1,88 @@ +//! On-hardware FP16/A100 end-to-end ZK consensus validation. +//! +//! Ingests the plain-proof bundle produced by the REAL sm_80 GPU lottery search +//! (`pearl_gemm.fp16_miner.search_block` on the local CMP 170HX, dumped by the +//! driver as `header(76) | u32le len | Fp16PlainProof::to_bytes()`), proves it +//! into the header-bound `Fp16ZkCertificate` with the production `Fp16Prover`, +//! and verifies that wrapped proof through the PRODUCTION verifier cache +//! (`src/api/fp16/fp16_cache.bin`) via `verify_wrapped_proof_with_headers` -- +//! exactly the path the node FFI (`verify_fp16_zk_cert_ffi`) runs. A flipped +//! proof byte must be rejected. +//! +//! Heavy (recursive wrap ~12-15 min); ignored by default. Run: +//! ```text +//! GPU_FP16_BUNDLE=/mnt/raid/projects/pearl-scratch/gpu_fp16_plain_proof.bin \ +//! cargo test -p zk-pow --test fp16_gpu_zk_verify --release -- \ +//! gpu_tile_proves_and_verifies_through_cache --ignored --exact --nocapture +//! ``` + +use plonky2::plonk::proof::ProofWithPublicInputs; + +use zk_pow::api::fp16::zk::Fp16Prover; +use zk_pow::api::fp16::plain_proof::Fp16PlainProof; +use zk_pow::api::primitives::IncompleteBlockHeader; +use zk_pow::circuit::fp16::driver::Fp16System; +use zk_pow::circuit::fp16::verifier_cache::Fp16VerifierCache; +use zk_pow::circuit::fp16::wrapper::{verify_wrapped_proof_with_headers, D, F}; + +const EASY: u32 = 0x207f_ffff; + +#[test] +#[ignore = "GPU-sourced recursive FP16 wrap (~12-15 min); run explicitly with GPU_FP16_BUNDLE set"] +fn gpu_tile_proves_and_verifies_through_cache() { + // 1. Load the GPU-produced bundle: header(76) | u32le len | plain-proof bytes. + let path = std::env::var("GPU_FP16_BUNDLE") + .expect("set GPU_FP16_BUNDLE to the GPU plain-proof bundle path"); + let raw = std::fs::read(&path).expect("read GPU plain-proof bundle"); + assert!(raw.len() > 80, "bundle too short"); + let header = IncompleteBlockHeader::from_bytes(&raw[..76]).expect("parse header"); + let plen = u32::from_le_bytes(raw[76..80].try_into().unwrap()) as usize; + assert_eq!(80 + plen, raw.len(), "bundle length mismatch"); + let plain = Fp16PlainProof::from_bytes(&raw[80..80 + plen]).expect("parse Fp16PlainProof"); + println!( + "GPU bundle: header nbits={:#010x}, plain-proof {} bytes, geometry h={} w={} k={}", + header.nbits, + plen, + plain.job.operands.a.pattern.tile_size(), + plain.job.operands.b.pattern.tile_size(), + plain.job.k, + ); + + // 2. PROVE the GPU-found tile into the header-bound ZK certificate. + let mut prover = Fp16Prover::new(); + let cert = prover + .prove_from_plain_proof(&header, &plain) + .expect("prove the GPU-found winning tile"); + println!("proved: Fp16ZkCertificate carries {} proof bytes", cert.proof_bytes.len()); + + // 3. VERIFY through the PRODUCTION cache, exactly as the node FFI does. + let (h, w, k) = cert.tile_geometry(); + let (a_hash, b_hash) = (cert.job.operands.a.hash_id, cert.job.operands.b.hash_id); + let cache_path = + std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/api/fp16/fp16_cache.bin"); + let cache = Fp16VerifierCache::from_bytes(&std::fs::read(&cache_path).expect("read fp16_cache.bin")) + .expect("parse production cache"); + let mut system = Fp16System::::new(h, w, k, a_hash, b_hash); + let verifier = cache + .get(system.degree_bits()) + .expect("production cache covers the fixture profile"); + let vd = verifier.circuit(); + let proof = ProofWithPublicInputs::from_bytes(cert.proof_bytes.clone(), &vd.common) + .expect("deserialize wrapped proof"); + verify_wrapped_proof_with_headers(&mut system, vd, &proof, &header, &cert.job, EASY) + .expect("GPU tile -> ZK prove -> verify-through-production-cache must ACCEPT"); + println!("ACCEPT: GPU-found tile verified through the production verifier cache (consensus path)."); + + // 4. TAMPER: a flipped proof byte must be rejected. + let mut bad = cert.proof_bytes.clone(); + *bad.last_mut().unwrap() ^= 1; + let rejected = ProofWithPublicInputs::from_bytes(bad, &vd.common) + .map_err(|e| e.to_string()) + .and_then(|p| { + verify_wrapped_proof_with_headers(&mut system, vd, &p, &header, &cert.job, EASY) + .map_err(|e| e.to_string()) + }) + .is_err(); + assert!(rejected, "a tampered wrapped proof must be rejected"); + println!("REJECT: tampered proof correctly rejected. End-to-end GPU->ZK->consensus verify PASSED."); +}