package core import ( "bytes" "crypto/sha256" "encoding/binary" "encoding/hex" ) // Hash is the type for a hash data packet type Hash [32]byte // IsZero returns true if the Hash is empty (all zeroes) func (h *Hash) IsZero() bool { z := Hash{} if bytes.Equal(z[:], h[:]) { return true } return false } func (h *Hash) String() string { return hex.EncodeToString(h[:]) } // HashBytes performs a hash over a given byte array func HashBytes(b []byte) Hash { h := sha256.Sum256(b) return h } // PoWData is the interface for the data that have the Nonce parameter to calculate the Proof-of-Work type PoWData interface { Bytes() []byte GetNonce() uint64 IncrementNonce() } // CheckPoW verifies the PoW difficulty of a Hash func CheckPoW(hash Hash, difficulty uint64) bool { var empty [32]byte if !bytes.Equal(hash[:][0:difficulty], empty[0:difficulty]) { return false } return true } // CalculatePoW calculates the nonce for the given data in order to fit in the current Proof of Work difficulty func CalculatePoW(data PoWData, difficulty uint64) (uint64, error) { hash := HashBytes(data.Bytes()) for !CheckPoW(hash, difficulty) { data.IncrementNonce() hash = HashBytes(data.Bytes()) } return data.GetNonce(), nil } func Uint64ToBytes(u uint64) []byte { buff := new(bytes.Buffer) err := binary.Write(buff, binary.LittleEndian, u) if err != nil { panic(err) } return buff.Bytes() } func Uint64FromBytes(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }