Clarify if we want to prehash before signing messages
See original GitHub issueNOTE This issue is not to do any coding, but just make a decision on our architecture
The original golang code uses https://godoc.org/golang.org/x/crypto/ed25519 which will produce the ed25519 signature of whatever we enter it. There is no prehashing here.
Every ledger code I have seen does prehashing on the transaction before signing. I am not sure if this is required, or just a convention. Maybe @rudi-cilibrasi knows better.
I did a little investigation and it seems there is a prehash step (using keccack) in ethereum as well:
- https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
- https://github.com/ethereumjs/ethereumjs-util/blob/master/index.js#L358-L385
When I worked on the first demo ledger app for cosmos, we had to use some flag to specify:
- this public key is in software, verify signature against full sign bytes
- this public key is in ledger, verify signature against sha256(sign bytes)
Needless to say this was clunky and didn’t seem right. Let’s discuss if we will need this prehashing step, and if so, consider doing it everywhere. This will update the signing algorithm used in weave
, weave-js
and in web4/@iov-keycontrol
. We can pass the unhashed sign bytes to the keyring entries so they can verify the content (eg. ledger app), but then hash before signing them.
I would like some feedback here, especially anyone who has dealt with this issue before.
Issue Analytics
- State:
- Created 5 years ago
- Comments:16 (16 by maintainers)
Top GitHub Comments
According to https://tools.ietf.org/html/rfc8032#section-4,
Ed25519
is a PureEdDSA variant, which means that the pre-hash function is the identity (i.e. no prehashing).However, part of Ed25519 is the ability to handle arbitrary sized input messags (
M
) because of an internal SHA512 step: https://tools.ietf.org/html/rfc8032#section-5.1.6Given that, I think we can consider
Ed25519
to be a signing mechanism that consumes plain messagesM
or prehashed messagesPH(M)
. In this case, having an optional prehashing step makes sense.The situation is different for Secp256k1, where the signing algorithm itself truncates input to be smaller than N (256bit). This must never happen on unprehashed messages.
“passing full sign bytes into libsodium” means libsodium does the prehashing for you because the API is designed like that: https://github.com/jedisct1/libsodium/blob/569778b517496861a3880e0e690973bf08a52e08/src/libsodium/crypto_sign/ed25519/ref10/sign.c#L65 You cannot use arbitrary length input data with elliptic curves so the hashing is done somewhere.
~I guess libsodium’s crypto_sign is implemented as
Ed25519(SHA512(m))
but I’ll verify that.~