Archived
1
0

re add pow captcha (initial)

This commit is contained in:
Jeff Becker 2018-02-22 07:53:34 -05:00
parent 2bb4540118
commit c3426871d2
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
18 changed files with 24656 additions and 7 deletions

View File

@ -1,7 +1,9 @@
REPO=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
REPO_GOPATH=$(REPO)/go
MINIFY=$(REPO_GOPATH)/bin/minify
JS=$(REPO)/contrib/static/nntpchan.js
STATIC_DIR=$(REPO)/contrib/static
JS=$(STATIC_DIR)/nntpchan.js
MINER_JS=$(STATIC_DIR)/miner-js.js
CONTRIB_JS=$(REPO)/contrib/js/contrib
LOCAL_JS=$(REPO)/contrib/js/nntpchan
VENDOR_JS=$(REPO)/contrib/js/vendor
@ -15,6 +17,11 @@ NNTPD=$(REPO)/nntpd
GOROOT=$(shell go env GOROOT)
GO=$(GOROOT)/bin/go
GOPHERJS_GOROOT ?= $(GOROOT)
GOPHERJS_GO = $(GOPHERJS_GOROOT)/bin/go
GOPHERJS=$(REPO_GOPATH)/bin/gopherjs
all: clean build
build: js srnd
@ -23,14 +30,23 @@ full: clean full-build
full-build: srnd beta native
js: $(JS)
js: $(JS) $(MINER_JS)
srnd: $(SRND)
$(MINIFY):
GOPATH=$(REPO_GOPATH) go get -v github.com/tdewolff/minify/cmd/minify
GOPATH=$(REPO_GOPATH) $(GO) get -v github.com/tdewolff/minify/cmd/minify
js-deps: $(MINIFY)
$(GOPHERJS):
GOPATH=$(REPO_GOPATH) $(GOPHERJS_GO) get -v github.com/gopherjs/gopherjs
js-deps: $(MINIFY) $(MINER_JS)
$(MINER_JS): $(GOPHERJS) $(MINIFY)
cp -rf $(SRND_DIR)/src/github.com $(REPO_GOPATH)/src/
GOROOT=$(GOPHERJS_GOROOT) GOPATH=$(REPO_GOPATH) $(GOPHERJS) -m -v build github.com/ZiRo-/cuckgo/miner_js
$(MINIFY) --mime=text/javascript > $(STATIC_DIR)/miner-js.js < miner_js.js
rm -f miner_js.js.map miner_js.js
$(JS): js-deps
rm -f $(JS)
@ -70,16 +86,16 @@ test-native:
GOROOT=$(GOROOT) $(MAKE) -C $(NNTPCHAN_DAEMON_DIR) test
clean: clean-js clean-srnd
clean: clean-srnd clean-js
clean-full: clean clean-beta clean-native
clean-full: clean clean-beta clean-native clean-js
clean-srnd:
rm -f $(SRND)
GOROOT=$(GOROOT) $(MAKE) -C $(SRND_DIR) clean
clean-js:
rm -f $(JS)
rm -f $(JS) $(MINER_JS)
clean-beta:
rm -f $(NNTPCHAND)

View File

