forked from cerc-io/plugeth
Implemented AR PoW
This commit is contained in:
parent
56843ca0fc
commit
cb845b9bc8
11
pow/ar/block.go
Normal file
11
pow/ar/block.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package ar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"github.com/ethereum/eth-go/ethtrie"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Block interface {
|
||||||
|
Trie() *ethtrie.Trie
|
||||||
|
Diff() *big.Int
|
||||||
|
}
|
54
pow/ar/ops.go
Normal file
54
pow/ar/ops.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package ar
|
||||||
|
|
||||||
|
import "math/big"
|
||||||
|
|
||||||
|
const lenops int64 = 9
|
||||||
|
|
||||||
|
type OpsFunc func(a, b *big.Int) *big.Int
|
||||||
|
|
||||||
|
var ops [lenops]OpsFunc
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ops[0] = Add
|
||||||
|
ops[1] = Mul
|
||||||
|
ops[2] = Mod
|
||||||
|
ops[3] = Xor
|
||||||
|
ops[4] = And
|
||||||
|
ops[5] = Or
|
||||||
|
ops[6] = Sub1
|
||||||
|
ops[7] = XorSub
|
||||||
|
ops[8] = Rsh
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Add(x, y)
|
||||||
|
}
|
||||||
|
func Mul(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Mul(x, y)
|
||||||
|
}
|
||||||
|
func Mod(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Mod(x, y)
|
||||||
|
}
|
||||||
|
func Xor(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Xor(x, y)
|
||||||
|
}
|
||||||
|
func And(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).And(x, y)
|
||||||
|
}
|
||||||
|
func Or(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Or(x, y)
|
||||||
|
}
|
||||||
|
func Sub1(x, y *big.Int) *big.Int {
|
||||||
|
a := big.NewInt(-1)
|
||||||
|
a.Sub(a, x)
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
func XorSub(x, y *big.Int) *big.Int {
|
||||||
|
t := Sub1(x, nil)
|
||||||
|
|
||||||
|
return t.Xor(t, y)
|
||||||
|
}
|
||||||
|
func Rsh(x, y *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Rsh(x, uint(y.Uint64()%64))
|
||||||
|
}
|
122
pow/ar/pow.go
Normal file
122
pow/ar/pow.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package ar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
op OpsFunc
|
||||||
|
i, j *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tape struct {
|
||||||
|
tape []Entry
|
||||||
|
block Block
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTape(block Block) *Tape {
|
||||||
|
return &Tape{nil, block}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Tape) gen(w, h int64, gen NumberGenerator) {
|
||||||
|
self.tape = nil
|
||||||
|
|
||||||
|
for v := int64(0); v < h; v++ {
|
||||||
|
op := ops[gen.rand64(lenops).Int64()]
|
||||||
|
r := gen.rand64(100).Uint64()
|
||||||
|
|
||||||
|
var j *big.Int
|
||||||
|
if r < 20 && v > 20 {
|
||||||
|
j = self.tape[len(self.tape)-1].i
|
||||||
|
} else {
|
||||||
|
j = gen.rand64(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := gen.rand64(w)
|
||||||
|
self.tape = append(self.tape, Entry{op, i, j})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Tape) runTape(w, h int64, gen NumberGenerator) *big.Int {
|
||||||
|
var mem []*big.Int
|
||||||
|
for i := int64(0); i < w; i++ {
|
||||||
|
mem = append(mem, gen.rand(ethutil.BigPow(2, 64)))
|
||||||
|
}
|
||||||
|
|
||||||
|
set := func(i, j int) Entry {
|
||||||
|
entry := self.tape[i*100+j]
|
||||||
|
mem[entry.i.Uint64()] = entry.op(entry.i, entry.j)
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := true
|
||||||
|
for i := 0; i < int(h)/100; i++ {
|
||||||
|
var entry Entry
|
||||||
|
if dir {
|
||||||
|
for j := 0; j < 100; j++ {
|
||||||
|
entry = set(i, j)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for j := 99; i >= 0; j-- {
|
||||||
|
entry = set(i, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t := mem[entry.i.Uint64()]
|
||||||
|
if big.NewInt(2).Cmp(new(big.Int).Mod(t, big.NewInt(37))) < 0 {
|
||||||
|
dir = !dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sha3(mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Tape) Verify(header, nonce []byte) bool {
|
||||||
|
n := ethutil.BigD(nonce)
|
||||||
|
|
||||||
|
var w int64 = 10000
|
||||||
|
var h int64 = 150000
|
||||||
|
gen := Rnd(Sha3([]interface{}{header, new(big.Int).Div(n, big.NewInt(1000))}))
|
||||||
|
self.gen(w, h, gen)
|
||||||
|
|
||||||
|
gen = Rnd(Sha3([]interface{}{header, new(big.Int).Mod(n, big.NewInt(1000))}))
|
||||||
|
hash := self.runTape(w, h, gen)
|
||||||
|
|
||||||
|
it := self.block.Trie().Iterator()
|
||||||
|
next := it.Next(string(new(big.Int).Mod(hash, ethutil.BigPow(2, 160)).Bytes()))
|
||||||
|
|
||||||
|
req := ethutil.BigPow(2, 256)
|
||||||
|
req.Div(req, self.block.Diff())
|
||||||
|
return Sha3([]interface{}{hash, next}).Cmp(req) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Tape) Run(header []byte) []byte {
|
||||||
|
nonce := big.NewInt(0)
|
||||||
|
var w int64 = 10000
|
||||||
|
var h int64 = 150000
|
||||||
|
|
||||||
|
req := ethutil.BigPow(2, 256)
|
||||||
|
req.Div(req, self.block.Diff())
|
||||||
|
|
||||||
|
for {
|
||||||
|
if new(big.Int).Mod(nonce, b(1000)).Cmp(b(0)) == 0 {
|
||||||
|
gen := Rnd(Sha3([]interface{}{header, new(big.Int).Div(nonce, big.NewInt(1000))}))
|
||||||
|
self.gen(w, h, gen)
|
||||||
|
}
|
||||||
|
|
||||||
|
gen := Rnd(Sha3([]interface{}{header, new(big.Int).Mod(nonce, big.NewInt(1000))}))
|
||||||
|
hash := self.runTape(w, h, gen)
|
||||||
|
|
||||||
|
it := self.block.Trie().Iterator()
|
||||||
|
next := it.Next(string(new(big.Int).Mod(hash, ethutil.BigPow(2, 160)).Bytes()))
|
||||||
|
|
||||||
|
if Sha3([]interface{}{hash, next}).Cmp(req) < 0 {
|
||||||
|
return nonce.Bytes()
|
||||||
|
} else {
|
||||||
|
nonce.Add(nonce, ethutil.Big1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
pow/ar/pow_test.go
Normal file
47
pow/ar/pow_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package ar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/eth-go/ethdb"
|
||||||
|
"github.com/ethereum/eth-go/ethtrie"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestBlock struct {
|
||||||
|
trie *ethtrie.Trie
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestBlock() *TestBlock {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
return &TestBlock{
|
||||||
|
trie: ethtrie.New(db, ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TestBlock) Diff() *big.Int {
|
||||||
|
return b(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TestBlock) Trie() *ethtrie.Trie {
|
||||||
|
return self.trie
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TestBlock) Hash() []byte {
|
||||||
|
a := make([]byte, 32)
|
||||||
|
a[0] = 10
|
||||||
|
a[1] = 2
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPow(t *testing.T) {
|
||||||
|
entry := make([]byte, 32)
|
||||||
|
entry[0] = 255
|
||||||
|
|
||||||
|
block := NewTestBlock()
|
||||||
|
|
||||||
|
pow := NewTape(block)
|
||||||
|
nonce := pow.Run(block.Hash())
|
||||||
|
fmt.Println("Found nonce", nonce)
|
||||||
|
}
|
66
pow/ar/rnd.go
Normal file
66
pow/ar/rnd.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package ar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/eth-go/ethcrypto"
|
||||||
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var b = big.NewInt
|
||||||
|
|
||||||
|
type Node interface {
|
||||||
|
Big() *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ByteNode []byte
|
||||||
|
|
||||||
|
func (self ByteNode) Big() *big.Int {
|
||||||
|
return ethutil.BigD(ethutil.Encode([]byte(self)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sha3(v interface{}) *big.Int {
|
||||||
|
if b, ok := v.(*big.Int); ok {
|
||||||
|
return ethutil.BigD(ethcrypto.Sha3(b.Bytes()))
|
||||||
|
} else if b, ok := v.([]interface{}); ok {
|
||||||
|
return ethutil.BigD(ethcrypto.Sha3(ethutil.Encode(b)))
|
||||||
|
} else if s, ok := v.([]*big.Int); ok {
|
||||||
|
v := make([]interface{}, len(s))
|
||||||
|
for i, b := range s {
|
||||||
|
v[i] = b
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethutil.BigD(ethcrypto.Sha3(ethutil.Encode(v)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NumberGenerator interface {
|
||||||
|
rand(r *big.Int) *big.Int
|
||||||
|
rand64(r int64) *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type rnd struct {
|
||||||
|
seed *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Rnd(s *big.Int) rnd {
|
||||||
|
return rnd{s}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self rnd) rand(r *big.Int) *big.Int {
|
||||||
|
o := b(0).Mod(self.seed, r)
|
||||||
|
|
||||||
|
self.seed.Div(self.seed, r)
|
||||||
|
|
||||||
|
if self.seed.Cmp(ethutil.BigPow(2, 64)) < 0 {
|
||||||
|
self.seed = Sha3(self.seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self rnd) rand64(r int64) *big.Int {
|
||||||
|
return self.rand(b(r))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user