async function sha256(message) {
// encode as UTF-8
const msgBuffer = new TextEncoder("utf-8").encode(message)
// hash the message
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer)
// convert ArrayBuffer to Array
const hashArray = Array.from(new Uint8Array(hashBuffer))
// convert bytes to hex string
const hashHex = hashArray
.map((b) => ("00" + b.toString(16)).slice(-2))
.join("")
return hashHex
}
const { useState, unstable_useTransition: useTransition, useCallback, useRef } = React
const timeFormatter = new Intl.NumberFormat('en-US', { maximumSignificantDigits: 3 })
const hashRateFormatter = new Intl.NumberFormat('en-US', { maximumSignificantDigits: 4 })
const addToAverage = (currentAverage, newValue, nthValue) => {
return (currentAverage * ((nthValue - 1) / nthValue)) + (newValue * (1 / nthValue))
}
const Component = () => {
const [input, setInput] = useState("")
const [output, setOutput] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
const [smallestHash, setSmallestHash] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
const [hashingTime, setHashingTime] = useState(0)
const [averageHashingTime, setAverageHashingTime] = useState(0)
const hashes = useRef(new Set(["e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"]))
const [startTransition, isPending] = useTransition({ timeoutMs: 5000 })
const onChange = useCallback(e => {
const value = e.target.value
setInput(value)
startTransition(() => {
const t0 = performance.now()
sha256(value).then(result => {
const t1 = performance.now()
setSmallestHash(currentSmallest => parseInt(result, 16) < parseInt(currentSmallest, 16) ? result : currentSmallest)
setOutput(result)
setHashingTime(t1-t0)
let countAverage = !hashes.current.has(result)
hashes.current.add(result)
if (countAverage) {
setAverageHashingTime(current => addToAverage(current, t1-t0, hashes.current.size))
}
})
})
})
return (
<>
<label className="font-semibold">Pretend Block Data</label>
<textarea className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 mb-4 font-mono placeholder-gray-500" value={input} onChange={onChange} placeholder="Type anything in here" />
<div className="flex justify-between">
<label className="font-semibold">SHA-256 Output</label>
<p className="font-mono text-sm text-gray-500">{hashes.current.size} {hashes.current.size == 1 ? 'hash' : 'hashes'}</p>
</div>
<div className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 font-mono text-sm break-all">
{output}
</div>
<div className="flex justify-between mb-4">
<div className="font-mono text-sm text-gray-500">
Computed in {timeFormatter.format(hashingTime)} ms
</div>
<div className="font-mono text-sm text-gray-500 hidden">
Hash Rate: {hashRateFormatter.format(1000 / averageHashingTime)} hashes / sec
</div>
</div>
<p className="mb-4">Try to see how small of an output you can find. See if you can find an output that starts with <code className="border-gray-300 border-solid border bg-gray-200 rounded p-1 font-mono text-sm">00</code></p>
<label className="font-semibold">Smallest Output Found</label>
<div className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 font-mono text-sm break-all">
{smallestHash}
</div>
</>
)
}
ReactDOM.unstable_createRoot(document.getElementById("root")).render(<Component />)
View Compiled