@ -0,0 +1,11 @@
*.pyc
*~
*.ini
*.db
build.dir
\#*
.\#*
_obj
*.log
*.la
*.txt

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 ZiRo-
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,41 @@
Cuckoo Cycle
============
# Go implementation
This is a Go implementation of the cuckoo Proof of Work algorith "cuckoo cycle" by John Tromp.
This implementation includes the verification function as a library, and a simple multi-threaded miner.
# Installation
To install this miner just run
`go get github.com/ZiRo-/cuckgo/miner`
# Usage
```
Usage of miner:
-e float
easiness in percentage (default 50)
-m int
maximum number of solutions (default 8)
-t int
number of miner threads (default 4)
```
# Algorithm
For details about the algorith, see: https://github.com/tromp/cuckoo
# Benchmarks
#### N = 100, Easiness = 55, Average time = 0.9 s, CPU = i5-4210U
![N = 100, Easiness = 55, Average time = 0.9 s, CPU = i5-4210U] (https://raw.githubusercontent.com/ZiRo-/cuckgo/master/bench/bench_N_100_e_55_avg_0.9.png)
#### N = 100, Easiness = 50, Average time = 2.3 s, CPU = i5-4210U
![N = 100, Easiness = 50, Average time = 2.3 s, CPU = i5-4210U] (https://raw.githubusercontent.com/ZiRo-/cuckgo/master/bench/bench_N_100_e_50_avg_2.3.png)
#### N = 300, Easiness = 46, Average time = 56.2 s, CPU = i5-4210U
![N = 300, Easiness = 46, Average time = 56.2 s, CPU = i5-4210U] (https://raw.githubusercontent.com/ZiRo-/cuckgo/master/bench/bench_N_300_e_46_avg_56.2.png)
# JavaScript version
Using [GopherJS](https://github.com/gopherjs/gopherjs) the Go implementation can be transpiled to JavaScript,
which is also included in this repo. This file currently exports one function:
`cuckoo["mine_cuckoo"](easiness)`
which returns the same base64 representation of a proof as the Go CLI miner.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,56 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import (
"encoding/base64"
"fmt"
"github.com/ZiRo-/cuckgo/cuckoo"
"os"
)
func main() {
if len(os.Args) < 2 {
os.Exit(3)
}
data, err := base64.StdEncoding.DecodeString(os.Args[1])
if err != nil {
fmt.Println("error:", err)
os.Exit(2)
}
cuck, err := cuckoo.DecodeCuckooJSON(data)
if err != nil {
fmt.Println("error:", err)
os.Exit(2)
}
//fmt.Println(cuck)
if cuckoo.VerifyJSON(*cuck) {
fmt.Println("Valid")
os.Exit(0)
} else {
fmt.Println("Invalid")
os.Exit(1)
}
}

View File

@ -0,0 +1,232 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package cuckoo
import "crypto/sha256"
const (
SIZESHIFT uint64 = 20
PROOFSIZE uint64 = 42
SIZE uint64 = 1 << SIZESHIFT
HALFSIZE uint64 = SIZE / 2
NODEMASK uint64 = HALFSIZE - 1
)
type Cuckoo struct {
v [4]uint64
}
func u8(b byte) uint64 {
return (uint64)(b) & 0xff
}
func u8to64(p [sha256.Size]byte, i int) uint64 {
return u8(p[i]) | u8(p[i+1])<<8 |
u8(p[i+2])<<16 | u8(p[i+3])<<24 |
u8(p[i+4])<<32 | u8(p[i+5])<<40 |
u8(p[i+6])<<48 | u8(p[i+7])<<56
}
func NewCuckoo(header []byte) *Cuckoo {
hdrkey := sha256.Sum256(header)
return NewCuckooSHA(hdrkey)
}
func NewCuckooSHA(hdrkey [sha256.Size]byte) *Cuckoo {
self := new(Cuckoo)
k0 := u8to64(hdrkey, 0)
k1 := u8to64(hdrkey, 8)
self.v[0] = k0 ^ 0x736f6d6570736575
self.v[1] = k1 ^ 0x646f72616e646f6d
self.v[2] = k0 ^ 0x6c7967656e657261
self.v[3] = k1 ^ 0x7465646279746573
return self
}
type Edge struct {
U uint64
V uint64
}
func (self *Edge) HashCode() int {
return int(self.U) ^ int(self.V)
}
func (self *Cuckoo) Sipedge(nonce uint64) *Edge {
return &Edge{self.Sipnode(nonce, 0), self.Sipnode(nonce, 1)}
}
func (self *Cuckoo) siphash24(nonce uint64) uint64 {
v0 := self.v[0]
v1 := self.v[1]
v2 := self.v[2]
v3 := self.v[3] ^ nonce
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
v0 ^= nonce
v2 ^= 0xff
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
v0 += v1
v2 += v3
v1 = (v1 << 13) | v1>>51
v3 = (v3 << 16) | v3>>48
v1 ^= v0
v3 ^= v2
v0 = (v0 << 32) | v0>>32
v2 += v1
v0 += v3
v1 = (v1 << 17) | v1>>47
v3 = (v3 << 21) | v3>>43
v1 ^= v2
v3 ^= v0
v2 = (v2 << 32) | v2>>32
return v0 ^ v1 ^ v2 ^ v3
}
// generate edge in cuckoo graph
func (self *Cuckoo) Sipnode(nonce uint64, uorv uint32) uint64 {
return self.siphash24(2*nonce+uint64(uorv)) & NODEMASK
}
// verify that (ascending) nonces, all less than easiness, form a cycle in graph
func (self *Cuckoo) Verify(nonces []uint64, easiness uint64) bool {
us := make([]uint64, PROOFSIZE)
vs := make([]uint64, PROOFSIZE)
i := 0
var n uint64
for n = 0; n < PROOFSIZE; n++ {
if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n-1]) {
return false
}
us[n] = self.Sipnode(nonces[n], 0)
vs[n] = self.Sipnode(nonces[n], 1)
}
loop := true
for loop { // follow cycle until we return to i==0; n edges left to visit
j := i
for k := 0; uint64(k) < PROOFSIZE; k++ { // find unique other j with same vs[j]
if k != i && vs[k] == vs[i] {
if j != i {
return false
}
j = k
}
}
if j == i {
return false
}
i = j
for k := 0; uint64(k) < PROOFSIZE; k++ { // find unique other i with same us[i]
if k != j && us[k] == us[j] {
if i != j {
return false
}
i = k
}
}
if i == j {
return false
}
n -= 2
loop = (i != 0)
}
return n == 0
}

View File

@ -0,0 +1,69 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package cuckoo
import (
"crypto/sha256"
"encoding/json"
)
type CuckooJSON struct {
Parameter map[string]uint64 `json:"parameters"`
InputData []byte `json:"header"` //sha256 bytes
Cycle []uint64 `json:"cycle"`
}
func DecodeCuckooJSON(jsonBlob []byte) (*CuckooJSON, error) {
res := new(CuckooJSON)
err := json.Unmarshal(jsonBlob, res)
if err != nil {
return nil, err
}
return res, nil
}
func EncodeCuckooJSON(cuck CuckooJSON) ([]byte, error) {
return json.Marshal(cuck)
}
func VerifyJSON(cuck CuckooJSON) bool {
easy := cuck.Parameter["easiness"]
if easy <= 0 || easy >= SIZE {
return false
}
if len(cuck.InputData) != sha256.Size {
return false
}
if uint64(len(cuck.Cycle)) != PROOFSIZE {
return false
}
var sha [sha256.Size]byte
copy(sha[:], cuck.InputData)
c := NewCuckooSHA(sha)
return c.Verify(cuck.Cycle, easy)
}

View File

@ -0,0 +1,54 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import (
"flag"
"fmt"
"github.com/ZiRo-/cuckgo/miner/miner_lib"
"runtime"
)
var nthreads int
var maxsols int
var easipct float64
//var header string
func init() {
flag.IntVar(&nthreads, "t", 0, "number of miner threads")
flag.IntVar(&maxsols, "m", 8, "maximum number of solutions")
flag.Float64Var(&easipct, "e", 50.0, "easiness in percentage")
//flag.StringVar(&header, "h", "cuck", "Header")
}
func main() {
flag.Parse()
if (nthreads < 1) {
nthreads = runtime.NumCPU()
}
//fmt.Println("Looking for", cuckoo.PROOFSIZE, "-cycle on cuckoo", cuckoo.SIZESHIFT, "with", easipct, "% edges and", nthreads, "threads")
c := miner_lib.Mine(easipct, maxsols, nthreads)
fmt.Println(c.String())
}

View File

@ -0,0 +1,292 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package miner_lib
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"github.com/ZiRo-/cuckgo/cuckoo"
"sync"
)
const MAXPATHLEN = 4096
const RANDOFFS = 64
const MAXLEN = 1024
type CuckooSolve struct {
graph *cuckoo.Cuckoo
easiness int
cuckoo []int
sols [][]int
nsols int
nthreads int
}
type CuckooProof struct {
solve *CuckooSolve
b []byte
}
func NewCuckooSolve(hdr []byte, en, ms, nt int) *CuckooSolve {
self := &CuckooSolve{
graph: cuckoo.NewCuckoo(hdr),
easiness: en,
sols: make([][]int, 2*ms), //this isn't completley safe for high easiness
cuckoo: make([]int, 1+int(cuckoo.SIZE)),
nsols: 0,
nthreads: 1,
}
for i := range self.sols {
self.sols[i] = make([]int, cuckoo.PROOFSIZE)
}
return self
}
func (self *CuckooSolve) path(u int, us []int, done chan int) int {
nu := 0
for nu = 0; u != 0; u = self.cuckoo[u] {
nu++
if nu >= MAXPATHLEN {
for nu != 0 && us[nu-1] != u {
nu--
}
if nu < 0 {
//fmt.Println("maximum path length exceeded")
} else {
//fmt.Println("illegal", (MAXPATHLEN - nu), "-cycle")
}
close(done)
return -1
}
us[nu] = u
}
return nu
}
func (self *CuckooSolve) solution(us []int, nu int, vs []int, nv int) {
cycle := make(map[int]*cuckoo.Edge)
n := 0
edg := &cuckoo.Edge{uint64(us[0]), uint64(vs[0]) - cuckoo.HALFSIZE}
cycle[edg.HashCode()] = edg
for nu != 0 { // u's in even position; v's in odd
nu--
edg := &cuckoo.Edge{uint64(us[(nu+1)&^1]), uint64(us[nu|1]) - cuckoo.HALFSIZE}
_, has := cycle[edg.HashCode()]
if !has {
cycle[edg.HashCode()] = edg
}
}
for nv != 0 { // u's in odd position; v's in even
nv--
edg := &cuckoo.Edge{uint64(vs[nv|1]), uint64(vs[(nv+1)&^1]) - cuckoo.HALFSIZE}
_, has := cycle[edg.HashCode()]
if !has {
cycle[edg.HashCode()] = edg
}
}
n = 0
for nonce := 0; nonce < self.easiness; nonce++ {
e := self.graph.Sipedge(uint64(nonce))
has, key := contains(cycle, e)
if has {
self.sols[self.nsols][n] = nonce
n++
delete(cycle, key)
}
}
if uint64(n) == cuckoo.PROOFSIZE {
self.nsols++
} else {
//fmt.Println("Only recovered ", n, " nonces")
}
}
func contains(m map[int]*cuckoo.Edge, e *cuckoo.Edge) (bool, int) {
h := e.HashCode()
for k, v := range m {
if k == h && v.U == e.U && v.V == e.V { //fuck Java for making me waste time just to figure out that that's how Java does contains
return true, k
}
}
return false, 0
}
func worker(id int, solve *CuckooSolve, done chan int) {
cuck := solve.cuckoo
us := make([]int, MAXPATHLEN)
vs := make([]int, MAXPATHLEN)
for nonce := id; nonce < solve.easiness; nonce += solve.nthreads {
us[0] = (int)(solve.graph.Sipnode(uint64(nonce), 0))
u := cuck[us[0]]
vs[0] = (int)(cuckoo.HALFSIZE + solve.graph.Sipnode(uint64(nonce), 1))
v := cuck[vs[0]]
if u == vs[0] || v == us[0] {
continue // ignore duplicate edges
}
nu := solve.path(u, us, done)
nv := solve.path(v, vs, done)
if nu == -1 || nv == -1 {
return
}
if us[nu] == vs[nv] {
min := 0
if nu < nv {
min = nu
} else {
min = nv
}
nu -= min
nv -= min
for us[nu] != vs[nv] {
nu++
nv++
}
length := nu + nv + 1
//fmt.Println(" " , length , "-cycle found at " , id , ":" , (int)(nonce*100/solve.easiness) , "%")
if uint64(length) == cuckoo.PROOFSIZE && solve.nsols < len(solve.sols) {
solve.solution(us, nu, vs, nv)
}
continue
}
if nu < nv {
for nu != 0 {
nu--
cuck[us[nu+1]] = us[nu]
}
cuck[us[0]] = vs[0]
} else {
for nv != 0 {
nv--
cuck[vs[nv+1]] = vs[nv]
}
cuck[vs[0]] = us[0]
}
}
close(done)
}
func Mine(easipct float64, maxsols, nthreads int) *CuckooProof {
b := make([]byte, RANDOFFS)
_, err := rand.Read(b)
if err != nil {
panic(err)
}
easy := int(easipct * float64(cuckoo.SIZE) / 100.0)
solve := NewCuckooSolve(b, easy, maxsols, 1)
for k := 0; k < MAXLEN-RANDOFFS; k++ {
b = append(b, 0)
for i := 0; i < 256; i += nthreads {
cs := make([]chan int, nthreads)
solvers := make([]*CuckooSolve, nthreads)
for n := 0; n < nthreads; n++ {
cs[n] = make(chan int)
}
out := merge(cs...)
for n := 0; n < nthreads; n++ {
if i+n < 256 {
b[RANDOFFS+k] = byte(i + n)
solvers[n] = NewCuckooSolve(b, easy, maxsols, 1)
go worker(i, solvers[n], cs[n])
} else {
close(cs[n])
}
}
<-out
for n, s := range solvers {
if s.nsols > 0 {
b[RANDOFFS+k] = byte(i + n)
solve = s
goto done
}
}
}
}
done:
/* for s := 0; s < solve.nsols; s++ {
//fmt.Print("Solution")
for i := 0; uint64(i) < cuckoo.PROOFSIZE; i++ {
fmt.Printf(" %x", solve.sols[s][i])
}
fmt.Println()
}*/
if solve.nsols <= 0 {
solve = nil
}
return &CuckooProof{solve, b}
}
func (self *CuckooProof)String() string {
c := formatProof(self.solve, self.b)
json, _ := cuckoo.EncodeCuckooJSON(c)
return base64.StdEncoding.EncodeToString(json)
}
func formatProof(solve *CuckooSolve, b []byte) cuckoo.CuckooJSON {
sha := sha256.Sum256(b)
easy := uint64(solve.easiness)
cycle := make([]uint64, len(solve.sols[0]))
m := make(map[string]uint64)
m["easiness"] = easy
for i, n := range solve.sols[0] {
cycle[i] = uint64(n)
}
return cuckoo.CuckooJSON{m, sha[:], cycle}
}
func merge(cs ...chan int) chan int {
var wg sync.WaitGroup
out := make(chan int)
// Start an output goroutine for each input channel in cs. output
// copies values from c to out until c is closed, then calls wg.Done.
output := func(c chan int) {
for n := range c {
out <- n
}
wg.Done()
}
wg.Add(len(cs))
for _, c := range cs {
go output(c)
}
// Start a goroutine to close out once all the output goroutines are
// done. This must start after the wg.Add call.
go func() {
wg.Wait()
close(out)
}()
return out
}

View File

@ -0,0 +1,155 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import "crypto/sha256"
import "github.com/gopherjs/gopherjs/js"
const (
SIZESHIFT uint64 = 20
PROOFSIZE uint64 = 42
SIZE uint64 = 1 << SIZESHIFT
HALFSIZE uint64 = SIZE / 2
NODEMASK uint64 = HALFSIZE - 1
)
type Cuckoo struct {
v [4]uint64
vh [4]uint32
vl [4]uint32
key []byte
}
func u8(b byte) uint64 {
return (uint64)(b) & 0xff
}
func u8to64(p [sha256.Size]byte, i int) uint64 {
return u8(p[i]) | u8(p[i+1])<<8 |
u8(p[i+2])<<16 | u8(p[i+3])<<24 |
u8(p[i+4])<<32 | u8(p[i+5])<<40 |
u8(p[i+6])<<48 | u8(p[i+7])<<56
}
func NewCuckoo(header []byte) *Cuckoo {
hdrkey := sha256.Sum256(header)
return NewCuckooSHA(hdrkey)
}
func NewCuckooSHA(hdrkey [sha256.Size]byte) *Cuckoo {
self := new(Cuckoo)
k0 := u8to64(hdrkey, 0)
k1 := u8to64(hdrkey, 8)
self.v[0] = k0 ^ 0x736f6d6570736575
self.v[1] = k1 ^ 0x646f72616e646f6d
self.v[2] = k0 ^ 0x6c7967656e657261
self.v[3] = k1 ^ 0x7465646279746573
self.key = hdrkey[:]
for i,h := range(self.v) {
self.vl[i] = uint32 (h & 0xFFFFFFFF);
self.vh[i] = uint32((h & (0xFFFFFFFF << 32) ) >> 32);
}
return self
}
type Edge struct {
U uint64
V uint64
}
func (self *Edge) HashCode() int {
return int(self.U) ^ int(self.V)
}
func (self *Cuckoo) Sipedge(nonce uint64) *Edge {
return &Edge{self.Sipnode(nonce, 0), self.Sipnode(nonce, 1)}
}
func (self *Cuckoo) siphash24(nonce uint64) uint64 {
return siphash24_js(self.vh, self.vl, nonce)
}
var sh *js.Object = js.Global.Get("SipHash")
func siphash24_js(vh, vl [4]uint32, nonce uint64) uint64 {
arr := sh.Call("hash", vh[0], vl[0], vh[1], vl[1], vh[2], vl[2], vh[3], vl[3], 0, nonce)
high := arr.Index(0).Uint64();
low := arr.Index(1).Uint64();
return (high << 32) | low;
}
// generate edge in cuckoo graph
func (self *Cuckoo) Sipnode(nonce uint64, uorv uint32) uint64 {
return self.siphash24(2*nonce+uint64(uorv)) & NODEMASK
}
// verify that (ascending) nonces, all less than easiness, form a cycle in graph
func (self *Cuckoo) Verify(nonces []uint64, easiness uint64) bool {
us := make([]uint64, PROOFSIZE)
vs := make([]uint64, PROOFSIZE)
i := 0
var n uint64
for n = 0; n < PROOFSIZE; n++ {
if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n-1]) {
return false
}
us[n] = self.Sipnode(nonces[n], 0)
vs[n] = self.Sipnode(nonces[n], 1)
}
loop := true
for loop { // follow cycle until we return to i==0; n edges left to visit
j := i
for k := 0; uint64(k) < PROOFSIZE; k++ { // find unique other j with same vs[j]
if k != i && vs[k] == vs[i] {
if j != i {
return false
}
j = k
}
}
if j == i {
return false
}
i = j
for k := 0; uint64(k) < PROOFSIZE; k++ { // find unique other i with same us[i]
if k != j && us[k] == us[j] {
if i != j {
return false
}
i = k
}
}
if i == j {
return false
}
n -= 2
loop = (i != 0)
}
return n == 0
}

