Skip to content

Instantly share code, notes, and snippets.

@zillwc
Last active June 7, 2019 17:54
Show Gist options
  • Select an option

  • Save zillwc/60df091803ebd3fe5c9deed3d87b2cfe to your computer and use it in GitHub Desktop.

Select an option

Save zillwc/60df091803ebd3fe5c9deed3d87b2cfe to your computer and use it in GitHub Desktop.
Computes proof of work for variable length md5 prefix match
/*
MD5 Prefix Proof of Work
Computes proof of work for variable length md5 prefix match
Charset: a-zA-Z
Usage:
$. go run md5_prefix_proof_of_work.go <MD5 Prefix>
Examples:
$ go run md5_prefix_proof_of_work.go af232 // mUOtbyGE
$ go run md5_prefix_proof_of_work.go 38ad22 // C0dutV6A
Note: most runs take ~5 seconds to run; absolutely worst case: ~20 seconds
Zillwc
*/
package main
import (
"fmt"
"os"
"crypto/md5"
"math/rand"
"time"
"encoding/hex"
"strings"
)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
func generateRandomCode(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func main() {
rand.Seed(time.Now().UnixNano())
prefix := os.Args[1]
for {
code := generateRandomCode(8)
hash := md5.New()
hash.Write([]byte(code))
hashString := hex.EncodeToString(hash.Sum(nil))
if strings.HasPrefix(hashString, prefix){
fmt.Printf("%s\n", code)
break
}
}
}
@OmarDarwish
Copy link

OmarDarwish commented Jun 3, 2019

parallelized:

func main() {
  rand.Seed(time.Now().UnixNano())
  prefix := os.Args[1]

  found := false
  limit := 30
  semaphore := make(chan bool, limit)

  for !found {
    // wait if we've hit limit
    semaphore <- true

    go func() {
      // release lock at the end
      defer func(){
        <-semaphore
      }()

      attempt := generateRandomCode(8)
      hash := md5.New()
      hash.Write([]byte(attempt))
      hashString := hex.EncodeToString(hash.Sum(nil))

      if strings.HasPrefix(hashString, prefix){
        fmt.Printf("%s\n",attempt)
        found = true
      }
    }()
  }
}

@OmarDarwish
Copy link

maybe you can take the parallelization limit as a command line arg

@zillwc
Copy link
Author

zillwc commented Jun 7, 2019

As discussed on slack, the parallelized version is slower :/
Attaching full parallelized version for posterity:

package main

import (
  "fmt"
  "os"
  "crypto/md5"
  "math/rand"
  "time"
  "encoding/hex"
  "strings"
)

var prefix = os.Args[1]
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

func generateRandomCode(n int) string {
  b := make([]rune, n)
  for i := range b {
    b[i] = letters[rand.Intn(len(letters))]
  }

  return string(b)
}

func main() {
  rand.Seed(time.Now().UnixNano())
  prefix := os.Args[1]

  found := false
  limit := 1000
  semaphore := make(chan bool, limit)

  for !found {
    semaphore <- true

    go func() {
      defer func(){
        <-semaphore
      }()

      attempt := generateRandomCode(8)
      hash := md5.New()
      hash.Write([]byte(attempt))
      hashString := hex.EncodeToString(hash.Sum(nil))

      if strings.HasPrefix(hashString, prefix){
        fmt.Printf("%s\n",attempt)
        found = true
      }
    }()
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment