# lets-prove-leftpad: the same padding function proved in two dozen proof systems

> The lets-prove-leftpad repository holds provably correct implementations of leftpad across about two dozen formal verification systems, from Coq and Lean to Frama-C and Dafny, so the same trivial specification can be used to compare how each tool expresses a proof. It is a teaching and comparison project, not a library anyone would depend on.

**hwayne/lets-prove-leftpad** — Proving leftpad correct two-dozen different ways

- Repository: https://github.com/hwayne/lets-prove-leftpad
- Stars: 757 · Forks: 68
- Language: SystemVerilog
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/hwayne-lets-prove-leftpad

## One specification, repeated across every major proof assistant

The lets-prove-leftpad repository collects provably correct versions of a single function. Leftpad takes a character, a length, and a string, and pads the string to that length by adding the character on the left.

```python
>> leftpad('!', 5, "foo")
!!foo
>> leftpad('!', 0, "foo")
foo
```

The README calls the collection a sampler of all the different tools that can be used to prove code correct, standardized by all being proofs for leftpad. That standardisation is the entire point. Because the function is tiny, the interesting variable is not the algorithm but the proof system, and the repository turns that into something you can compare side by side.

The direction of the work is documented in a linked post on the author's site, which the README points to for the motivations and history. The formal methods angle is also personal rather than academic, since the author says he shouts at clouds about formal methods on his website and on Bluesky, and the repository asks people who want to contribute to read the contribution guidelines in CONTRIBUTING.md and submit their favourite proofs.

## The specification is where the difficulty actually lives

The README makes a point that surprises people who have not written specifications before: the implementation is simple, but the specification, meaning what you actually and formally want the function to do, is surprisingly tricky.

Three properties have to be proved for something to count as leftpad. The length of the output must be max(n, len(str)). The prefix of the output must be padding characters and nothing but padding characters. The suffix of the output must be the original string.

Each of those three clauses carries a hidden question. Max means the function has to handle the case where the string is already longer than the requested length, and a specification that does not say what happens then is incomplete. The prefix clause is a universal statement over a range, not a check of one position. The suffix clause has to line up with the prefix clause, since the two together fix the length of the padding. Writing a specification that captures all of that is the work, and the README notes that a proof of leftpad is meant to be small enough to be mostly grokkable by formal methods outsiders while being complex enough to differentiate the ways proofs are written.

That framing explains why a joke repository is worth reading. The claim being tested is the one the README makes about provable correctness: if the proof is wrong, the code will not compile. Compare that to testing, where even a thousand inputs leave the thousand and first case unknown.

## The directory listing is the real content of the repository

The top level of the repository is a list of proof systems, one directory each, and that listing is the most informative thing in the project. It includes acl2, agda, b, coq_ssreflect, cryptol, dafny, dafny with a functional variant, frama-c, fstar, hol-light, hol4, idris, isabelle, java, lean3, lean4, liquidhaskell, maude, metamath, rocq, smtlib, tlaps, tlaps with a no temporal logic variant, verifast, verus with a rust variant, why3, and z3py.

What this tells you is the range of the formal methods world that the author wanted represented. There are interactive theorem provers with general purpose logics such as Coq, Rocq, Lean, Agda, Isabelle, HOL Light and HOL4, and there are specialised verification tools built around a specific programming language, which is what frama-c for C, liquidhaskell for Haskell, verifast for C and Java, and verus for Rust are. There are language-level specification languages such as Dafny and Why3, there is a temporal logic tool in tlaps, and there is a cryptol entry for the Cryptol language used in hardware verification. b and maude are algebraic and rewriting toolkits, metamath is a proof system in its own right, and smtlib is a format directory rather than a prover.

That variety is what makes the collection worth browsing. Two directories marked as variants, one functional dafny and one rust verus, plus the tlaps split, show the author treating the same problem in several modes of use rather than just listing tool names.

## Proving versus testing, stated as a comparison rather than a slogan

The README draws a deliberate contrast between proofs and tests, and it does so with a specific argument rather than a general claim. The claim of provable correctness is that you can totally guarantee the code does what you say it does, and the way you do that is by providing a proof that a computer can check.

Against that, the README points out that even if you test your function for a thousand different inputs, you still do not know for sure that the thousand and first test will pass. With a proof, the function works for all inputs, regardless of whether you try a thousand cases or ten trillion.

The README also acknowledges the cost honestly. Proving code correct is described as extremely hard, and also mindbogglingly hard, which is the stated reason most programmers do not do it. That is the framing to keep in mind when looking at the repository: the value here is educational, since the proofs are small enough to read and the toolchains are large enough to be intimidating.

