Simple web-based tool for BLS keys

This is a tool for working with BLS keys as used in most aspects of SAFE network operations (wallet, vaults, accounts etc).

Use the tool here
or download it for offline use here (download bls-standalone.html)

My main reason for doing it (besides learning wasm and bls) was because the output from safe-api commands did not seem to be compatible with any existing BLS tools, despite being based on a standard BLS pairing BLS12-381. The main one I was interested in was the herumi tool, make sure to select BLS12_381 pairing parameter, you’ll notice the key lengths are different to what is given by safe-api and this tool.

Some quirks that are kinda neat

  • The tool is pretty compact. It’s about 300K, 100K when compressed. Compared to, say, the BIP39 tool which is 4MB that’s really impressive. The wasm binary is 194K when compiled and after conversion to base64 for use in the tool grows to around 279K.

  • wasm is usually loaded as a module (ie from a server), so getting this working in a single static html page was a pretty neat trick. Single static html page is useful because you can save it to a thumb drive and run it on an offline computer.

  • Compiling threshold_crypto to wasm was extremely simple. The main hurdle I came across was the random number generator which needed to be replaced with a ‘static’ one that doesn’t try to access the operating system rng. Working with wasm is a little tricky because it can’t easily return arrays or strings or any complex responses, it can only return a single number at a time. So some tricks with iteratively getting and setting bytes within fixed arrays was needed, but in the end is not too much hassle.

  • There are no javascript libraries used in the tool, or css frameworks. It’s nice to just write clean native javascript and have a few simple css declarations. Rust dependencies are as close to just threshold_crypto as possible, I didn’t bring any convenience helpers for wasm-to-javascript.

Some things I’m still a little uncertain about, any help would be great

  • What is the effect of using a very basic random number generator for encrypt? Since wasm can’t work with the random number generator supplied by the operating system (which rng_core uses by default), the process used by the tool is

    • generate secure random u64 in javascript (ie a length 2 uint32array in javascript populated by Crypto.getRandomValues)
    • use this generated u64 to seed a very basic rust random number generator
    • use that basic random number generator when encrypting, ie PublicKey::encrypt_with_rng.
    • @AndreasF I’m hoping you’re still around in the forum, I saw you’re a large contributor to the threshold_crypto library and was hoping you might have some insight into the specific rng system I’ve used and whether it’s ok to use it for encrypt? It looks to me like it’s only used to determine u so that single u64 from javascript is ok in this instance?
  • Is it valid to generate secure random bytes for the secret key in javascript, then try to deserialize them into a threshold_crypto::SecretKey? Sometimes this deserialization process fails so I keep retrying a new set of random bytes until it works (usually no more than 3 retries needed, the most retries I’ve seen is 11). Is there any risks or faults with this approach to generating secret keys?

If you want to test, here’s a few things to start you off

My public key:


I signed a message which you can verify:

Thanks for trying it out!

If you want you can post your public key here and I’ll send you an encrypted message for a laugh. Keep in mind this is a very alpha release, still some features to be finished, automated tests to be written, this is a release-early-release-often kinda tool.

You can also use the safe-api command safe auth create-acc to generate keys that will work with this tool.


Again amazing work @mav We (the community) are lucky to have such great input.


Which PRNG did you use, I only know a few like Mersanne twister and Fortuna.

True RNG is hard, I saw an episode of Numberphile on youtube, apparently one way of true RNG is observing the decay of radioactive materials. :slightly_smiling_face:


next = old + 1 :slight_smile: seriously.

My question is, does the proper use of the encrypt function depend only on the initial value of the rng (which is a strong random value from javascript Crypto.getRandomValues) or does it also depend on next() generating an actually random number?


In the rust rand crates, rand_core defines some traits next_u64() is again a random number and hopefully not guessable. RngCore in rand_core - Rust Not sure that helps. Rng is a very hard subject as you know. Here we really need a CSPRNG IMO.


Really cool tool! Was fun to play around with and sign random messages

I’ll bite, here’s mine :slight_smile:

My public key:

Not sure about the rng stuff, so can’t really weigh in on it (it’s definitely a dicey subject as mentioned earlier), but I’d be interested to know if you can dig up an answer to the question of encrypt depending on next().


If it is a problem then it’s easy to solve. Just pump a vector full of random values from javascript and have the prng iterate over the vector. But if a simple solution works then no need to add this complexity. Let’s see what comes up about the importance of next() for encrypt().

1 Like

:joy:, First I thought it was a mathematical joke but then I saw the link.

I totaly get it, there are probably some russian guy in a shed somewhere in Siberia who make these things, no need to invent the wheel twice. :slightly_smiling_face:

I hope we can help you find the answer.

1 Like

Wow… brilliant!


I read the source code into the dependencies to see how many random values were required but felt I started getting too far into the weeds once I got into crate pairing (elliptic curves) and ff (finite fields).

