Inviting Python HIVE devs to play around with spqsigs: Experimental hash-based signatures for a post-quantum HIVE ecosystem.

In preparation for work on this proposal, I wrote two blog posts on hash-based signatures. One on One Time Signatures and one on the creation and use of multi-use hash-based signing keys. These post had some sample Python code in them, and as not to let the work I did on these blog posts go to waste, I cleaned up the blog-post code, added a few features for performance (multi-processing) and better security (salts), and leveraged the features of the BLAKE2b hashing algoritm.

I pushed the code to github and pypi. Note this library is not one of the higher level the library of the actual proposal, but it is a candidate for the lower level implementation of hash-based signatures for HIVE. I'm going to write an equivalent and 100% format-compatible C++ library next, to together with the Python version should form the foundation for the higher level libraries.

If you've worked on software projects for HIVE, you will have used HIVE's ECDSA siging-keys. As you may know, ECDSA is (or rather will be) vulnerable to reversing the signing key from a public key or signed transaction using a modified SHOR's algorithm for solving the discrete logarithm problem on elliptic curves.

Hash-based signatures aren't. But usage and properties of hash-based signatures are quite a bit different from usage and properties of ECDSA signatures. You can read more about this in different posts I wrote in the HIVE Quantum Resistance Community. I won't rehash everything, but to sum it up quickly:

  • Hash-based signatures are big. They can even be huge.
  • Hash-based signing keys are a depletable resource. You can only sign som N messages or transactions before your key (from a security perspective) becomes useless.
  • There are trade-offs between performance (mainly of key creation, but also of signing and validation) and signature size.

With this post I want to ask you, the HIVE development community to play around with hash-based signatures a bit, do so using my (currently alpha grade) python library, and get a feel of how hash-based signatures work. I need you guys onboard for my proposal. Quantum computing keeps moving forward, getting stronger, getting bigger, and it will be a few years (at least) before one of the big players has a quantum computer big enough (somewhere around 1500 qubits) general purpose quantum computer to potentially disrupt a blockchain like HIVE, there still is a lot of work to be done. Work that could start here, but work also that will need many of you guys onboard, integrating hash-based signatures through all layers of the HIVE ecosystem. Work also including a well thought out roadmap that implements things like market separation of quantum secure vs quantum insecure holdings, etc, etc.

Work that could start with you guys taking an our with spqsigs just to get a first feel of the subject.

pip install

So here we go. Install spqsigs using pip:

python3 -m pip install spqsigs

importing

Next, import the two classes SigningKey and Validator

from spqsigs import SigningKey,  Validator

Creating a new key

Creating a new key can take a while depending on the parameters. The parameters for new key creation are:

  • hashlen: The number of bytes to use as digest length dor BLAKE2b. This defaults to 24 bytes.
  • wotsbits: The number of bits to sign with one set of WOTS chains. Note that each bit makes signing key generation a factor of two slower. This value defaults to 12 bit.
  • merkledepth: The depth (or height) of the top level merkle tree. You can sign two to the power depth messages with a single signing key before it depletes. Adding one level to the depth doubles both the number of messages you can sign with a single key and the amount of time to generate a signing key.
  • multiproc: The number of processes to use during signing key generation. This defaults to 8.

You can create a quick and insecure signing key that can sign only a few dozen messages, where creation doesn't need multi processing to have acceptable performance:

sigkey = SigningKey(hashlen=10, wotsbits=4, merkledepth=5, multiproc=1)

Or you can create a secure signing key that takes half an hour or more to create, even with multi processing, and allows you to sign many thousands of messages.

sigkey = SigningKey(hashlen=24, wotsbits=12, merkledepth=16, multiproc=8)

It is suggested when experimenting you use lower numbers for merkledepth. This will make your key deplete quickly, but will make it possible to experiment with the hashlength and wotsbits parameters a bit.

sigkey = SigningKey(hashlen=24, wotsbits=12, merkledepth=3, multiproc=8)

If you don't mind waiting for a long time for higher numbers for merkledepth, use the backup possibility below.

Backing up the signing-key

If it took you half an hour to create a key, you may want to back it up, even if just for experimenting. In a real life situation you will need to back it up, because as we said a signing key is a depletable resource, and we need to (somewhere) keep track of just how depleted the resource is. Please note that the below way of backup is insecure and not meant for production use. This functionality will be higher-level library functionality.

import json

...

with open("signkey_state.json", "w") as outfil:
    json.dump(sigkey.get_state(), outfile)

And to restore a signing key from such backup:

with open("signkey_state.json") as infil:
    oldstate = json.load(infil)
sigkey = SigningKey(restore=oldstate)

If you created the many-usage secure signing key in half an hour, restoring it should take much less time.

signing a message

Signing a message is real simple:

message = b"This is a message"
signature = sigkey.sign_message(message)

Please try out printing out the signatures made with a SigningKey using different creation settings.

print(signature.hex().upper())

Notice how large the signature is?

Validating the message.

In order to validate a signature, you first need to instantiate a Validator. You MUST do this using the exact same values for hashlengt, wotsbits and merkledepth.

validate = Validator(hashlen=24, wotsbits=12, merkledepth=10)

Now we can invoke the validator. Note that invoking the validator returns three values:

  • A boolean indicating validation succeeded or failed
  • The (binary) public key of the signing key used in signing.
  • The index used for signing. This index starts at 0 for the first message signed and ends at two to the power merkledepth minus one for the signature that depletes the signing key.
ok, pubkey, index = validate(message, signature)
print(ok, index, pubkey.hex().upper())

Feedback and proposal support are welcome

Please play around with the above library. As a dev, get a feel for hash based signatures. In th e future HIVE will need them and your part of the HIVE ecosystem will need your help to make HIVE post-quantum ready before the first effective post-quantum hour.

If you realize making HIVE post-quantum ready is important. Then please:

  • Play around with this library, get a feel for hash-based signatures
  • Join and weigh in with blog-posts in the HIVE Quantum Resistance Community
  • Support my proposal if you haven't already.
  • Think about and write your own post-quantum proposal.

image.png

H2
H3
H4
3 columns
2 columns
1 column
1 Comment
Ecency