View File

@ -0,0 +1,226 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import (
"crypto/sha256"
"encoding/base64"
"github.com/gopherjs/gopherjs/js"
)
const MAXPATHLEN = 4096
const RANDOFFS = 64
const MAXLEN = 1024
type CuckooSolve struct {
graph *Cuckoo
easiness int
cuckoo []int
sols [][]int
nsols int
nthreads int
}
func NewCuckooSolve(hdr []byte, en, ms, nt int) *CuckooSolve {
self := &CuckooSolve{
graph: NewCuckoo(hdr),
easiness: en,
sols: make([][]int, 2*ms), //this isn't completley safe for high easiness
cuckoo: make([]int, 1+int(SIZE)),
nsols: 0,
nthreads: 1,
}
for i := range self.sols {
self.sols[i] = make([]int, PROOFSIZE)
}
return self
}
func (self *CuckooSolve) path(u int, us []int) int {
nu := 0
for nu = 0; u != 0; u = self.cuckoo[u] {
nu++
if nu >= MAXPATHLEN {
for nu != 0 && us[nu-1] != u {
nu--
}
if nu < 0 {
//fmt.Println("maximum path length exceeded")
} else {
//fmt.Println("illegal", (MAXPATHLEN - nu), "-cycle")
}
return -1
}
us[nu] = u
}
return nu
}
func (self *CuckooSolve) solution(us []int, nu int, vs []int, nv int) bool {
cycle := make(map[int]*Edge)
n := 0
edg := &Edge{uint64(us[0]), uint64(vs[0]) - HALFSIZE}
cycle[edg.HashCode()] = edg
for nu != 0 { // u's in even position; v's in odd
nu--
edg := &Edge{uint64(us[(nu+1)&^1]), uint64(us[nu|1]) - HALFSIZE}
_, has := cycle[edg.HashCode()]
if !has {
cycle[edg.HashCode()] = edg
}
}
for nv != 0 { // u's in odd position; v's in even
nv--
edg := &Edge{uint64(vs[nv|1]), uint64(vs[(nv+1)&^1]) - HALFSIZE}
_, has := cycle[edg.HashCode()]
if !has {
cycle[edg.HashCode()] = edg
}
}
n = 0
for nonce := 0; nonce < self.easiness; nonce++ {
e := self.graph.Sipedge(uint64(nonce))
has, key := contains(cycle, e)
if has {
self.sols[self.nsols][n] = nonce
n++
delete(cycle, key)
}
}
if uint64(n) == PROOFSIZE {
self.nsols++
return true
} else {
//fmt.Println("Only recovered ", n, " nonces")
}
return false
}
func contains(m map[int]*Edge, e *Edge) (bool, int) {
h := e.HashCode()
for k, v := range m {
if k == h && v.U == e.U && v.V == e.V { //fuck Java for making me waste time just to figure out that that's how Java does contains
return true, k
}
}
return false, 0
}
func worker(id int, solve *CuckooSolve) {
cuck := solve.cuckoo
us := make([]int, MAXPATHLEN)
vs := make([]int, MAXPATHLEN)
for nonce := id; nonce < solve.easiness; nonce += solve.nthreads {
us[0] = (int)(solve.graph.Sipnode(uint64(nonce), 0))
u := cuck[us[0]]
vs[0] = (int)(HALFSIZE + solve.graph.Sipnode(uint64(nonce), 1))
v := cuck[vs[0]]
if u == vs[0] || v == us[0] {
continue // ignore duplicate edges
}
nu := solve.path(u, us)
nv := solve.path(v, vs)
if nu == -1 || nv == -1 {
return
}
if us[nu] == vs[nv] {
min := 0
if nu < nv {
min = nu
} else {
min = nv
}
nu -= min
nv -= min
for us[nu] != vs[nv] {
nu++
nv++
}
length := nu + nv + 1
//fmt.Println(" " , length , "-cycle found at " , id , ":" , (int)(nonce*100/solve.easiness) , "%")
if uint64(length) == PROOFSIZE && solve.nsols < len(solve.sols) {
if solve.solution(us, nu, vs, nv) {
break;
}
}
continue
}
if nu < nv {
for nu != 0 {
nu--
cuck[us[nu+1]] = us[nu]
}
cuck[us[0]] = vs[0]
} else {
for nv != 0 {
nv--
cuck[vs[nv+1]] = vs[nv]
}
cuck[vs[0]] = us[0]
}
}
}
func mine_cuckoo(b []byte, easipct float64) []string {
easy := int(easipct * float64(SIZE) / 100.0)
solve := NewCuckooSolve(b, easy, 8, 1)
worker(0, solve)
res := make([]string, 2)
if solve.nsols > 0 {
c := formatProof(solve, b)
json, _ := EncodeCuckooJSON(c)
str := base64.StdEncoding.EncodeToString(json)
res[0] = "ok"
res[1] = str
} else {
res[0] = "D^:"
}
return res
}
func formatProof(solve *CuckooSolve, b []byte) CuckooJSON {
sha := sha256.Sum256(b)
easy := uint64(solve.easiness)
cycle := make([]uint64, len(solve.sols[0]))
m := make(map[string]uint64)
m["easiness"] = easy
for i, n := range solve.sols[0] {
cycle[i] = uint64(n)
}
return CuckooJSON{m, sha[:], cycle}
}
func main() {
js.Global.Set("cuckoo", map[string]interface{}{
"mine_cuckoo": mine_cuckoo,
})
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,94 @@
var SipHash = (function() {
function u8to64(p , i) {
return { l: (p[i] | p[i+1]<<8 | p[i+2]<<16 | p[i+3]<<24) , h: (p[i+4] | p[i+5]<<8 | p[i+6]<<16 | p[i+7]<<24) };
}
function _add(a, b) {
var rl = a.l + b.l,
a2 = { h: a.h + b.h + (rl / 2 >>> 31) >>> 0,
l: rl >>> 0 };
a.h = a2.h; a.l = a2.l;
}
function _xor(a, b) {
a.h ^= b.h; a.h >>>= 0;
a.l ^= b.l; a.l >>>= 0;
}
function _rotl(a, n) {
var a2 = {
h: a.h << n | a.l >>> (32 - n),
l: a.l << n | a.h >>> (32 - n)
};
a.h = a2.h; a.l = a2.l;
}
function _rotl32(a) {
var al = a.l;
a.l = a.h; a.h = al;
}
function _compress(v0, v1, v2, v3) {
_add(v0, v1);
_add(v2, v3);
_rotl(v1, 13);
_rotl(v3, 16);
_xor(v1, v0);
_xor(v3, v2);
_rotl32(v0);
_add(v2, v1);
_add(v0, v3);
_rotl(v1, 17);
_rotl(v3, 21);
_xor(v1, v2);
_xor(v3, v0);
_rotl32(v2);
}
function hash(v0h, v0l, v1h, v1l, v2h, v2l, v3h, v3l, mh, ml) {
var mi = { h: mh, l: ml };
var v0 = { h: v0h, l: v0l };
var v1 = { h: v1h, l: v1l };
var v2 = { h: v2h, l: v2l };
var v3 = { h: v3h, l: v3l };
/*var k0 = u8to64(key, 0);
var k1 = u8to64(key, 8);
var v0 = { h: k0.h, l: k0.l }, v2 = k0;
var v1 = { h: k1.h, l: k1.l }, v3 = k1;
_xor(v0, { h: 0x736f6d65, l: 0x70736575 });
_xor(v1, { h: 0x646f7261, l: 0x6e646f6d });
_xor(v2, { h: 0x6c796765, l: 0x6e657261 });
_xor(v3, { h: 0x74656462, l: 0x79746573 });*/
_xor(v3, mi);
_compress(v0, v1, v2, v3);
_compress(v0, v1, v2, v3);
_xor(v0, mi);
_xor(v2, { h: 0, l: 0xff });
_compress(v0, v1, v2, v3);
_compress(v0, v1, v2, v3);
_compress(v0, v1, v2, v3);
_compress(v0, v1, v2, v3);
var h = v0;
_xor(h, v1);
_xor(h, v2);
_xor(h, v3);
var res = new Uint32Array(2);
res[0]=h.h; res[1]=h.l;
return res;
};
return {
hash: hash,
};
})();
var module = module || { }, exports = module.exports = SipHash;

View File

@ -0,0 +1,69 @@
/*
The MIT License (MIT)
Copyright (c) 2016 ZiRo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import (
"crypto/sha256"
"encoding/json"
)
type CuckooJSON struct {
Parameter map[string]uint64 `json:"parameters"`
InputData []byte `json:"header"` //sha256 bytes
Cycle []uint64 `json:"cycle"`
}
func DecodeCuckooJSON(jsonBlob []byte) (*CuckooJSON, error) {
res := new(CuckooJSON)
err := json.Unmarshal(jsonBlob, res)
if err != nil {
return nil, err
}
return res, nil
}
func EncodeCuckooJSON(cuck CuckooJSON) ([]byte, error) {
return json.Marshal(cuck)
}
func VerifyJSON(cuck CuckooJSON) bool {
easy := cuck.Parameter["easiness"]
if easy <= 0 || easy >= SIZE {
return false
}
if len(cuck.InputData) != sha256.Size {
return false
}
if uint64(len(cuck.Cycle)) != PROOFSIZE {
return false
}
var sha [sha256.Size]byte
copy(sha[:], cuck.InputData)
c := NewCuckooSHA(sha)
return c.Verify(cuck.Cycle, easy)
}