And then I realised I can easily see how often next is called by logging it each time it’s called (seemed so obvious once I realised it :man_facepalming:). Turns out is called 4 times every time encrypt is used.

This change has been published in v0.1.2 of the tool, see the rng changes in this commit Encrypt messages with correct amount of randomness · iancoleman/blsttc_ui@64296a4 · GitHub


A new feature has been added for generating and managing multisig wallet keys.

Use it on the website or download bls-standalone.html.

So far the tool has only dealt with single keys. The new feature is for group keys. There are two main ways that group keys can be generated.

The first way to generate group keys (which in this tool I’ve called Simple Threshold Keys) is where a single user controls all aspects of the keys, eg a multisig wallet, so they are trusted to derive all secret and public keys and distribute them to people.

There’s a second way to generate keys which is Distributed Key Generation (DKG) which I will be implementing next. Each person generates their secret key privately and only shares their public keys. The public keys are combined into a group public key for doing crypto operations as a group. This is how elder nodes will generate keys for doing stuff as a section. It’s a way for untrusted entities to form group keys and is quite different to the Simple Threshold Keys where all key management is done by a single trusted entity.

Group crypto operations are sign and verify where m-of-n keys are needed to create a valid signature, and encrypt and decrypt where m-of-n keys are needed to decrypt a message.

Technical question: Is poly a suitable object / abstraction to be using for backups? It’s a handy single data point that can be used to derive all needed info, a bit like a bip32 root key. Any suggestions for best practices here? This is really getting deep into the implementation details of the threshold_crypto crate so I’m not really expecting an answer to be honest…!

A bit of a technical look into what’s coming next, any tips are welcome: With DKG, maidsafe uses this process to generate keys. It seems like the order of keys matters: “The members of the DKG session must also be deterministic, meaning that all members must use the same members list”. Does this mean all members must use the same order for members, or is any order ok? In BLS-DKG the order seems to matter and is based on sorting (see this code in the test) where id is a random number. But nowhere else besides in the test code do I see sorting. Does order of members matter? I’m going to dig into this myself while developing the next part of the interface, but if anyone has an easy answer off the top of their head (or enjoys doing some code digging) I’d be keen to hear it.

Also I know @qi_ma you are not a particularly public figure so I’m hesitant to tag you here, but it’s truly impressive how much you’ve contributed to the SAFE network and the BLS keys aspects (especially the DKG aspect). Thank you so much for your work and your code which has been invaluable while creating this tool. BLS-DKG in particular is unbelievable.


Yes, they have to.

It’s because in the production code, we use BTreeSet, which ensures the ids are sorted.
The testing code using a vector with sort just to explicitly demo this.

And last, really appreciate your warm words! :smile:


Your presence here is infrequent but valued every time you do show up :slight_smile:


whether it’s ok to use it for encrypt ?

If I remember correctly it’s pretty important for the random number to be secure: If you can crack it, i.e. find out the random number, you can decrypt the message (without the secret key).


The tool now has Distributed Key Generation (DKG)

A way to generate a group public key by coordinated action rather than a trusted dealer.

This is how a group of untrusted nodes (eg elders in a section on the SAFE network) can form a group key without giving away any individual secrets or trusting any individual participant.

Something to keep in mind is this scenario is by nature not done by a single entity or in one hit. So it’s more of a demo or example rather than a tool for generating and managing keys in a DKG style.

It’s a very simple concept at a high level, but a lot of technical language and concepts underlying it which took a fair bit of exploring to grok. Hopefully the language of the tool is simple enough to grasp, and not too simple that it hides the real process happening. I’ll add a glossary for dkg soon to help link the UI to the libraries that are running behind it all.

Ultimately this feels like it’s not a very useful feature, but I found it interesting. BLS-DKG is really cool.


Ah nice one @mav.

This is definitely a great tool for learning about the various bits of BLS :tada:


@mav, you are are already famous for your BIP39 tool, I guess that you will be also famous for your BLS tool when safe network is out.

The problem with wasm in Rust is that normally you need WebPack to generate the executive code to make the link between JavaScript and Rust and this package manager needs to be configured with a json file and I don’t grasp the syntax of this configuration file.

You avoided the use of a package manager but at the price of a 167 lines Python script, which is certainly not simpler than a configuration file.

To avoid both a configuration file and a script file, there is Parcel package manager that has no configuration file and can automatically handle wasm generated from a Rust crate.

I tried this technology on a fork of you repository and it seems to work. My fork is GitHub - Thierry61/threshold_crypto_ui: UI for threshold_crypto rust library and the result can be tested in the associated GitHub page BLS - Threshold Crypto (which is a simple static web site).

Additionally the Python script was concatenating js files inside index.html and debugging on original source files was not possible, whereas Parcel generates map files that allow this.

If you’re interested I can issue a pull request. Modifications are small: a few lines here and there, plus docs directory that is generated by npm build command.


Open source: take a good idea, refine it, hand it back, repeat.


Cool to see these mods!