One detail is worth flagging for anyone judging scope. The roughly two dozen directories represent that many independent toolchains, and each one has its own build system, its own proof assistant, its own installation, and often its own version of the same function. There is no unified build, and the README does not describe one.

## A project with no releases and a custom licence

The repository has no GitHub releases, and the last push was on 2026-07-07. The default branch is master, and the collection is not packaged in any form that a consumer would install, since each directory targets a different toolchain with its own conventions.

The licence is the one item that needs care. The licence field records Other, described as a custom licence that GitHub cannot classify, with a pointer to the LICENSE file. For a repository whose entire purpose is to be copied and modified, since every proof is a contribution and every contribution is meant to be reusable, the exact terms matter more than usual. A reader who wants to reuse one of the proofs inside a larger verified project needs to read that file rather than assume the permissive terms that similar teaching repositories often carry.

The repository also carries a CODE_OF_CONDUCT.md and a.gitignore, and the primary language is recorded as SystemVerilog, which is interesting given the list of directories. Given that the collection spans proof systems written for many different languages, it is a useful reminder that the SystemVerilog directory is one entry among many rather than the main event.

## Where this sits against writing a proof from scratch

The alternative to reading a leftpad proof is writing one yourself, and the difference is instructive. Starting from an empty file in a single tool means making every decision yourself: how to state the specification, whether to use a refinement type or a Hoare triple or a dependent function type, how much library scaffolding to assume. The result is a proof that is coherent but that quietly inherits your assumptions.

A collection like this reverses that. Because every entry targets the same three properties, the differences between the directories are the differences between the systems rather than the differences between two people's choices. A proof written in a refinement type checker, where the return type itself states the length guarantee, looks structurally different from one written in a pure theorem prover, where the length fact is a separate lemma, even though both establish the same property. Reading several side by side is the cheapest way to see which style suits a given problem.

The comparison also has limits. Each proof was written by someone who knows that tool, so the comparison is between what each system allows and encourages, not between what is possible in each. A lean or coq proof here is not evidence that the other system cannot express the same thing. And a proof that compiles in one system says nothing about the maintenance cost of the surrounding infrastructure, which for most of these directories is the dominant factor in whether the proof survives contact with a real codebase.

## Conclusion

lets-prove-leftpad fits a developer who wants to see what a proof looks like in a system they are considering learning, and it does not fit a team looking for a padding function to ship, since the implementations are demonstrations with per-system tooling rather than a maintained library. Before spending an afternoon in one directory, pick the target system first and read the contribution guidelines in CONTRIBUTING.md, because each proof carries the build and dependency overhead of its own toolchain and the repository has no releases, so there is no version of the collection to pin against.

## FAQ

### What is leftpad and what does the lets-prove-leftpad repository prove?

Leftpad takes a character, a length, and a string, and pads the string to that length by adding the character on the left. The repository holds provably correct versions of that function across about two dozen proof systems, each of which must show that the output length is max(n, len(str)), that the prefix is padding characters only, and that the suffix is the original string.

### Which formal verification systems does the repository cover?

The top level directories include acl2, agda, b, coq_ssreflect, cryptol, dafny, frama-c, fstar, hol-light, hol4, idris, isabelle, java, lean3, lean4, liquidhaskell, maude, metamath, rocq, smtlib, tlaps, verifast, verus, why3, and z3py, with separate functional and rust variants for dafny and verus and a tlaps variant without temporal logic.

### Why does the repository exist if leftpad is a trivial function?

The README gives two reasons: it is funny, and leftpad is a good demo for different proof techniques. The idea is simple and the implementation is simple, but the specification of what you formally want is surprisingly tricky, so the same problem is used to compare how different tools express a proof.

### How do I contribute a proof to lets-prove-leftpad?

The README asks contributors to read the contribution guidelines in CONTRIBUTING.md and then submit their favourite proofs, adding a directory for their system. The project also has a CODE_OF_CONDUCT.md.

### Can I use lets-prove-leftpad in a production project?

The repository is a teaching and comparison collection rather than a packaged library, it has no GitHub releases, and its licence is a custom one that GitHub cannot classify, with the terms in the LICENSE file. A reader who wants to reuse a proof should read that file and the per directory build instructions first.

## Sources

- [hwayne/lets-prove-leftpad on GitHub](https://github.com/hwayne/lets-prove-leftpad)
- [Issues](https://github.com/hwayne/lets-prove-leftpad/issues)
- [README](https://github.com/hwayne/lets-prove-leftpad/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hwayne-lets-prove-leftpad
