Use pre-hashing for signatures


In this thread, I want to propose a LIP for the roadmap objective “Allow for memory-efficient signing”. The proposal’s main contribution is to introduce a pre-hashing step in the signing process.

I’m looking forward to your feedback.

Here is a complete LIP draft:

LIP: <LIP number>
Title: Use pre-hashing for signatures
Author: Maxime Gagnebin <>
Type: Standards Track
Created: <YYYY-MM-DD>
Updated: <YYYY-MM-DD>
Requires: 0037


This LIP introduces pre-hashing for signatures in Lisk, this includes transactions, block headers and certificate signatures. This allows signing to be performed on memory limited devices such as hardware wallets.


This LIP is licensed under the Creative Commons Zero 1.0 Universal.


Introducing memory efficient signing allows all objects used in the Lisk protocol to be signed on devices with limited memory. Most of the current transactions have a small size and can be signed on existing devices. However, new transactions implemented in the interoperability module, or transactions implemented in decentralized applications are likely to be too large to be signed directly on such devices. This argument was overlooked in the past which led to the pre-hashing step being removed in LIP 0008.

With the current proposal, signatures are computed against the hash of the message to be signed and hence always computed for a byte string of small constant size.


Choice of Hash Function

Hashing before signing is a common practice and different protocols use different hash functions for this task. For the Lisk protocol, the natural choice of hash function is SHA-256. This function is used in multiple other parts of the protocol and hence it makes sense to not expose the protocol to another hash function.

Introduction of another hash function to the Lisk protocol was suggested in LIP 0010, but was later withdrawn as SHA-256 is widely used and can be considered secure.

On Removing Pre-hashing in LIP 0008

LIP 0008 removed the pre-hashing step from the Lisk signing protocol. This was mainly done as this step was deemed unnecessary and removing it could improve the theoretical security of the signing process. However this is not reflected by a practical improvement in protocol security as the SHA-256 hash function is considered collision resistant and secure. This hash function is used in several critical parts of many applications, including Lisk, and any future findings that SHA-256 is insecure would require changing the protocol throughout.


The signature for a binary message message and a secret key sk is generated by signMessage(sk, tag, networkIdentifier, message) as defined below. tag must be the correct message tag for message as defined in LIP 0037, and networkIdentifier the correct network identifier for the chain. The resulting signature signature in combination with the message message and the matching public key pk is verified by verifyMessageSig(pk, tag, networkIdentifier, message, signature).

signMessage(sk, tag, networkIdentifier, message):
    taggedMessage = tag || networkIdentifier || message
    hashedMessage = hash(taggedMessage)
    return Sign(sk, hashedMessage)

verifyMessageSig(pk, tag, networkIdentifier, message, signature):
    taggedMessage = tag || networkIdentifier || message
    hashedMessage = hash(taggedMessage)
    return Verify(pk, hashedMessage, signature)

Where hash is the SHA-256 hash digest of the input, and the functions Sign and Verify are the signing and verifying functions of the respective signature scheme.

Signing and Verifying with Ed25519

For the Ed25519 signature scheme, Sign and Verify are the signing and verifying functions as specified in RFC 8032.

The signMessage and verifyMessageSig functions defined in LIP 0037 are superseded by the functions defined in this LIP.

Signing and Verifying with BLS

For the BLS signature scheme used in Lisk, Sign (identical to CoreSign) and Verify (identical to CoreVerify) are the signing and verifying functions as specified in BLS Signatures draft-irtf-cfrg-bls-signature-04.

The signBLS and verifyBLS functions defined in LIP 0038 are superseded by the functions defined in this LIP.

Reference Implementation


Backwards Compatibility

This LIP results in a hard fork as nodes following the proposed protocol will reject signatures according to the previous protocol, and nodes following the previous protocol will reject signatures according to the proposed protocol.

I opened a pull request for this proposal: Add LIP "Use pre-hashing for signatures" by MaximeGagnebin · Pull Request #135 · LiskHQ/lips · GitHub