Finality provider BTC private key used as HMAC key for generating nonces
Description
In GenerateRandomness
, nonces are generated as the HMAC-SHA256 of the chainID
and the block height that the nonce is for, keyed by the finality provider's private key:
func GenerateRandomness(key []byte, chainID []byte, height uint64) (*eots.PrivateRand, *eots.PublicRand) {
// calculate the randomn hash of the key concatenated with chainID and height
digest := hmac.New(sha256.New, key)
digest.Write(append(sdk.Uint64ToBigEndian(height), chainID...))
randPre := digest.Sum(nil)
// ...
}
func (lm *LocalEOTSManager) getRandomnessPair(fpPk []byte, chainID []byte, height uint64, passphrase string) (*eots.PrivateRand, *eots.PublicRand, error) {
record, err := lm.KeyRecord(fpPk, passphrase)
if err != nil {
return nil, nil, err
}
privRand, pubRand := randgenerator.GenerateRandomness(record.PrivKey.Serialize(), chainID, height)
return privRand, pubRand, nil
}
Impact
Since the finality provider's private key is revealed upon slashing, this allows other parties to rederive the nonces for finality-provider votes, allowing them to sign messages with the same nonces that were committed to previously, which is more flexibility than is needed to carry out slashing.
Recommendations
Since currently all the randomness is stored in the finality provider's database, true randomness could be committed to and stored instead. If preserving the ability to regenerate the nonces from a constant amount of space is desired, use a separate uniformly-generated key for the HMAC-SHA256 key.