Blog

  • Friday Archaeology: A Quarter-Century-Old Crypto Library, the Cult of the Dead Cow, and a Rijndael Buffer Overwrite

    It is Friday. El Reg informs us that 45 percent of AI-generated code now ships with security flaws, that vibe-coded apps are leaking student data to unauthenticated attackers, and that rogue AI agents have learned to escalate privileges and exfiltrate secrets without being asked. In this climate of automated incompetence, I thought it might be instructive to look at some code written by a human, with a book, in 1999. Today we are going down memory lane — this code has never once hallucinated a dependency.

    The Dig

    Because everything I do is technical, even nostalgia comes with a tarball. I unearthed this:

    https://gitlab.llama.gs/attic/scl

    SCL — the Small Crypto Library — and its companion SSSL, the Small Secure Socket Library. Approximately 20,000 lines of C++ implementing, from scratch: a bignum library, RSA, DSA, ElGamal, Rabin-Williams, Blum-Goldwasser, Diffie-Hellman, MQV, all five AES candidates (Rijndael was selected in October 2000, so I was ahead of the news cycle), seven hash functions, seven block cipher modes, DER encoding, a secure socket layer with protocol negotiation, and the beginnings of a TLS 1.0 implementation. Written between 1999 and 2001. I was 22.

    Now, it is received wisdom that when programmers look at their old code, they recoil in horror, as one might upon discovering a photograph of oneself in flared trousers at a school disco. I looked at mine and thought: actually, this is rather good.

    This puts me in mind of Bill Bryson’s observation in Neither Here Nor There about his friend Stephen Katz’s relationship with women. Bryson notes that most men, as they age, gradually lower their standards. Katz, however, had actually raised his — he had started from such a comprehensively low base that the only possible direction was up. My situation is the inverse but structurally identical: the class hierarchy is clean, the block cipher modes compose correctly, the DER encoder works. I looked at 22-year-old me’s code with twenty-five more years of context, and the younger version passed review. Standards were apparently already set.

    The Story

    Some context. In the summer of 1999, I was in Varna, Bulgaria, teaching UNIX courses to save money and waiting for my B.Sc. to finish. I ordered Bruce Schneier’s Applied Cryptography from Amazon. It cost me a significant fraction of a Bulgarian salary. The book arrived. I read it. Then I did what any reasonable person would do: I implemented everything in it.

    The test vectors in the repository? Typed by hand from Schneier’s appendices. Every single DES permutation. Every Blowfish round. The IDEA vectors. The lot. The first three lines of the test vector file read:

    # This is a comment.
    # I like comments very much.
    # The next line is empty.

    That is a 22-year-old testing his flex parser.

    In June 2000, I graduated and made aliyah to Israel, where I joined Zend Technologies in Ramat Gan — the company behind the PHP language engine. The crypto library came with me. The CVS timestamps tell the whole story: initial import Saturday June 9, 2001, a furious week of refactoring the DER encoding layer, and then silence. The last commit is Saturday June 16, 2001. I had renamed AddPrimitive to addValue and Write to toFile halfway through, left half the callers using the old names, commented out a constructor I hadn’t finished implementing, and walked away.

    Why? Because the Israeli army started sending letters. I had already done my time as a conscript in the Bulgarian navy — an experience that cured me permanently of any romantic notions about military service — and I was not about to do it again. I left for the Netherlands in rather a hurry. The crypto library stayed behind, frozen mid-refactor, a monument to the universal truth that API migrations are never completed.

    (In a parallel timeline, I might have stayed. Before Zend, I had applied for a master’s at the Weizmann Institute. The admissions interview was with Adi Shamir — yes, that Shamir, the S in RSA, whose algorithm I had just finished implementing. They asked basic mathematics questions. Nobody told me I should prepare. I didn’t get in. Ended up doing both a master’s and a doctorate at Delft instead, which worked out rather well. Zero regrets, but it remains a good dinner party story.)

    The Hacktivists

    Here is where it gets interesting. Towards the end of my time in Israel, I started receiving emails about SCL. They came from hacked accounts — which should have been the first clue about the correspondents — and referenced mailing lists populated by legitimate security researchers. The group was interested in using SCL+SSSL as the crypto layer for an anti-censorship tool.

    The group was the Cult of the Dead Cow. The tool was Peekabooty.

    For those too young or insufficiently misspent to remember: cDc was the hacking collective founded in a Texas slaughterhouse in 1984, famous for Back Orifice, for coining the term “hacktivism,” and for having a membership roster that included a future U.S. congressional candidate (Beto O’Rourke) and the man who would become DARPA’s Chief Information Officer (Peiter “Mudge” Zatko). Their offshoot Hacktivismo, led by the pseudonymous Oxblood Ruffin, was building tools to punch through national firewalls — specifically China’s.

    Peekabooty was a peer-to-peer anonymity network that routed web requests through encrypted relays using standard SSL, so that censors couldn’t distinguish it from ordinary e-commerce traffic. The design started in July 2000 — the exact month I arrived at Zend. Paul Baranowski and Joey deVilla built it in Toronto, previewed it at DEF CON 9 in the summer of 2001, and it was, in concept, a direct predecessor of Tor.

    They needed a small, BSD-licensed, self-contained C++ crypto library with an SSL socket layer. In 2001, the options were OpenSSL (enormous, GPL-ish, and famously hostile to casual integration) or mine. The emails were real. The interest was genuine.

    And then I left for the Netherlands, the library sat unfinished, and Peekabooty eventually shipped using other crypto. The world got Tor instead. Oxblood Ruffin is now in Berlin. Mudge is running IT at DARPA. Joey deVilla plays accordion at tech conferences in Tampa. Baranowski designs card games in New York. And the library sat in a tarball on a backup drive for twenty-five years.

    The Resurrection

    This week, I made it compile on Slackware 15.0. This involved: modernising the autotools, fixing a DER API that was half-refactored in June 2001, discovering a buffer overwrite in the Rijndael key schedule that had been silently scribbling past the end of an array since 1999, finding the same bug in Blowfish, mass-replacing register keywords that C++17 no longer tolerates, const-correcting approximately four hundred string literals, and explaining to a 26-year-old libtool that SONAME is not optional.

    The Rijndael bug is worth mentioning. AES-256 needs 60 round key words. The key schedule macro generates 8 per iteration. Seven iterations produce 56 — but you need indices 56 through 59, so the seventh iteration is necessary. It also writes indices 60 through 63, which are past the end of the wEncryptionKey[60] array. This has been undefined behaviour since the Clinton administration. It worked because whatever sat after the array in memory didn’t matter. The fix is to make the array 64 elements. The compiler finally noticed in 2026.

    The code is now on GitLab, in the attic where it belongs:

    https://gitlab.llama.gs/attic/scl

    Next Week

    Normal service resumes. There are things to open-source and a rather long arc to lay out properly. The crypto library was the prologue. The interesting parts come next.

  • From DSL to FPGA: Closing the Loop

    This quarter, 4,500 CEOs told PwC their AI investments produced nothing. Separately, someone used AI to rewrite SQLite in Rust — 2,000 times slower. I have a cunning plan: what if we used computers to do actual computing?

    Last week I said I was building a toolchain that goes from formal logic to real hardware. That post was a manifesto. This one is a receipt.

    Seven days later: a full ALU — add, subtract, multiply, divide, integer factorization — running at 100MHz on a $150 Basys3 FPGA. UART command line with tab completion and history. No manual Verilog. No hand-optimized netlists. No venture capital. No pitch deck.

    The arithmetic circuits are generated programmatically in llogic, translated to synthesizable Verilog by llogic2verilog, and deployed on a MicroBlaze soft processor over AXI4-Lite. The entire path from logical specification to working silicon is automated. One person, one week, open source.

    The factor command brute-forces integer factorization by driving the multiplier at clock speed — 100 million candidates per second on a hobby board. Not a simulation. Not a testbench. Electrons moving through gates on a Xilinx Artix-7.

    Nobody wrote this Verilog

    That’s the point. Not the ALU — any undergraduate can write an adder. The point is that no human touched the HDL.

    The circuit specifications live in llogic‘s DSL — a formal representation that spans Boolean formulas, CNF, circuits, and reversible/quantum circuits under one roof. lcfgen generates parameterized circuit families from that representation. llogic2verilog translates them to synthesizable Verilog. Vivado takes it the rest of the way.

    llogic DSL → lcfgenllogic2verilog → Vivado → FPGA

    Every step automated. Every component open source. No license fees, no NDAs, no EDA vendor lock-in.

    What’s next

    If you work on synthesis, hardware, or you’re funding research — the code is open and the board costs $150.

    Next post: cryptographic circuit generators for DES and SHA, synthesized from the DSL, deployed to the FPGA. After that: an open-source architecture for SHA-1 collision hunting that makes Bitcoin’s address space look rather less comfortable. All designs public — because if the vulnerability exists, pretending otherwise is just poor manners. Any coins found can fund something useful. Clean energy. Quantum computing. Not espresso machines with a subscription model.

    Ceterum censeo slopem esse delendam.

    (Cato the Elder ended every speech in the Roman Senate with “Carthage must be destroyed” — regardless of the topic. This is that, but for AI slop.)

    Repositories:

  • The Synthesis Problem: Why I’m Building a New Logic Toolchain

    Modern chip design leaves performance on the table. A lot of it. Meanwhile, billionaire CEOs with the technical depth of a drunk high-schooler who wants to be new age when he grows up keep calling a glorified autocomplete “AGI.” Nobody’s asking if the circuit itself is well-designed — just whether the output sounds smart.

    The tools we use to go from a logical specification to a physical circuit are decades old in their core ideas. They work — billions of transistors ship every year — but they settle for “good enough” at almost every stage of the pipeline. Synthesis heuristics that don’t explore the real optimization space. Representation formats that can’t talk to each other. A wall between the people who study formal logic and the people who tape out silicon.

    I want to build better circuits. Not a better CPU, not a better GPU — better circuits, generally. Classical, reversible, quantum. The kind of improvement that comes from rethinking the synthesis process itself, not from adding more transistors.

    That’s what this project is about.

    What I Actually Built

    Over the past several years, I’ve been assembling an open source toolchain that connects formal logic to real hardware. Each piece exists because I hit a wall with existing tools.

    llogic is the foundation — a library of logic representations. Boolean formulas, CNF, DNF, OBDDs, QBF, combinational circuits, reversible circuits, quantum circuits. They all live under one roof because they share more structure than the textbooks let on. A circuit is a formula is a constraint problem. If your tools understand that, you can move between representations and optimize across them.

    lcfgen generates circuit families — parameterized circuit structures that let you explore design spaces systematically instead of hand-wiring one instance at a time.

    llogic2verilog translates circuits from llogic’s internal representation into synthesizable Verilog. This is the bridge from formal logic to hardware toolchains.

    lverilog is a Verilog parser that produces a clean AST, because I needed one that I could actually inspect and transform programmatically without fighting a legacy codebase.

    llogic_basys3 is the proof that this isn’t academic exercise. It targets the Digilent Basys3 board — a Xilinx Artix-7 FPGA — and runs brute-force integer factorization by testing 16×16 bit multiplication at 50 MHz. A MicroBlaze soft processor drives the circuit over AXI, exposed as a UART interface. You feed it a number, it searches for factors — on a $150 hobby board, clocking through candidates at 50 million per second.

    Theory in. Hardware out. No marketing budget required, no claims of sentience.

    Why This Matters

    The connection between Boolean satisfiability, quantified Boolean formulas, and circuit structure is well-studied in theory. My published work on QBF-based circuit synthesis showed that you can use the structure of quantified formulas to derive circuits with provable properties. But the research community largely stops at the paper. The tooling to go from that theory to running hardware didn’t exist.

    It does now.

    And the scope is broader than classical digital logic. The same formal framework that represents a combinational circuit can represent a reversible circuit or a quantum circuit. The same optimization that simplifies a Boolean formula can simplify a quantum algorithm’s gate structure. There’s a deep connection to Bayesian inference here too — probabilistic reasoning over circuit structure — that I’ll write about separately.

    Where This Goes

    I’m not building a toolchain for the sake of building a toolchain. I care about two things: scalability and energy efficiency. Better synthesis means smaller circuits. Smaller circuits mean less power, less area, more throughput. At scale, this is the difference between a computation that’s feasible and one that isn’t.

    The implications reach beyond hardware design. Optimized circuit structures have direct applications in machine learning acceleration — which is to say, making the very large circuits that people mistake for intelligence actually run efficiently. The same goes for cryptanalysis and scientific computing — anywhere you’re bottlenecked by the gap between what you want to compute and what the hardware can deliver. I’ll write about those connections in future posts.

    The FPGA demo is the first milestone — a hobby board factoring integers to prove the pipeline works end-to-end. The next steps involve pushing the optimization boundaries, extending to quantum targets, and making the case — with working hardware — that this approach produces better circuits.

    If you’re a researcher working on synthesis, a hardware engineer frustrated with your tools, or a program manager looking for the next leap in design methodology: let’s talk.

    The code is open source. The results are reproducible. The ambition is to build circuits more powerful than anything that exists today.

    Repositories:

  • An Essay on Computation

    Since ancient time, humans have been building surprisingly intelligent computers. Computation is a very broad term. It happens not only in man-made computers but also in nature. The basis of computation is deceptively simple: if there is a notion of memory, one can count. By using counting, it is possible to perform addition. Addition is in the basis of multiplication. With addition and multiplication we are half-way there, having almost all of mathematics. Of course, this opening argument just promote me to be the dean of the faculty of gross generalization.

    One of the fundamental foundational questions, popularized by Scientific American, is if the universe is analog or digital. While the correct answer is probably “neither and both, it is quantum, it is the solution of the Schrödinger equation for all particles in the universe, it is a complex vector that only the universe can compute”, I find quantum computers juxtaposing analog and digital concepts. A qubit is a superposition (linear combination) of zeros and ones although there is nothing special about choosing zero and one. It is possible, and although sounding exotic, I am sure there are, quantum computers whose state is made of ternary (for example) qubits.

    Let’s switch the topic and talk about errors in computation. All our machines make errors and everything around us is imperfect. What is worse, is that people want to scale computation, taking the output of one computational block and feeding it to another. Modern computational platforms are truly humongous. An average Pentium processor has thousands of NAND-gates. A NAND-gate is the basic logical computational building block of modern von-Neumann computing. As we will see in more technical detail in subsequent posts, a NAND gate is a very primitive device. Even to add two 16-bit numbers we need hundreds of them.

    A NAND gate in the device on which you are reading this is made out of CMOS transistors. The CMOS transistor is an analog device, even though we use only two voltages values (the values depend on the process being used), there is always some amount of noise, leakage, and imperfection. The ingenious thing behind the NAND gate is that, after feeding the input voltages, the electrical circuits of the NAND gate bring the output to either the power ground or to the power supply rail. These two latter values are used for logical zero and one. Let’s say that zero is everything between 0 V and 1.5 V and one is everything between 3V and 5V. This means that no matter if we take 0.1 V and 4.5 V as inputs or 1.2 V and 3.2 V, the output will always be close to 5V, no matter what. So, a NAND gate is self-error-correcting in a way. This allows the scaling-up and chaining of thousands of gates and we know that the Boolean zero/one result is always correct.

    Now you have a taste of what I will be writing about. I will try to be practical, precise, sciency, comprehensible, understandable, and fun. And, of course, I will be writing about many things. As one of my favorite Dutch expression says about “koetjes en kalfjes” (Google DuckDuckGo it).