EOSIO / eos

An open source smart contract platform
https://developers.eos.io/manuals/eos
MIT License
11.27k stars 3.76k forks source link

Remove canonical check from signature validation #6699

Open spoonincode opened 5 years ago

spoonincode commented 5 years ago

EOSIO uses ECDSA signatures over the secp256k1 ("k1") and secp256r1 ("r1") curves. Depending on how the signatures (consisting of two 32 byte bigints: r and s) are stored and depending on the value of s for a given signature it is possible for an entity who does not hold the private key to mutate an ECDSA signature and still have the signature be valid. This is sometimes referred to as “transaction malleability” on some other blockchains. On those blockchains the signature is part of the transaction uniqueness (the transaction “id”) leading to a potential attack where a transaction can be submitted to the chain a second time with a mutated, but still valid, signature by an entity who does not posses the private key.

EOSIO is not at risk to transaction malleability because signatures do not make up part of a transaction’s uniqueness. If an attacker takes an EOSIO transaction and mutates the ECDSA s value from a “high-s” to a “low-s”, the transaction id remains unchanged and the network will not accept the duplicate transaction.

Nevertheless, EOSIO imposes a “canonical” check of sorts on ECDSA signatures to protect against the non existent threat of transaction malleability. For r1 signatures the check is simply that a “low-s” value is used. This is a low overhead mutation: after a signature is created the signing code can take that signature and mutate a high-s to a low-s without performing another signature. The k1 code is significantly more obtuse though. There are canonical rules in place that require potentially performing a full signature multiple times until meeting certain criteria imposed on the r and s values.

These canonical checks make it difficult to perform ECDSA signatures on the k1 curve via some hardware solutions because doing multiple signatures may require the user to press a button multiple times on the hardware device. Hardware signatures are often slow too, meaning it could take over a half second to perform the multiple signatures needed. These limitations mean that r1 will have to be used in more cases than otherwise would be required. r1 is more taxing on the network to validate compared to k1 and thus it would be healthier for the network to use k1 whenever possible.

There is also a performance impact of needing to sign multiple times even for k1 signatures on a PC. For example, on my development box signing takes 45us. Over a random sample of 74000 “eosio canonical” signatures the number of times a signature is performed internally was:

Signatures n
1 36556
2 18432
3 9410
4 4833
5 2368
6 1156
7 610
8 303
9 180
10 64
11 44
12 21
13 9
14 7
15 3
16 0
17 1
18 2

This means on average over two times more signatures are made than strictly required. In some outliers a signature needed to be iterated so many times that it took over 700us to sign! This is particularly high overhead for a block signature.

aclark-b1 commented 4 years ago

In order to focus our efforts on issues that are currently creating difficulty for the community we are closing tickets that were created prior to the EOSIO 2.0 release. If you believe this issue is still relevant please feel free to reopen it or create a new one. Thank you for your continued support of EOSIO!