Swap Nonce and Graffiti Header Positions

Background

Currently most mining software uses the graffiti field as a nonce when mining Iron Fish blocks. The block header is serialized as follows before being passed to the blake3 hashing algorithm.

writeBigU64BE(header.randomness)         //  8
writeU32(header.sequence)                //  4
writeHash(header.previousBlockHash)      // 32
writeHash(header.noteCommitment)         // 32
writeHash(header.transactionCommitment)  // 32
writeBigU256BE(header.target.asBigInt()) // 32
writeU64(header.timestamp.getTime())     //  8
writeBytes(header.graffiti)              // 32

We can see the randomness field (the intended nonce) is at the beginning of the serialized bytes while graffiti is at the end. Because blake3 hashes data in chunks it is prone to ‘mid-state’ optimization. If the beginning portions of the data are kept constant while the end of the data changes, the intermediate result of hashing the beginning can be re-used for multiple hashes. Because randomness is in the initial bytes and graffiti is in the final bytes it is optimal to keep the randomness constant while changing the graffiti over and over again to mine. This leads the graffiti fields being unrecognizable in their ASCI form and essentially random bytes which was not the original intent of the field. Sha-3 in Bitcoin is succeptible to this as well as described further in this post.

Proposal

With the switch to the FishHash algorithm for mining the order in which these two fields appear can also easily be changed. Moving the graffiti to the front and randomness to the end will allow using randomness as the nonce to be more optimal than graffiti and the graffiti can be used for its intended purpose. The new serialization before passing to the FishHash function would be

writeBytes(header.graffiti)              // 32
writeU32(header.sequence)                //  4
writeHash(header.previousBlockHash)      // 32
writeHash(header.noteCommitment)         // 32
writeHash(header.transactionCommitment)  // 32
writeBigU256BE(header.target.asBigInt()) // 32
writeU64(header.timestamp.getTime())     //  8
writeBigU64BE(header.randomness)         //  8

Makes sense, we can get graffiti back with this change.