Status: design document. The core — a byte-exact, all-integer fixed-point inference engine for 1-bit (Q1_0) weights — is already built and measured in the
integer_inference_engine/bonsaiengine (bonsai/src/trinote/infer_int/reference_bonsai.py,bonsai/src/trinote/determinism/fixedpoint.py, the CPU/CUDA kernels, receipts, GGUF import). This document describes generalizing that core into a standalone engine, generalizing the weight codec to BitNet-style ternary models, and wiring it to Ollama for model distribution and a drop-in API. Sections are marked [proven] (exists today) or [proposed] (design).
Local LLM inference today (Ollama / llama.cpp) is fast and convenient but not reproducible: it runs in
floating point, and float arithmetic is non-associative, batch-variant, atomic-order-dependent, and varies by
BLAS/driver/CPU — so even greedy T=0 decoding drifts across machines, GPUs, and even batch sizes. You cannot
get the same bytes twice across hardware, so you cannot prove what a model produced.
A deterministic integer inference engine fixes this at the root: do all model arithmetic in
integer fixed-point. Integer addition is exactly associative ((a+b)+c == a+(b+c) with a defined mod-2⁶⁴
wrap), so the result is byte-identical regardless of thread count, SIMD width, GPU, or batch size — provided
no integer overflow (which a fail-loud bound guarantees). That single property unlocks verifiable inference:
a third party can re-execute the run on a reference CPU and get the same bytes, so a generation can carry a
cryptographic receipt.
BitNet-style LLMs are the natural fit. Their weights are already 1-bit ({−1,+1}, Q1_0) or 1.58-bit ternary
({−1,0,+1}, BitNet b1.58) — there is no float weight to quantize away, and the "matmul" is a signed integer
sum, not a floating-point dot product. Integer inference is not a compromise for these models; it is the
honest implementation.
Ollama is the distribution and UX layer. It already manages GGUF models (pull, run, an HTTP API) and is
where users get models. The standalone engine reuses Ollama's model store and exposes an Ollama-compatible
API, swapping only the compute backend — from llama.cpp's float kernels to the deterministic integer engine.
Net:
ollama pulla tiny BitNet model → run it through a deterministic integer engine → get byte-exact, reproducible, optionally receipted output, on CPU (or a GPU as a verified producer). Edge, audit, compliance, agent-notarization, and "prove what the model said" use cases that float engines structurally cannot serve.
| Piece | What it gives | What it lacks alone |
|---|---|---|
| Integer engine | byte-exact reproducibility → verifiable/receiptable inference | a model format + distribution + UX |
| BitNet-style models | weights already integer (1-bit / ternary); tiny; CPU-friendly | a deterministic, verifiable runtime |
| Ollama | model distribution (pull), storage, a familiar API + clients |
reproducibility (it is float / llama.cpp) |
The intersection is the product: verifiable local inference of tiny integer models with a familiar UX.
This is the load-bearing engineering, already implemented and byte-exact in the reference project.
Activations live as int64 fixed-point with frac fractional bits (e.g. frac=16). The only floats permitted
are scalar constants computed host-side once, correctly rounded, and committed as integers (e.g.
inv_sqrt_fp = round((1/√head_dim)·2^frac)). There is no float in the compute path and no float
reduction — that is the actual guarantee.
Every reduction in a transformer — the weight apply, the attention scores, the softmax denominator, the @V
accumulation, the vocab argmax — is an integer sum. Integer + is associative and commutative in ℤ/2⁶⁴ℤ, so
any order (thread, warp, SIMD lane, atomic, tiling, batch) yields the identical sum. The classic sources of
GPU/threaded non-determinism therefore do not apply:
- float non-associativity → N/A (integer).
- batch-invariance failure (result depends on batch size/tiling) → N/A (integer sums are tiling-independent).
- atomic-order races → harmless for integer sums; only
argmaxneeds a fixed lowest-index tie-break. - transcendental/library variance (
expf, cuBLAS) → avoided: softmax/SiLU use integer polynomials, notexpf; no BLAS.
- Weight apply (the "matmul"): a masked integer signed-sum (see §4).
- RMSNorm: 128-bit sum-of-squares (the residual stream is unbounded across layers, so it exceeds int64),
a bit-exact integer
isqrt, and floor-division (toward −∞, not truncation). Fails loud if even 128 bits is insufficient (→ a big-int reference path). - Softmax: integer max-shift, a cubic
2^-fpolynomial, integer normalize (floor-div). Noexp. - SiLU: the same integer
2^-fpolynomial sigmoid. - RoPE: integer multiply-add + arithmetic floor-shift; host-computed
cos/sintables in fixed-point. - Argmax / sampling: lowest-index tie-break; samplers (greedy/temp/top-k/top-p/min-p) are integer and
reproducible via a counter-based (SHA-256 + Lemire) draw keyed by
(seed, position).
Integer associativity holds only if no value silently wraps unexpectedly. The engine carries a per-tensor
bound (max|a|·max|b|·K ≤ 2⁶³−1) checked before each multiply; a breach raises rather than wrapping
(a silent wrap would be "wrong-but-still-deterministic" — both producer and verifier would agree on garbage).
There are two deliberate wrap-by-construction exceptions, both byte-identical across the NumPy oracle and the
C/CUDA producers (so producer and verifier wrap the same way, and determinism is preserved by consistent wrap
rather than by raising):
- The Q1 weight apply — wraps mod-2⁶⁴ by construction (the packed masked-sum matches the NumPy reference bit for bit).
- The SiLU / sigmoid activation path (
fixed_point_sigmoid/fixed_point_siluand the FFNgate*up) — the distancem − xand thex·sigmoid(x)product are not fail-loud-bounded; for an out-of-envelope input (e.g. an int64-min-scale mask sentinel) they wrap, but wrap identically in the oracle and the native/GPU kernels (pinned at the int64 extremes bytest_bonsai_native_silu_matches_oracle_if_present). Real activations are RMSNorm-bounded and never reach the wrap; callers must use a bounded causal-mask sentinel (~−2^(frac+30)), which the engine always does. Every other multiply (attention Q·Kᵀ / probs·V, RMSNorm gain, RoPE, sampler temperature) keeps the fail-loud bound.
The pure-integer reference (NumPy/Python) is the canonical verifier; accelerated kernels (CPU C/OpenMP,
optional CUDA) are byte-identical producers. A receipt produced on a GPU re-executes bit-for-bit on a
CPU-only verifier — so a third party never needs the producer's hardware. The parity gate
(np.array_equal(kernel_out, oracle_out)) is what makes aggressive kernel work safe.
The "matmul" Y = X · Wᵀ for low-bit signed weights is a masked integer sum, not a float dot product. This
is where the engine and BitNet meet.
Per output o, per 128-weight group b, with signᵢ ∈ {−1,+1} and int activations xᵢ:
signed_sum_b = Σ_i signᵢ·xᵢ = 2·(Σ_{bit=1} xᵢ) − (Σ_i xᵢ) = 2·pos_sum_b − block_total_b
out_o = Σ_b arshift( signed_sum_b · scale[o,b], frac ) # per-group scale, per-group floor, then sum
block_total_b is independent of o (compute once per token-group, reuse across all outputs); only pos_sum_b
depends on the weight bits — a masked sum of x, no multiply by ±1 and no branch.
Ternary is the same shape with a zero state that simply drops out of the sum:
signed_sum_b = Σ_i wᵢ·xᵢ = (Σ_{wᵢ=+1} xᵢ) − (Σ_{wᵢ=−1} xᵢ) # zeros contribute nothing
out_o = Σ_b arshift( signed_sum_b · scale[o,b], frac )
Two sign bits per weight (or a packed 5-trits-per-byte / i2 layout) select +x, −x, or skip. The engine's
existing masked-sum machinery covers it directly; the only new code is the ternary unpack in the weight
codec. BitNet b1.58 also publishes a per-tensor (or per-row) scale that maps onto the per-group scale[o,b].
Define a small interface so the engine is weight-format-agnostic:
class QuantCodec:
group_size: int
def unpack_signs(bits) -> int8[...] # {−1,0,+1}
def scale(o, b) -> int64 # per-group integer scale (fixed-point)
def apply(x_fp, weight, frac) -> int64 # masked integer signed-sum -> out (byte-exact)
Implementations: Q1_0Codec [proven], BitNet158Codec (ternary) [proposed], and any future
per-group-scaled low-bit signed scheme. The pure-integer apply is the oracle; CPU/CUDA kernels are
byte-identical fast paths registered against the same parity gate.
Two consistent choices, both fully integer/deterministic:
- Fixed-point int64 activations (the engine's current model).
xcarriesfracbits; the apply isint64; RMSNorm uses int128. Maximally faithful (no activation quantization), at int64 cost. - BitNet-native int8 activations + int32 accumulation. BitNet quantizes activations per-token (absmax →
int8) and accumulates ternary·int8 in int32. This is still deterministic (integer accumulation,
associative) and maps to
__dp4a/int8-IMMA tensor cores. The engine can support a per-tensor activation scale path so it matches a BitNet reference bit-for-bit, provided the reference's quant+accumulate is specified exactly (absmax rounding, int32 accumulate, requant) and reproduced.
Determinism does not require int64 — it requires integer accumulation with a defined no-overflow/wrap contract. int8×ternary→int32 is byte-exact iff the int32 accumulator never overflows (a static per-tensor bound, like §3.4). The fixed-point-int64 path is the conservative default; the int8 path is the performance/compat path for BitNet.
The masked signed-sum maps to hardware integer MAC units (__dp4a, int8 IMMA tensor cores) while staying
byte-exact, via a base-256 limb decomposition of the (multi-bit) activations — int8 weight (±1/ternary) ×
int8 activation-limb → int32, recombined in int64 (exact mod-2⁶⁴). Full derivation + overflow proof:
bonsai-notary/Q1-BITMATMUL-REFORMULATION.md.
Honest measured caveat [proven]: for the Q1_0 case on a consumer GPU, the masked sum is add-bound, not multiply-bound (the ±1 weight is a sign flip, not a real multiply), so DP4A gave only ~1.15× kernel-only and did not win end-to-end — the win came from weight residency + large-M prefill, not from tensor cores. BitNet ternary with int8 activations is more multiply-like and is exactly the regime tensor cores are built for, so the tensor-core path is more promising there — but it must be measured, not assumed (this project's recurring lesson: three plausible GPU optimizations measured as regressions and were gated off).
┌─────────────────────────────────────────────────────────────┐
GGUF model ───▶│ Importer: GGUF → integer artifact │
(Ollama blob / │ • dequant-to-integer weights (packed signs + per-group int │
HF download) │ scales), fixed-point RoPE tables, integer norm gains │
└─────────────────────────────────────────────────────────────┘
│ integer artifact (safetensors / mmap)
▼
┌──────────────────────────────────────────────────────────────────────────────┐
│ CORE ENGINE (all integer) │
│ pure-integer reference ── canonical VERIFIER (the oracle) │
│ CPU native (C/OpenMP) ┐ │
│ CUDA (per-host opt-in) ┘ byte-identical PRODUCERS (parity-gated) │
│ QuantCodec: Q1_0 | BitNet-ternary | … │
│ integer ops: apply · RMSNorm · softmax · SiLU · RoPE · argmax · samplers │
└──────────────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────┼───────────────────────────┐
▼ ▼ ▼
CLI (run / serve) Ollama-compatible HTTP Library API (embed)
/api/generate /api/chat + optional RECEIPTS
+ OpenAI /v1/chat/completions (commit + re-exec + sign)
Layers:
- Importer — read GGUF (incl. Ollama's blob store, §7), dequantize to the integer artifact: packed weight signs, per-group integer scales, fixed-point RoPE tables, integer RMSNorm gains, committed sampler/config.
- Core — the pure-integer oracle + byte-identical CPU/CUDA kernels + the
QuantCodec. (Extracted fromreference_bonsai.py/fixedpoint.py/q1_native.py/gpu_native.py/bonsai_q1_kernel.c/bonsai_q1_gpu.cu.) - Interfaces — CLI, an Ollama/OpenAI-compatible server, and a library API.
- Receipts (optional) — commitments + bit-exact re-execution + signatures (extracted from
receipts/).
Ollama's backend is llama.cpp (float) — this engine does not plug into Ollama's runner. Instead it reuses the two parts of Ollama that matter: its model store and its API surface. GGUF is the bridge.
Ollama stores pulled models under ~/.ollama/models/ as OCI-style content-addressed blobs plus JSON manifests
(manifests/<registry>/<namespace>/<model>/<tag>). A manifest lists layers by sha256: digest; one layer
(media type for the model GGUF) is the weights blob. The importer:
- resolves a model name+tag → manifest → the GGUF blob digest →
blobs/sha256-<digest>; - reads that GGUF directly (no copy) and imports it to the integer artifact (cached, content-addressed by the blob digest so re-import is skipped).
So the user does ollama pull <bitnet-model> and points the engine at the model name — it finds the blob.
(Exact manifest media-types/paths should be pinned against the installed Ollama version at implementation
time; treat the above as the shape, not a frozen spec.)
Expose an HTTP server matching the endpoints existing Ollama clients use:
POST /api/generate(prompt → completion, streaming NDJSON)POST /api/chat(messages → chat, streaming)GET /api/tags(list available integer models)- plus an OpenAI-compatible
POST /v1/chat/completionsfor the broad tool ecosystem.
Requests run on the deterministic integer engine. Two value-adds over stock Ollama: responses are
byte-reproducible at a fixed seed, and an optional receipt: true request field returns (or logs) a
verifiable receipt alongside the output.
Ship integer artifacts as GGUF (or a sidecar) with a Modelfile so ollama create registers them. The engine
advertises which GGUF quant types it can run deterministically (Q1_0 and BitNet ternary types) and refuses
others loudly rather than silently falling back to float.
This is interop, not a fork of Ollama: reuse its distribution + API, replace the compute with the integer engine. Float GGUF models (the majority) are out of scope — the engine runs 1-bit / ternary models, where integer is exact and the determinism story is real.
Because the engine is byte-exact, each generation can emit a receipt: commitments over (model hash, input,
output, integer execution trace), a hash-linked ledger entry, and third-party-verifiable signatures
(secp256k1; the receipt carries only the public key). A verifier re-executes the receipt on the CPU integer
oracle and confirms the bytes — no shared secret, no GPU, no trust in the producer. This is the capability a
float engine structurally cannot offer (it can't reproduce its own bytes), and it is fully built in the
reference project (receipts/, bonsai_runtime.emit_and_verify_*). For a standalone engine it is an opt-in
feature, off by default for plain "fast local inference," on for audit/agent/compliance use.
Scope: re-execute the COMMITTED artifact, not re-import the GGUF. Verification binds the committed
artifactDigestto the receipt'smodelHashand re-runs the committed integer artifact — that is byte-stable everywhere. It does NOT claim that re-importing the same GGUF reproduces the same artifact: the RoPE/YaRN tables are built with libmcos/sin+ floatpowthen rounded and committed+hashed, so import on different hardware can yield a differentartifactDigest/modelHash. "Verifiable" = re-execute the exact committed bytes, not re-derive them from source.
Honest, measured on an 8-core CPU + RTX 3070 (so directional for the standalone engine, exact for Q1_0-8B):
- CPU decode: the 1-bit weight gather is L3-latency-bound at the portable build floor; concurrency (threads / process-sharding) is the lever, not single-stream kernel tuning.
- GPU (byte-exact producer): weight residency + large-M prefill are the wins — single-query decode 2.14×, prefill 17.6× (T=256), end-to-end generation 12.7–15.8×, batch decode 1.85×, all byte-identical to the CPU oracle. Consumer-GPU int64 is emulated (the headwind); DP4A/IMMA helped Q1_0 only marginally (add-bound) — expect a better tensor-core story for BitNet int8×ternary.
- Determinism cost: int128 RMSNorm + integer softmax polynomials are more work than float equivalents, but this is what buys reproducibility; for tiny BitNet models the absolute cost is small and CPU-friendly, which is the sweet spot.
Takeaway: the engine is competitive and reproducible; it trades a constant factor of arithmetic for a property (byte-exactness) no float engine has. BitNet's small size makes that trade cheap.
"CI-gated" below means the byte-exact CPU-oracle ⇄ CPU-native parity (incl. the int64 overflow boundary) runs
on every push/PR via .github/workflows/ci.yml, which builds the native kernel and
sets TRINOTE_REQUIRE_NATIVE=1 so a missing kernel fails the suite rather than silently passing on the oracle
alone. GPU parity is not in CI (no GPU runner).
| Capability | Status |
|---|---|
| All-integer fixed-point transformer, byte-exact CPU-oracle ⇄ CPU-native (incl. int64 overflow boundary) | proven, CI-gated (Q1_0 8B) |
| Pure-integer oracle + byte-identical CPU C kernel | proven, CI-gated |
CUDA kernel int64-faithful (no float atomics/expf/fast-math), byte-checked vs CPU oracle on GPU hardware or BONSAI_VERIFY_GPU=1 |
proven on hardware; NOT in default CI (no GPU in CI) |
| Q1_0 masked-sum apply, integer RMSNorm/softmax/SiLU/RoPE, integer samplers | proven |
| Cryptographic receipts (commit + re-exec + secp256k1 signatures) | proven |
| GGUF import → integer artifact (re-execute the committed artifact; re-import is not byte-stable — RoPE/YaRN libm tables) | proven (one model family) |
| GPU residency / prefill / batch wins, byte-checked vs CPU oracle when GPU present | proven (measured on one GPU) |
| Extract the core into a standalone, format-agnostic engine | proposed |
BitNet158Codec (ternary) + a generic QuantCodec interface |
proposed |
| int8-activation BitNet path (DP4A/IMMA) with a matching parity gate | proposed |
Read Ollama's blob store; serve /api/generate /api/chat /v1 |
proposed |
Package integer artifacts as Ollama models (Modelfile) |
proposed |
- BitNet GGUF formats. The exact GGUF quant types / packing for BitNet b1.58 (and bitnet.cpp's
layouts) must be read and pinned; the ternary unpack + per-tensor activation quant must be reproduced
bit-for-bit to claim byte-exactness against a BitNet reference. Until verified against a real model, the
BitNet158Codecis a design, not a guarantee. - Activation-quant determinism. If matching a published BitNet reference, every rounding step (absmax, int8 cast, int32 accumulate, requant) must be specified and reproduced; otherwise the engine defines its own (still-deterministic) numerics and is self-consistent but not bit-equal to that reference.
- Ollama API/version drift. Manifest media-types and API fields evolve; pin against the installed version and test, rather than hard-coding.
- Cross-hardware verification is argued, not exhaustively measured. Integer associativity gives byte-exactness by construction, but it should be validated on ≥2 CPU arches and ≥2 GPU arches before the "verify anywhere" claim is load-bearing (the reference project verified launch-geometry invariance on one GPU only).
- Scope discipline. This is for 1-bit / ternary models. Don't promise float-GGUF parity; refuse unsupported quant types loudly. The value is verifiable integer inference of integer models, not a general llama.cpp replacement.
- Extract the integer core (oracle + CPU kernel +
QuantCodec) into a standalone package; re-run the Q1_0 parity gate to prove the extraction is byte-identical. - Add
BitNet158Codec; import one real BitNet b1.58 GGUF; prove the integer oracle runs it and is self-reproducible (same bytes across thread counts). - Add the Ollama blob-store reader (
ollama pull→ engine runs the blob) and a minimal/api/generate. - Turn on optional receipts; demonstrate produce-on-GPU / verify-on-CPU byte-exact.
Each step is gated by np.array_equal(producer, oracle) — correctness first, speed second, exactly as the
reference engine was built.
Reference implementation (the proven core this generalizes): integer_inference_engine/bonsai —
bonsai/src/trinote/infer_int/ (engine, kernels, import, samplers, receipts glue),
bonsai/src/trinote/determinism/fixedpoint.py (integer primitives), bonsai/tools/bonsai_q1_kernel.c +
bonsai/tools/bonsai_q1_gpu.cu (byte-identical CPU/CUDA producers), plus the external
Q1-BITMATMUL-REFORMULATION, GPU-FEASIBILITY, IMPLEMENT-GPU-MODE, DETERMINISM, and SAMPLER design notes.