diff --git a/whisper/whisperv6/envelope.go b/whisper/whisperv6/envelope.go index c42d1fa8a..5d9d35081 100644 --- a/whisper/whisperv6/envelope.go +++ b/whisper/whisperv6/envelope.go @@ -27,7 +27,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/rlp" @@ -82,7 +81,7 @@ func (e *Envelope) Seal(options *MessageParams) error { return nil } - var target, bestBit int + var target, bestLeadingZeros int if options.PoW < 0 { // target is not set - the function should run for a period // of time specified in WorkTime param. Since we can predict @@ -101,10 +100,10 @@ func (e *Envelope) Seal(options *MessageParams) error { for i := 0; i < 1024; i++ { binary.BigEndian.PutUint64(buf[56:], nonce) d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - if firstBit > bestBit { - e.Nonce, bestBit = nonce, firstBit - if target > 0 && bestBit >= target { + leadingZeros := 256 - d.BitLen() + if leadingZeros > bestLeadingZeros { + e.Nonce, bestLeadingZeros = nonce, leadingZeros + if target > 0 && bestLeadingZeros >= target { return nil } } @@ -112,7 +111,7 @@ func (e *Envelope) Seal(options *MessageParams) error { } } - if target > 0 && bestBit < target { + if target > 0 && bestLeadingZeros < target { return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) } @@ -130,13 +129,14 @@ func (e *Envelope) PoW() float64 { func (e *Envelope) calculatePoW(diff uint32) { buf := make([]byte, 64) - h := crypto.Keccak256(e.rlpWithoutNonce()) + rlp := e.rlpWithoutNonce() + h := crypto.Keccak256(rlp) copy(buf[:32], h) binary.BigEndian.PutUint64(buf[56:], e.Nonce) - d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - x := gmath.Pow(2, float64(firstBit)) - x /= float64(e.size()) + powHash := new(big.Int).SetBytes(crypto.Keccak256(buf)) + leadingZeroes := 256 - powHash.BitLen() + x := gmath.Pow(2, float64(leadingZeroes)) + x /= float64(len(rlp)) x /= float64(e.TTL + diff) e.pow = x } diff --git a/whisper/whisperv6/envelope_test.go b/whisper/whisperv6/envelope_test.go index 410b250a3..d6e38e683 100644 --- a/whisper/whisperv6/envelope_test.go +++ b/whisper/whisperv6/envelope_test.go @@ -25,6 +25,33 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +func TestPoWCalculationsWithNoLeadingZeros(t *testing.T) { + e := Envelope{ + TTL: 1, + Data: []byte{0xde, 0xad, 0xbe, 0xef}, + Nonce: 100000, + } + + e.calculatePoW(0) + + if e.pow != 0.07692307692307693 { + t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow) + } +} + +func TestPoWCalculationsWith8LeadingZeros(t *testing.T) { + e := Envelope{ + TTL: 1, + Data: []byte{0xde, 0xad, 0xbe, 0xef}, + Nonce: 48159, + } + e.calculatePoW(0) + + if e.pow != 40329.846153846156 { + t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow) + } +} + func TestEnvelopeOpenAcceptsOnlyOneKeyTypeInFilter(t *testing.T) { symKey := make([]byte, aesKeyLength) mrand.Read(symKey)