Skip to content

Instantly share code, notes, and snippets.

@yowmamasita
Created June 19, 2024 22:23
Show Gist options
  • Select an option

  • Save yowmamasita/6db7a6aff8a9287a3bc11b7b98a186fd to your computer and use it in GitHub Desktop.

Select an option

Save yowmamasita/6db7a6aff8a9287a3bc11b7b98a186fd to your computer and use it in GitHub Desktop.
Compute the lowest SHA hash https://shallenge.quirino.net/
package main
import (
"crypto/sha256"
"fmt"
"math"
"runtime"
"strings"
"sync"
"sync/atomic"
)
const username = "yowmamasita"
var base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
func generateNonces(length int, start, end int64, results chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
nonce := make([]byte, length)
for i := start; i < end; i++ {
for j := 0; j < length; j++ {
nonce[j] = base64Chars[(i/int64(math.Pow(64, float64(j))))%64]
}
results <- string(nonce)
}
}
func worker(id int, results <-chan string, newLowestHash chan<- string, currentLowestHash *atomic.Value, currentLowestZeroes *atomic.Int32, wg *sync.WaitGroup) {
defer wg.Done()
for nonce := range results {
fullString := username + "/" + nonce
hash := sha256.Sum256([]byte(fullString))
hashHex := fmt.Sprintf("%x", hash)
leadingZeroes := countLeadingZeroes(hashHex)
currentZeroes := currentLowestZeroes.Load()
if leadingZeroes > currentZeroes || (leadingZeroes == currentZeroes && isLower(hashHex, currentLowestHash.Load().(string))) {
currentLowestHash.Store(hashHex)
currentLowestZeroes.Store(leadingZeroes)
newLowestHash <- fmt.Sprintf("New lowest hash found by worker %d: %s (%s/%s) with %d leading zeroes", id, hashHex, username, nonce, leadingZeroes)
}
}
}
func isLower(hash1, hash2 string) bool {
for i := 0; i < len(hash1); i++ {
if hash1[i] < hash2[i] {
return true
} else if hash1[i] > hash2[i] {
return false
}
}
return false
}
func countLeadingZeroes(hash string) int32 {
leadingZeroes := int32(0)
for i := 0; i < len(hash); i++ {
if hash[i] == '0' {
leadingZeroes++
} else {
break
}
}
return leadingZeroes
}
func main() {
numCPU := runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
currentLowestHash := atomic.Value{}
currentLowestHash.Store(strings.Repeat("f", 64))
currentLowestZeroes := atomic.Int32{}
currentLowestZeroes.Store(0)
newLowestHash := make(chan string, numCPU)
results := make(chan string, 1000)
var wg sync.WaitGroup
for i := 0; i < numCPU; i++ {
wg.Add(1)
go worker(i, results, newLowestHash, &currentLowestHash, &currentLowestZeroes, &wg)
}
go func() {
for length := 1; length <= 64; length++ {
maxCount := int64(math.Pow(64, float64(length)))
chunkSize := maxCount / int64(numCPU)
for i := 0; i < numCPU; i++ {
start := int64(i) * chunkSize
end := start + chunkSize
if i == numCPU-1 {
end = maxCount
}
wg.Add(1)
go generateNonces(length, start, end, results, &wg)
}
}
wg.Wait()
close(results)
}()
go func() {
wg.Wait()
close(newLowestHash)
}()
for newHash := range newLowestHash {
fmt.Println(newHash)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment