BLS "Malleability" PoC Description
Problem 1: BLS signature validation in lotus uses blst
library method VerifyCompressed
. This method accepts signatures in 2 forms: "serialized", and "compressed", meaning that BLS signatures can be provided as either of 2 unique byte arrays.
- (Link -
VerifyCompressed
): SeeAggregateVerifyCompressed
, which accepts both signatures and public keys in serialized and compressed forms. - (Link -
blsSigner.Verify
): InvokesVerifyCompressed
Problem 2: Lotus block validation functions perform a uniqueness check on provided blocks. Two blocks are considered distinct if the CIDs of their blockheader do not match. The CID method for blockheader includes the BlockSig
of the block.
- (Link -
BlockHeader.ToStorageBlock
): Serializes the blockheader withBlockSig
included
As a result: Two blocks that are identical in every way (except that one uses a "serialized" BlockSig
and the other "compressed"), will be considered distinct blocks. These problems occur in at least 3 locations in lotus code:
/chain/sync.go::ValidateBlock
:/chain/vm/syscalls.go::VerifyConsensusFault
:/chain/sub/incoming.go::Validate
:
Remediation: Blocks should be checked for uniqueness without the inclusion of the BlockSig
.
Notes: The code below is a POC that VerifyCompressed
will accept signatures when provided in both forms: "serialized" and "compressed". The console output of the POC follows:
Verifying signature...
P2Affine.Verify: Valid!
================
Serialized: 04f423a63f915e347f19ef629741251e26518ced0a14d5130ed8760e0bf91c72f085ba6b984f15ef7f7ea9d3421fd4a910d40ec76a3a31452574234ed00039e55a01f4994328604ae60134b6854b2a5082810e1a676826de5c8babf057ceb8421915f1fd5cdb1cd38de7a9016c0e5eeeb29ac0d3c29a128476258cf39e0ce04d1bff8f02984c79eb57bebe75a73a66a813fec8d09868929e5bfe9f55d3185abcb74337a11868577071420e7cede325c0c75ca0ba90aeb8040e0e4eecacb21143
(len: 192)
================
Compressed: a4f423a63f915e347f19ef629741251e26518ced0a14d5130ed8760e0bf91c72f085ba6b984f15ef7f7ea9d3421fd4a910d40ec76a3a31452574234ed00039e55a01f4994328604ae60134b6854b2a5082810e1a676826de5c8babf057ceb842
(len: 96)
================
VerifyCompressed(sigSerialized, pkSerialized): Valid!
VerifyCompressed(sigSerialized, pkCompressed): Valid!
VerifyCompressed(sigCompressed, pkSerialized): Valid!
VerifyCompressed(sigCompressed, pkCompressed): Valid!