Compare commits
No commits in common. "master" and "v1.0.0" have entirely different histories.
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,3 @@
|
|||||||
cmd/hashcash/hashcash
|
|
||||||
|
|
||||||
# ---> Go
|
# ---> Go
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
|
|||||||
37
README.md
37
README.md
@ -4,39 +4,4 @@ HTTP Hashcash implemented in Go.
|
|||||||
|
|
||||||
Explanation at https://therootcompany.com/blog/http-hashcash/
|
Explanation at https://therootcompany.com/blog/http-hashcash/
|
||||||
|
|
||||||
Go API docs at https://pkg.go.dev/git.rootprojects.org/root/hashcash?tab=doc
|
Go docs at https://godoc.org/git.rootprojects.org/root/hashcash
|
||||||
|
|
||||||
# CLI Usage
|
|
||||||
|
|
||||||
Install:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get git.rootprojects.org/root/hashcash/cmd/hashcash
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
```txt
|
|
||||||
Usage:
|
|
||||||
hashcash new [subject *] [expires in 5m] [difficulty 10]
|
|
||||||
hashcash parse <hashcash>
|
|
||||||
hashcash solve <hashcash>
|
|
||||||
hashcash hash <hashcash>
|
|
||||||
hashcash verify <hashcash> [subject *]
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
my_hc=$(hashcash new)
|
|
||||||
echo New: $my_hc
|
|
||||||
hashcash parse "$my_hc"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
my_hc=$(hashcash solve "$my_hc")
|
|
||||||
echo Solved: $my_hc
|
|
||||||
hashcash parse "$my_hc"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
hashcash verify "$my_hc"
|
|
||||||
```
|
|
||||||
|
|||||||
@ -1,162 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.rootprojects.org/root/hashcash"
|
|
||||||
)
|
|
||||||
|
|
||||||
func help() {
|
|
||||||
fmt.Println("Usage:")
|
|
||||||
fmt.Println("\thashcash new [subject *] [difficulty 10] [expires in 5m]")
|
|
||||||
fmt.Println("\thashcash parse <hashcash>")
|
|
||||||
fmt.Println("\thashcash solve <hashcash>")
|
|
||||||
fmt.Println("\thashcash hash <hashcash>")
|
|
||||||
fmt.Println("\thashcash verify <hashcash> [subject *]")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
args := os.Args[:]
|
|
||||||
nargs := len(args)
|
|
||||||
|
|
||||||
if nargs < 2 {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch args[1] {
|
|
||||||
case "new":
|
|
||||||
var subject string
|
|
||||||
if nargs >= 3 {
|
|
||||||
subject = args[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
var difficulty int
|
|
||||||
if nargs >= 4 {
|
|
||||||
var err error
|
|
||||||
difficulty, err = strconv.Atoi(args[3])
|
|
||||||
if nil != err {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var expIn time.Duration
|
|
||||||
if nargs >= 5 {
|
|
||||||
var err error
|
|
||||||
expIn, err = time.ParseDuration(args[4])
|
|
||||||
if nil != err {
|
|
||||||
fmt.Println(err)
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expIn = 5 * time.Minute
|
|
||||||
}
|
|
||||||
|
|
||||||
h := hashcash.New(hashcash.Hashcash{
|
|
||||||
Subject: subject,
|
|
||||||
Difficulty: difficulty,
|
|
||||||
ExpiresAt: time.Now().Add(expIn),
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println(h.String())
|
|
||||||
return
|
|
||||||
case "parse":
|
|
||||||
var token string
|
|
||||||
if 3 != nargs {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
token = args[2]
|
|
||||||
h, err := hashcash.Parse(token)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b, _ := json.MarshalIndent(h, "", " ")
|
|
||||||
fmt.Println(string(b))
|
|
||||||
return
|
|
||||||
case "solve":
|
|
||||||
var token string
|
|
||||||
if 3 != nargs {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
token = args[2]
|
|
||||||
h, err := hashcash.Parse(token)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = h.Solve(22)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(h.String())
|
|
||||||
return
|
|
||||||
case "hash":
|
|
||||||
var token string
|
|
||||||
if 3 != nargs {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
token = args[2]
|
|
||||||
hash := sha256.Sum256([]byte(token))
|
|
||||||
fmt.Println(hex.EncodeToString(hash[:]))
|
|
||||||
return
|
|
||||||
case "verify":
|
|
||||||
var token string
|
|
||||||
if nargs < 3 {
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
token = args[2]
|
|
||||||
h, err := hashcash.Parse(token)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
subject := "*"
|
|
||||||
if nargs >= 4 {
|
|
||||||
subject = args[3]
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.Verify(subject)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var duration string
|
|
||||||
dur := h.ExpiresAt.Sub(time.Now())
|
|
||||||
if dur > 365*24*time.Hour {
|
|
||||||
duration = "...a long, long time"
|
|
||||||
} else {
|
|
||||||
duration = dur.Truncate(time.Second).String()
|
|
||||||
}
|
|
||||||
fmt.Println("valid for", duration)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
help()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
hashcash.go
13
hashcash.go
@ -216,10 +216,6 @@ func (h *Hashcash) Verify(subject string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func verifyBits(hash []byte, bits, n int) bool {
|
func verifyBits(hash []byte, bits, n int) bool {
|
||||||
if 0 == bits {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if bits > 8 {
|
if bits > 8 {
|
||||||
bits -= 8
|
bits -= 8
|
||||||
@ -231,12 +227,15 @@ func verifyBits(hash []byte, bits, n int) bool {
|
|||||||
|
|
||||||
// (bits % 8) == bits
|
// (bits % 8) == bits
|
||||||
pad := 8 - bits
|
pad := 8 - bits
|
||||||
if 0 == hash[i]>>pad {
|
if 0 != hash[i]>>pad {
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
// 0 == bits
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solve will search for a solution, returning an error if the difficulty is
|
// Solve will search for a solution, returning an error if the difficulty is
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user