proof-of-work-solver/solver.go

108 lines
22 KiB
Go

package main
import (
"bufio"
"fmt"
"math"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
)
func checkUtility(utility string) {
if _, err := exec.LookPath(utility); err != nil {
fmt.Printf("%s is not installed. Please install it and try again.\n", utility)
os.Exit(1)
}
}
func main() {
requiredUtils := []string{"argon2", "xxd", "bc"}
for _, utils := range requiredUtils {
checkUtility(utils)
}
var challenge string
if len(os.Args) < 2 {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Challenge Code: ")
challenge, _ = reader.ReadString('\n')
challenge = strings.TrimSpace(challenge)
} else {
challenge = strings.TrimSpace(os.Args[1])
}
// Validate the challenge format
matched, _ := regexp.MatchString(`^([0-9]+):([0-9]+):([A-Za-z0-9]+):([0-9]+)$`, challenge)
if !matched {
fmt.Println("Invalid challenge format. Expected format: memory_cost:time_cost:salt:difficulty")
os.Exit(2)
}
// Parse challenge code
parts := strings.Split(challenge, ":")
memoryCost := parts[0]
timeCost := parts[1]
salt := parts[2]
difficulty := parts[3]
// Debugging output
fmt.Printf("Memory Cost: %s\n", memoryCost)
fmt.Printf("Time Cost: %s\n", timeCost)
fmt.Printf("Salt: %s\n", salt)
fmt.Printf("Difficulty: %s\n", difficulty)
// Generate prefix for the password
pwPrefix := fmt.Sprintf("UNBLOCK-%s-", randomString(8))
difficultyRaw := int(math.Exp(math.Log(256) * (4 - math.Log(float64(parseInt(difficulty))) / math.Log(256))))
fmt.Printf("Estimated iterations: %s\n", difficulty)
fmt.Printf("Time Cost: %s\n\n", timeCost)
n := 1
startTime := time.Now()
// Main loop to find the solution
for {
pw := fmt.Sprintf("%s%d", pwPrefix, n)
cmd := exec.Command("bash", "-c", fmt.Sprintf("echo -n '%s' | argon2 %s -t %s -k %s -p 1 -id -v 13 -r", pw, salt, timeCost, memoryCost))
hashResult, err := cmd.Output()
if err != nil {
fmt.Println("Error executing argon2:", err)
return
}
hashBytes := string(hashResult)
hashSlice := strings.Split(hashBytes, "$")
hashHex := hashSlice[3][:8]
if parseInt(hashHex) < difficultyRaw {
fmt.Printf("\nSOLUTION FOUND\n")
fmt.Printf("Your unblock code is: %s\n", pw)
fmt.Println("This is the code you enter into the site to pass the challenge.\n")
break
} else {
elapsedTime := time.Since(startTime).Seconds()
fmt.Printf("\rElapsed Time: %.0f seconds.", elapsedTime)
n++
}
}
}
func randomString(length int) string {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
func parseInt(s string) int {
i, _ := strconv.ParseInt(s, 16, 0)
return int(i)
}