blst: a BLS12-381 signature library written in C and assembly
Multilingual BLS12-381 signature library
At a glance
- What is it?
- blst is the pairing-based cryptography library behind a good deal of the signature work in proof-of-stake systems, and it is interesting for two reasons beyond raw speed: it has been audited by a firm whose report is public and is being formally verified by another, and it deliberately refuses to manage memory, start threads, or generate random numbers, on the grounds that those belong to the binding rather than to the library.
- Who is it for?
- blst fits a project implementing BLS signatures for a proof-of-stake protocol or a signature aggregation scheme, particularly one that already knows the specifications it must follow and wants the arithmetic to be fast and independently checked. It does not fit a project that wants a complete cryptographic toolkit, because the library does not provide random number generation and leaves memory and threading to the caller.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Assembly, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the library is, and where the trust comes from
blst, pronounced like the word blast, is a BLS12-381 signature library focused on performance and security. It is written in C and assembly.
The two words in that focus statement matter separately, because they pull in different directions and the library resolves the tension by being small. Performance comes from the assembly modules, which implement the field and curve arithmetic for specific instruction sets. Security comes from the library being narrow, so that there is less of it to be wrong about, and from the fact that the arithmetic has been examined by people whose job is examining arithmetic.
The trust evidence is the part of the readme that matters most, and there are three strands to it.
An initial audit was conducted by a security consultancy in January 2021, and the report is linked directly rather than summarised, which is what you want from an audit: you read it yourself and decide what it means for your use.
Formal verification of the library is on-going and is being done by another organisation, with the work published in its own repository so that the verification is checkable rather than a claim in a slide deck. Formal verification of a pairing library is a large undertaking, and the fact that it is in progress rather than complete is stated plainly in the readme.
And the library is compliant with two specifications: the IETF draft for BLS signatures, at version six, and the final RFC for hashing to elliptic curves. Those are the two pieces of the puzzle that a caller has to get exactly right, because a signature that does not match the specification is a signature nobody else can verify. The serialization format is implemented according to a definition named in the readme, which is the third compatibility point and the one most likely to bite somebody implementing a network from an older draft.
The readme says the library is under active development, which is the fourth strand and the one that tells you how to read the rest. A library in active development with a public audit and a verification effort in progress is a library you can use and should keep watching.
The three things the library refuses to do
The general notes on implementation contain the most unusual decision in the project, and it is a decision about scope.
The library deliberately abstains from dealing with memory management and multi-threading, with the rationale that these ultimately belong in language-specific bindings. Another responsibility that is left to the application is random number generation.
All of it is in the name of run-time neutrality, and the readme says that this makes integration into more stringent environments like Intel SGX or ARM TrustZone trivial.
That word trivial is the payoff, and it is worth understanding why the omission buys it. An enclave or a secure world restricts what a process may do: it may not allocate in certain ways, it may not create threads, it may not read a system source of randomness without an explicit syscall into the host. A library that allocates, that spawns a thread pool, and that calls the system generator internally has to be rewritten for such an environment, or replaced. A library that does none of those is already inside the environment's rules, because it does nothing that the environment forbids.
So the omissions are the features. The library is a set of pure operations over a 256-bit secret key, a curve point, and a field element, and it leaves the caller to decide where those values live and how long they live.
The other notable decision is in the same paragraph. The field operations are optimized for general 384-bit usage, as opposed to being tuned specifically for the 381-bit parameters of the BLS12-381 curve. The stated reason is that some decisions are made to maximise the public good beyond this one curve, and with the formal verification of these foundational components the authors believe the same building block can serve other curves that want high performance and an extra element of security.
That is a real engineering trade. Specialising the arithmetic for exactly 381 bits would make this curve faster. Optimising for 384 bits makes the arithmetic reusable, and it makes the verification effort apply to a more general component. The library chooses the second, and says so, which is the kind of decision that is much easier to appreciate once somebody explains it.
Platforms, and two bindings that are not generated
The library primarily supports two hardware platforms and three operating systems, and then has a portable fallback for everything else.
The primary targets are 64-bit x86 and 64-bit ARM, on Linux, Mac and Windows. Those are the platforms where the assembly modules exist and where the performance claim is meaningful. But there is a portable replacement for the assembly modules, which can be compiled for a much wider set of platforms, and the readme says that problem reports for those other platforms will be considered and are likely to be addressed.
That is a sensible arrangement for a cryptographic library: the fast path is where the users are, and the correct path is everywhere else.
The bindings are where the design decision about language neutrality pays off, and the readme splits them into three tiers.
Two languages have explicit bindings written for them: Go and Rust, each with its own directory in the repository. These are the ones maintained by hand, and the two are chosen for a reason worth guessing at and worth stating carefully: they are languages whose runtime characteristics match the library's design, and both have a serious cryptographic ecosystem that needs a pairing library.
Other languages are handled by a code generator, unless there is a reason to write the binding by hand, and there are proof-of-concept scripts for Python, Java, Node.js, the WebAssembly toolchain, C#, and Zig.
The word proof-of-concept in that list is doing careful work. It distinguishes the generated bindings, which exist and work, from bindings that have had dedicated attention, and it tells a reader how much confidence to place in the first line of a new binding when the library itself is stable.
The Go binding has its own module file, and the repository has a Go language server configuration, a lint configuration, and a Go module marker file whose declared language version is old enough to be worth noticing for a library that is otherwise actively developed.
The interface, and the staging area next to it
The interface is a C header, and the readme organises the whole of it into four groups, which is the fastest way to understand what the library does.
Field operations are the arithmetic on the base field: addition, subtraction, multiplication, negation, inversion, and conversion to and from the Montgomery representation, which is the representation the assembly code uses because it keeps the numbers in a form where multiplication does not need a division.
Curve operations are the group arithmetic on the two curves: addition, doubling, scalar multiplication, conversion to and from affine coordinates, and a group check, which is the operation that verifies a point is actually on the curve and in the right subgroup. That last one is a security operation rather than a convenience, and having it in the interface is a statement about what the library considers its job.
The intermediate operations are hash to curve, pairing, and serialization and deserialization. The pairing is the operation that makes pairing-based cryptography work at all, and hash to curve is the step that turns an arbitrary message into a point that can be signed.
And then the signature operations proper: sign, verify, and aggregate. Aggregation is what makes this kind of signature interesting, because it allows many signatures to be combined into one, and a system that wants to aggregate needs the whole of the underlying machinery to be correct.
The second header is the interesting structural detail. There is an auxiliary header used as a staging area for experimental interfaces that may or may not get promoted into the main header. That is a real convention in library design and it is worth naming what it buys: it lets a new function be shipped, used, and argued about without it becoming a permanent part of the public interface, and it keeps the main header small enough that the compatibility guarantee behind it stays meaningful.
So the shape is: a small, stable, audited interface for the cryptography, and a slightly larger, unstable one for whatever is being worked on. For a library that other cryptographic libraries are built on top of, that separation is what makes the dependency safe to take.
The tutorial and its two counter-intuitions
The readme includes an introductory tutorial, and its framing is charming and slightly unusual: programming is understanding, and understanding implies mastering the lingo. It opens by pointing at the idea of a pair of additive groups being mapped to a multiplicative one and says that the tutorial is not about explaining that, but about connecting what you are supposed to know about pairing-based cryptography to the interface the library provides.
The tutorial itself is where the naming conventions are explained, and two things in it surprise almost everybody the first time.
The first is that a signing function does not sign a message. The signing operations sign a point on the corresponding elliptic curve, and you get that point from a message by calling the hash to curve or the encode to curve function first. That is not an implementation detail; it is the specification's design, and it is what makes the same point usable for things other than a message.
The second surprise is the naming mismatch. The signing function whose name mentions the first curve accepts output from the hash function that targets the second curve, and the other way round. The readme explains it: public keys and signatures come from complementary groups.
Everything else in the tutorial follows from those two points, and it is worth following because the names make sense afterwards.
There are two elliptic curves, with points held in two structures each, one for the projective form and one for the affine form, and elements of the multiplicative group in a third structure for the twelfth-degree extension field. One subset of points is chosen for public keys and another for signatures, and the choice is written into the name of the subroutine as a suffix.
The secret key is a scalar of 256 bits, created either by the key generation function or by deserializing a previously stored byte sequence, and the readme points out that there are two distinct uses for it: generating the associated public key, and performing a sign operation.
And once there is a public key and a signature, both can be serialized into byte sequences with either a straightforward serialization or a compressed one, and sent over the wire. The tutorial's closing line is cut off in the version available here, but the direction is clear: the library covers the whole path from a secret key to a message that somebody else can verify.
The repository, and what the build files tell you
The top level of the repository is short, and each entry means something about how the project is put together.
There is a source directory, a bindings directory, and a build directory, plus a build script for the Unix shells and a batch file for Windows. And there are two more build entry points, one written for the Zig build system and one for its package manager, which is worth noting because it tells you that the project is built by people who work in more than one ecosystem, and that the build configuration is treated as something to be expressed in the tooling of whoever is building it.
The bindings directory holds the interface headers and the per-language directories, and the source directory holds the assembly and C that the bindings call into. That separation is the mechanism by which the library stays language neutral: the cryptography is compiled once, and each binding is a thin translation of the header into the conventions of its language.
The continuous integration configuration is a mixture that also says something: a build workflow, a code analysis workflow, a lint configuration, and a configuration for a service that has since been folded into another. That is the residue of a project that has been running checks in several places over several years, which is normal and harmless, and it is the kind of thing a maintainer tidies when they have a free afternoon.
And there is a security policy file at the root, which is the file that says how to report a vulnerability in a cryptography library. For a library like this one, with an audit already published and a formal verification effort running, a published route for reporting a problem is part of the trust story rather than an afterthought.
The licence is Apache 2.0, the primary language is recorded as assembly, which is an honest description of where the performance comes from, and the release history shows a stream of patch releases across three versions, which is what a mature cryptographic library looks like: frequent small releases, a stable interface, and a large gap between them.
Editorial conclusion
blst fits a project implementing BLS signatures for a proof-of-stake protocol or a signature aggregation scheme, particularly one that already knows the specifications it must follow and wants the arithmetic to be fast and independently checked. It does not fit a project that wants a complete cryptographic toolkit, because the library does not provide random number generation and leaves memory and threading to the caller. Verify first which draft or final specification your network implements, because the library names two and the signature scheme has been revised, that you choose the right binding for the language you are using, since only two are first class and the rest are generated or experimental, and that you read the audit report and the verification repository rather than assuming that either of them covers the code you are shipping.
Frequently asked questions
What is the blst library?
It is a BLS12-381 signature library written in C and assembly, focused on performance and security. It provides field and curve arithmetic, hash to curve, pairings, serialization, and the signature operations themselves including sign, verify and aggregate, exposed through a C header with bindings for many languages.
Why does blst leave memory management, threading and random number generation to the caller?
To stay neutral at run time, so that the library can be used inside restrictive environments such as Intel SGX or ARM TrustZone without being rewritten. Those responsibilities belong to the language-specific bindings, and a library that only performs pure operations on keys and points does nothing that such an environment forbids.
Has blst been audited and formally verified?
An initial audit by a security consultancy was conducted in January 2021 and the report is published. Formal verification by another organisation is on-going and is published in its own repository. The readme states that the library is under active development, so both efforts are described as current rather than finished.
Which specifications does blst comply with?
The IETF draft for BLS signatures at version six and the final RFC for hashing to elliptic curves, and the serialization format follows a separately named definition. The readme links all three, and they matter because a signature that does not match the specification cannot be verified by anybody else.
Why does the blst signing function take a curve point instead of a message?
Because the specification works that way. You turn a message into a point with the hash to curve or the encode to curve function first, and then sign the point. The apparent mismatch between the curve named in the signing function and the curve named in the hashing function is deliberate, because public keys and signatures come from complementary groups.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/supranational-blst)Was this useful?