github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/pow/dagger/dagger.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package dagger 18 19 import ( 20 "hash" 21 "math/big" 22 "math/rand" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/crypto/sha3" 27 "github.com/ethereum/go-ethereum/logger" 28 ) 29 30 var powlogger = logger.NewLogger("POW") 31 32 type Dagger struct { 33 hash *big.Int 34 xn *big.Int 35 } 36 37 var Found bool 38 39 func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { 40 r := rand.New(rand.NewSource(time.Now().UnixNano())) 41 42 for i := 0; i < 1000; i++ { 43 rnd := r.Int63() 44 45 res := dag.Eval(big.NewInt(rnd)) 46 powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) 47 if res.Cmp(obj) < 0 { 48 // Post back result on the channel 49 resChan <- rnd 50 // Notify other threads we've found a valid nonce 51 Found = true 52 } 53 54 // Break out if found 55 if Found { 56 break 57 } 58 } 59 60 resChan <- 0 61 } 62 63 func (dag *Dagger) Search(hash, diff *big.Int) (uint64, []byte) { 64 // TODO fix multi threading. Somehow it results in the wrong nonce 65 amountOfRoutines := 1 66 67 dag.hash = hash 68 69 obj := common.BigPow(2, 256) 70 obj = obj.Div(obj, diff) 71 72 Found = false 73 resChan := make(chan int64, 3) 74 var res int64 75 76 for k := 0; k < amountOfRoutines; k++ { 77 go dag.Find(obj, resChan) 78 79 // Wait for each go routine to finish 80 } 81 for k := 0; k < amountOfRoutines; k++ { 82 // Get the result from the channel. 0 = quit 83 if r := <-resChan; r != 0 { 84 res = r 85 } 86 } 87 88 return uint64(res), nil 89 } 90 91 func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { 92 dag.hash = hash 93 94 obj := common.BigPow(2, 256) 95 obj = obj.Div(obj, diff) 96 97 return dag.Eval(nonce).Cmp(obj) < 0 98 } 99 100 func DaggerVerify(hash, diff, nonce *big.Int) bool { 101 dagger := &Dagger{} 102 dagger.hash = hash 103 104 obj := common.BigPow(2, 256) 105 obj = obj.Div(obj, diff) 106 107 return dagger.Eval(nonce).Cmp(obj) < 0 108 } 109 110 func (dag *Dagger) Node(L uint64, i uint64) *big.Int { 111 if L == i { 112 return dag.hash 113 } 114 115 var m *big.Int 116 if L == 9 { 117 m = big.NewInt(16) 118 } else { 119 m = big.NewInt(3) 120 } 121 122 sha := sha3.NewKeccak256() 123 sha.Reset() 124 d := sha3.NewKeccak256() 125 b := new(big.Int) 126 ret := new(big.Int) 127 128 for k := 0; k < int(m.Uint64()); k++ { 129 d.Reset() 130 d.Write(dag.hash.Bytes()) 131 d.Write(dag.xn.Bytes()) 132 d.Write(big.NewInt(int64(L)).Bytes()) 133 d.Write(big.NewInt(int64(i)).Bytes()) 134 d.Write(big.NewInt(int64(k)).Bytes()) 135 136 b.SetBytes(Sum(d)) 137 pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) 138 sha.Write(dag.Node(L-1, pk).Bytes()) 139 } 140 141 ret.SetBytes(Sum(sha)) 142 143 return ret 144 } 145 146 func Sum(sha hash.Hash) []byte { 147 //in := make([]byte, 32) 148 return sha.Sum(nil) 149 } 150 151 func (dag *Dagger) Eval(N *big.Int) *big.Int { 152 pow := common.BigPow(2, 26) 153 dag.xn = pow.Div(N, pow) 154 155 sha := sha3.NewKeccak256() 156 sha.Reset() 157 ret := new(big.Int) 158 159 for k := 0; k < 4; k++ { 160 d := sha3.NewKeccak256() 161 b := new(big.Int) 162 163 d.Reset() 164 d.Write(dag.hash.Bytes()) 165 d.Write(dag.xn.Bytes()) 166 d.Write(N.Bytes()) 167 d.Write(big.NewInt(int64(k)).Bytes()) 168 169 b.SetBytes(Sum(d)) 170 pk := (b.Uint64() & 0x1ffffff) 171 172 sha.Write(dag.Node(9, pk).Bytes()) 173 } 174 175 return ret.SetBytes(Sum(sha)) 176 }