implement basic hashcash-like proof of work
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
_ "crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g := Generator{
|
||||
Difficulty: 26,
|
||||
}
|
||||
c := g.RandomChallenge()
|
||||
fmt.Println(c.String())
|
||||
fmt.Println(c.Solve().String())
|
||||
}
|
||||
|
||||
type Challenge struct {
|
||||
Input [48]byte
|
||||
Date [20]byte
|
||||
Difficulty byte
|
||||
Solution int64
|
||||
}
|
||||
type Generator struct {
|
||||
Difficulty byte
|
||||
}
|
||||
|
||||
func (g *Generator) RandomChallenge() Challenge {
|
||||
bytes := make([]byte, 48)
|
||||
for i, _ := range bytes {
|
||||
bytes[i] = byte(rand.Int())
|
||||
}
|
||||
today := time.Now().UTC()
|
||||
date := today.Format("2006-01-02")
|
||||
hash := crypto.SHA1.New().Sum([]byte(date))
|
||||
return Challenge{
|
||||
Input: [48]byte(bytes),
|
||||
Date: [20]byte(hash),
|
||||
Difficulty: g.Difficulty,
|
||||
}
|
||||
}
|
||||
|
||||
// using a lookup table for this is super goofy but i'm lazy and it's 6am
|
||||
var prefixLookup = []int{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
|
||||
func (c Challenge) Solve() Challenge {
|
||||
bytes := make([]byte, 76)
|
||||
bytes = append(bytes, c.Input[:]...)
|
||||
bytes = append(bytes, c.Date[:]...)
|
||||
for {
|
||||
for i := range 8 {
|
||||
bytes[75-i] = byte(c.Solution >> (i * 8))
|
||||
}
|
||||
sum := make([]byte, 20)
|
||||
hash := crypto.SHA1.New()
|
||||
hash.Write(bytes)
|
||||
sum = hash.Sum(nil)
|
||||
count := 0
|
||||
for _, c := range sum {
|
||||
p := prefixLookup[c]
|
||||
count += p
|
||||
if p != 8 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if c.Solution%20000000 == 0 {
|
||||
println(c.Solution)
|
||||
}
|
||||
if count >= int(c.Difficulty) {
|
||||
println(c.Solution)
|
||||
break
|
||||
}
|
||||
c.Solution++
|
||||
}
|
||||
return c
|
||||
}
|
||||
func (c Challenge) String() string {
|
||||
bytes := make([]byte, 0)
|
||||
bytes = append(bytes, c.Input[:]...)
|
||||
bytes = append(bytes, c.Date[:]...)
|
||||
bytes = append(bytes, make([]byte, 8)...)
|
||||
bytes[68] = c.Difficulty
|
||||
for i := range 7 {
|
||||
bytes[75-i] = byte(c.Solution >> (i * 8))
|
||||
}
|
||||
return hex.EncodeToString(bytes)
|
||||
}
|
||||
Reference in New Issue
Block a user