<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://bayrak.dev/</id>
    <title>Baris Bayrak Blog</title>
    <updated>2026-06-30T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://bayrak.dev/"/>
    <subtitle>Baris Bayrak Blog</subtitle>
    <icon>https://bayrak.dev/img/baris-scan-192x192.png</icon>
    <entry>
        <title type="html"><![CDATA[Carnot — Compression, GPUs, and Cryptographic Accumulators]]></title>
        <id>https://bayrak.dev/2026/06/30/carnot-compression-research</id>
        <link href="https://bayrak.dev/2026/06/30/carnot-compression-research"/>
        <updated>2026-06-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A deep dive into Carnot: pattern-scale decomposition that beats zstd by 9×, a BWT pipeline that outruns lzma on enwik8, GPU-accelerated transforms, and a bilinear accumulator on BLS12-381.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://en.wikipedia.org/wiki/A_Mathematical_Theory_of_Communication" target="_blank" rel="noopener noreferrer" class="">Claude Shannon</a> proved in 1948 that every data source has a theoretical minimum — you can't compress below Shannon entropy. But that limit applies to the <em>true</em> data source, not your file. Real-world data is far more structured than byte frequencies suggest, and standard compressors leave a lot on the table.</p>
<!-- -->
<p><strong>Carnot</strong> is an open research project named after <a href="https://en.wikipedia.org/wiki/Nicolas_L%C3%A9onard_Sadi_Carnot" target="_blank" rel="noopener noreferrer" class="">Sadi Carnot</a> — who defined the theoretical maximum efficiency of heat engines. The project asks the same question in a different domain: <em>how close can we get to the true compression limit if we stop caring about throughput?</em></p>
<p>It has grown into three tracks across a Rust workspace: pattern-scale decomposition compression, GPU-accelerated transforms, and a cryptographic accumulator on BLS12-381. It's a lab notebook, not a product — 21 experiments so far, with failures documented as carefully as successes.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="pattern-scale-decomposition">Pattern-Scale Decomposition<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#pattern-scale-decomposition" class="hash-link" aria-label="Direct link to Pattern-Scale Decomposition" title="Direct link to Pattern-Scale Decomposition" translate="no">​</a></h2>
<p>The key insight, formalized in <a href="https://github.com/brsbyrk/carnot/blob/main/docs/cf-unification.md" target="_blank" rel="noopener noreferrer" class=""><code>docs/cf-unification.md</code></a>: every structured byte sequence decomposes into two orthogonal components — the <em>pattern</em> (generating rule: constant, alternating, counting, repeating) and the <em>scale</em> (length, repeats, frequency). Standard compressors conflate both channels; Carnot separates them.</p>
<p>The math uses continued fraction rational approximations of byte sequences. CF convergents find the infinite-limit structure in small terms, but encode length implicitly through a huge final term costing O(n). The bytecode VM is the practical fix — same pattern detection, but with an explicit O(log n) scale channel.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-bytecode-vm">The Bytecode VM<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#the-bytecode-vm" class="hash-link" aria-label="Direct link to The Bytecode VM" title="Direct link to The Bytecode VM" translate="no">​</a></h2>
<p>A 17-opcode stack VM with loop stack encodes structural patterns as tiny programs approaching the Kolmogorov complexity floor — the shortest possible description of the data:</p>
<table><thead><tr><th>Op</th><th>Pattern</th><th>Program size</th><th>100KB compressed</th><th>vs zstd</th></tr></thead><tbody><tr><td>LOOP/OUTPUT</td><td>Constant byte</td><td>7 B</td><td>~17 B</td><td><strong>~6×</strong></td></tr><tr><td>LOOP/PUSH/OUTPUT</td><td>Alternating AB</td><td>10 B</td><td>~30 B</td><td><strong>~9×</strong></td></tr><tr><td>Nested loop + math</td><td>Counting 0..255</td><td>15 B</td><td><strong>74 B</strong></td><td><strong>3.8×</strong></td></tr><tr><td>REPEAT_BLOCK</td><td>Repeating block</td><td>5+len</td><td>445 B</td><td>—</td></tr></tbody></table>
<p>Programs are discovered via beam search (width 50, sampling 4KB windows) rather than exhaustive enumeration. The adaptive pipeline selector auto-routes between 7 strategies: random pass-through, delta encoding for sorted integers, BWT+MTF+RLE for text, sparse encoding for low-entropy data, dedup for repeated blocks, RePair grammar compression, and the VM bytecode path for periodic/structured input. Candidate pruning gives a 1070× speedup on uniform data.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-bwt-pipeline">The BWT Pipeline<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#the-bwt-pipeline" class="hash-link" aria-label="Direct link to The BWT Pipeline" title="Direct link to The BWT Pipeline" translate="no">​</a></h2>
<p>The best general-purpose result comes from a <strong>five-stage Burrows-Wheeler pipeline</strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Raw data → BWT (SA-IS) → Move-to-Front → Zero-run → RePair → Order-1 Arithmetic Coding</span><br></div></code></pre></div></div>
<p>Each stage targets a different redundancy type:</p>
<table><thead><tr><th>Stage</th><th>What it exploits</th><th style="text-align:center">Gain</th></tr></thead><tbody><tr><td>BWT (sentinel SA-IS)</td><td>Long-range character grouping</td><td style="text-align:center">~25%</td></tr><tr><td>MTF</td><td>Local frequency skew after BWT</td><td style="text-align:center">~10%</td></tr><tr><td>Zero-run</td><td>Long runs of MTF-0 values</td><td style="text-align:center">~5%</td></tr><tr><td>RePair (incremental)</td><td>Repeated digrams</td><td style="text-align:center">~15%</td></tr><tr><td>Order-1 AC</td><td>Byte-level conditional probability</td><td style="text-align:center">~6.5%</td></tr></tbody></table>
<p>The evolution is visible in the experiment log — five attempts to get from a Python prototype at 0.2971 ratio to the Rust champion. The breakthrough was sentinel-based SA-IS BWT + incremental RePair, refined from 0.2512 ratio and 29 minutes down to 0.2352 at 2 minutes via flat-array order-1 modeling.</p>
<p>On <a href="https://mattmahoney.net/dc/textdata.html" target="_blank" rel="noopener noreferrer" class="">enwik8</a> 100MB:</p>
<table><thead><tr><th>Compressor</th><th style="text-align:center">Ratio</th><th>Time</th></tr></thead><tbody><tr><td><strong>Carnot BWT</strong></td><td style="text-align:center"><strong>0.2352</strong></td><td>2m 07s</td></tr><tr><td>PPMd</td><td style="text-align:center">0.225</td><td>—</td></tr><tr><td>xz -9e</td><td style="text-align:center">0.2483</td><td>82s</td></tr><tr><td>zstd -22</td><td style="text-align:center">0.2795</td><td>65s</td></tr><tr><td>bzip2 -9</td><td style="text-align:center">0.2901</td><td>~1s</td></tr><tr><td>gzip -9</td><td style="text-align:center">0.3648</td><td>~1s</td></tr></tbody></table>
<p>At 1GB (10× concatenated enwik8), xz pulls ahead — 0.1737 vs Carnot's 0.2403 — because LZMA2's 64MB sliding window exploits cross-copy repetition that BWT, confined to each 64MB block, misses. Carnot wins on single files by 5.3%; xz wins on concatenated copies. Both approaches have their regime.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="multi-threading-and-speed-improvements">Multi-threading and Speed Improvements<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#multi-threading-and-speed-improvements" class="hash-link" aria-label="Direct link to Multi-threading and Speed Improvements" title="Direct link to Multi-threading and Speed Improvements" translate="no">​</a></h2>
<p>Multi-threaded BWT gives 2.6× speedup at a 3.8% ratio cost on 100MB enwik8. Multi-block parallel compression scales near-linearly at 4×. The whole pipeline processes 64MB blocks sequentially to stay within RAM limits — SA-IS suffix array on 1GB needs ~5GB for the SA alone. A production run would need either 32GB+ RAM, out-of-core BWT, or pre-deduplication.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="gpu-bwt-acceleration">GPU BWT Acceleration<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#gpu-bwt-acceleration" class="hash-link" aria-label="Direct link to GPU BWT Acceleration" title="Direct link to GPU BWT Acceleration" translate="no">​</a></h2>
<p>BWT suffix array construction is the pipeline's bottleneck. <code>carnot-gpu-core</code> offloads it to the GPU via <a href="https://github.com/IlyaGrebnov/libcubwt" target="_blank" rel="noopener noreferrer" class="">libcubwt</a>, targeting a GTX 1060 6GB (Pascal, CC 6.1, CUDA 12.2). The FFI is scaffolded with <code>cudarc</code> device management and VRAM budgeting — libcubwt needs 20.5n bytes for n-byte input, capping at ~300MB on the 6GB card. A CPU fallback runs suffix sorting directly for testing. The <code>carnot-gpu-cli</code> provides <code>info</code> and <code>bench-bwt</code> subcommands.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="bilinear-accumulator-on-bls12-381">Bilinear Accumulator on BLS12-381<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#bilinear-accumulator-on-bls12-381" class="hash-link" aria-label="Direct link to Bilinear Accumulator on BLS12-381" title="Direct link to Bilinear Accumulator on BLS12-381" translate="no">​</a></h2>
<p>The <code>carnot-accumulator</code> crate implements a bilinear accumulator for constant-size set membership proofs — 48 bytes for the accumulator and each witness, regardless of how many elements are in the set:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Setup:  s = random secret</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        pk = g₂^s</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Accumulate:  acc = g₁^{∏(s + hash(x_i))}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Witness:     w   = g₁^{∏_{i≠j}(s + hash(x_j))}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Verify:      e(w, g₂^{hash(x_j)} · pk) == e(acc, g₂)</span><br></div></code></pre></div></div>
<p>Key implementation details:</p>
<ul>
<li class="">Pairings via <code>blst</code> on the BLS12-381 curve</li>
<li class=""><strong>NTT-based polynomial multiplication</strong> — tree-based product expansion in O(n log n) over a field with 2^32 roots of unity</li>
<li class=""><strong>Batch witness generation</strong> via prefix-suffix products in O(N)</li>
<li class=""><strong>Merkle tree</strong> integration for byte-level membership — each leaf is SHA-256(index || byte), so a verifier can brute-force all 256 byte values against a single Merkle proof</li>
<li class="">Powers-of-tau trusted setup with chunked verification and parallel brute-force checking</li>
</ul>
<p>This isn't directly about compression — it's infrastructure for verifiable computation. The polynomial math (NTT, pairings, finite fields) connects both domains.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-didnt-work">What Didn't Work<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#what-didnt-work" class="hash-link" aria-label="Direct link to What Didn't Work" title="Direct link to What Didn't Work" translate="no">​</a></h2>
<p>Failures are preserved as terrain maps for future explorers:</p>
<table><thead><tr><th>Experiment</th><th>Why it failed</th></tr></thead><tbody><tr><td>Renormalization group compression</td><td>Data Processing Inequality: provably bounded by H₁</td></tr><tr><td>Byte embeddings (bilinear)</td><td>Factorization loses specific transitions; simple counters win</td></tr><tr><td>Grammar induction (Sequitur)</td><td>Rule explosion on real data</td></tr><tr><td>Mixture of Experts</td><td>Gradient bug; hard assignment fragments data</td></tr><tr><td>Chain transform (Follow)</td><td>99.98% collision rate on text</td></tr><tr><td>CF compression</td><td>Confirmed negative — does not actually compress</td></tr><tr><td>Sorted u32 delta</td><td>Byte-level delta inflates; needs word-level encoding</td></tr></tbody></table>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-structural-gap">The Structural Gap<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#the-structural-gap" class="hash-link" aria-label="Direct link to The Structural Gap" title="Direct link to The Structural Gap" translate="no">​</a></h2>
<p>The project's central metric:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">H₀ - compression_ceiling = structural_gap</span><br></div></code></pre></div></div>
<p>H₀ is byte-frequency entropy (Shannon). The compression ceiling is the best ratio standard tools achieve on a given file. The gap measures <strong>latent structure that current compressors miss</strong> — the hunting ground:</p>
<table><thead><tr><th>Data</th><th style="text-align:center">H₀</th><th style="text-align:center">Ceiling</th><th style="text-align:center">Gap</th></tr></thead><tbody><tr><td>Uniform random</td><td style="text-align:center">8.00</td><td style="text-align:center">8.00</td><td style="text-align:center"><strong>0.00</strong> — truly incompressible</td></tr><tr><td>Markov order-3</td><td style="text-align:center">8.00</td><td style="text-align:center">5.72</td><td style="text-align:center"><strong>2.28</strong> — hidden transition structure</td></tr><tr><td>Periodic 256</td><td style="text-align:center">7.82</td><td style="text-align:center">0.66</td><td style="text-align:center"><strong>7.16</strong> — massive latent pattern</td></tr><tr><td>Repeated blocks</td><td style="text-align:center">8.00</td><td style="text-align:center">1.01</td><td style="text-align:center"><strong>6.98</strong> — dictionary obvious but H₀ blind</td></tr></tbody></table>
<p>Periodic signals and repeated blocks have H₀ ≈ 8.0 — byte-frequency counters see noise. But standard compressors exploit their structure easily. The gap quantifies what's left on the table.</p>
<p>The bit-plane experiment reached 99.7% of its theoretical bound, confirming intra-byte structure is well-understood. The remaining ~38% gap to PAQ/CMIX on enwik8 requires inter-byte context — longer-range models, match models, word-level prediction. Not one missing trick, but an architecture difference.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="philosophy">Philosophy<a href="https://bayrak.dev/2026/06/30/carnot-compression-research#philosophy" class="hash-link" aria-label="Direct link to Philosophy" title="Direct link to Philosophy" translate="no">​</a></h2>
<p>Three principles drive the project:</p>
<ol>
<li class=""><strong>Measure first.</strong> Every claim backed by the standard test corpus (10 synthetic types × 4 sizes).</li>
<li class=""><strong>Preserve the journey.</strong> Failed approaches stay in the repo — they're the map of what's been tried.</li>
<li class=""><strong>Trade time for compression.</strong> CPU-hours are abundant; novel algorithms aren't.</li>
</ol>
<p>The project achieved its goal: designing and benchmarking a novel compression pipeline that beats standard tools on structured data. The GPU and accumulator work extend the same mathematical foundation into new domains. Carnot remains open for exploration — the remaining gaps are documented, the architecture is modular, and the dead ends are mapped.</p>
<hr>
<p>Carnot is open-source under MIT. <a href="https://github.com/brsbyrk/carnot" target="_blank" rel="noopener noreferrer" class="">github.com/brsbyrk/carnot</a></p>]]></content>
        <author>
            <name>Baris Bayrak</name>
            <uri>https://github.com/brsbyrk</uri>
        </author>
        <category label="rust" term="rust"/>
        <category label="compression" term="compression"/>
        <category label="gpu" term="gpu"/>
        <category label="cryptography" term="cryptography"/>
        <category label="research" term="research"/>
    </entry>
</feed>