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  }