The main question that arises for me from this is, how is bls-standalone.html generated? When the python script was removed this was no longer possible.

It’s true that Parcel creates a static website but it requires 8 requests. The important part is the request for the .wasm file has content type application/wasm which cannot easily be stiched into a .html file (application/javascript requests can be stiched into a <script> tag, wasm cannot). This is subtly mentioned in the original post and requires a neat trick so “you can bypass the fetch of the wasm file and instantiate a WebAssembly module directly with the array”. For a single page application this is crucial, and using parcel will not resolve this. Some glue code is still required.

The python script glues all the resources (javascript, stylesheets, webassembly) on a single page. This requires some html/js template and some wasm bytes to be read and converted for use in the template. Ideally the wasm could be put directly into a tag, maybe <script type="wasm"> but to my knowledge that does not exist.

The number of requests is not the problem. It’s that the tool cannot be downloaded as a single file for use elsewhere (much like mhtml would achieve but that format doesn’t seem widely supported or used). A single file makes it easy to use offline, easy to put on a USB or email attachment, easy to release on github, easy to hash for verification, easy to sign with gpg, easy to double click in a file explorer.

One of the side effects of using parcel is there are now lines in the javascript (index.js) specific to the rust, eg import wasmExports from '../../Cargo.toml' and which will not work on a single html page.

A minor detail but this project would now depend on nodejs (which is not included on most linux distros by default to my understanding) whereas python is on most linux distros by default. I was tempted to do the glue using some npm package but in the end some lines of python was so much simpler.

I personally consider around 100 lines of python (once comments and html template string are removed) to be much simpler than installing a whole environment and parcel package to do the same thing (but not really the same thing since it’s no longer a single page). You’ll notice the python script doesn’t use anything outside the standard python library, no python package management required. I can see where you’re coming from and how using standard packages etc is a good idea, but in this case I’m not sure I agree with the benefit. If it were a large project or part of a company with standard modus operandi then sure, but that’s not the case and I doubt it ever will be.

A couple of tangents

I plan to change from the homegrown test suite to something like jasmine+selenium which will probably introduce a nodejs dependency anyhow (like bip39 test suite does), so then it would have rust for library + python for glue + nodejs for tests… kinda ugly! Selenium can run on python so maybe I will take that angle…? For now the homegrown test suite is fine, probably it won’t end up being necessary to upgrade it.

BIP39 tool conveniently will load from the src directory so can be reloaded directly in the browser as it’s developed. This is because it’s pure js, no rust or wasm (it has npm libraries but once compiled they stay untouched, a bit like wasm in this tool actually). The python script in bip39 tool is only there to generate the release file. But this tool requires building the library and converting to the single page for every change whether it be the rust wasm or the html/js/css. Maybe it would be best to have a two stage conversion, one to compile the wasm and stich it into index.html, then another to compile everything into a single page for release. This would allow the development html files to be loaded directly by the browser and the glue step only needed when wasm is changed. This would address the issue that ‘debugging on original source files was not possible’. I agree this is a pain point, but I have never had a problem with debugging on the single page. I’ve recently refactored so if a problem happens in one section of the page it’s easy to know which js file to look at (one js file per feature). It’s not perfect, mismatched line numbers are still an issue, but modules are very few lines of code so I’ve always found it easy to find the problem line (grep is useful too!). But I definitely see your point here and agree with you. I will consider moving to the two stage process to make the html/js/css dev aspects simpler.

I don’t think this tool will be as famous as the BIP39 tool. The reason is, bip39 was super useful when it came out. I’d been waiting a long time for it, had seen how good a feature like this would be from the earlier Armory Deterministic Wallets, and now with bip39 there would be a standard wallet format it was obvious to me everyone would want to move to it. The old bitcoin wallet format of 100 random keys with intermittent random update was too hard to use reliably, bip39 was going to be amazing. Thing is, BLS is not like that. SAFE manages the keys automatically. There’s not much introspection required. The offline signing and decrypting in the tool is useful perhaps, but that will change before SAFE release to allow hardware wallets to be supported. Key management via a bip32 hierarchy is not yet on offer in BLS (perhaps the simple threshold keys sort of offers it by being able to generate many child keys?). And the bip39 tool is mainly useful for exploring the hierarchy which is not needed in BLS. So… let’s see!

Thanks for looking into it, I’m really glad you were able to make changes relatively simply, that’s always a good sign!


version 0.1.5 is available. This has a new feature to create a Group Signature as well as a bunch of refactoring that isn’t visually noticeable but improves stuff behind the scenes.

Next and last feature to add is group decryption of messages.

Then after that some nice to haves

  • add compression to the wasm which shrinks the tool from 400KB to 100KB.
  • add more tests for the non-standard use cases
  • add a glossary and explainer section
  • add choice of encoding between hex/base32/base32z - maybe base64 but I’m hesitant due to double-click-then-copy-paste behavior can be easy to accidentally not select it all.