-1

I generated a hash value using sha3 and I need to convert it to a big.Int value. Is it possible ? or is there a method to get the integervalue of the hash ?

the following code throws an error that cannot convert type hash.Hash to type int64 :

package main 

import (
"math/big"
"golang.org/x/crypto/sha3"
"fmt"

)
func main(){

  chall := "hello word"
  b := byte[](chall)
  h := sha3.New244()
  h.Write(chall)
  h.Write(b)
  d := make([]byte, 16)
  h.Sum(d)
  val := big.NewInt(int64(h))
  fmt.Println(val)

}


enimert
  • 49
  • 1
  • 7
  • 1
    What do you consider the "integer value" of 28 bytes? – Volker May 20 '21 at 12:52
  • can you add clarity to your question. Do you want to save the state of the hash - or just its sum? As @Volker mentioned the `224` (bit) hash - is way too big to fit into 64 bits. – colm.anseo May 20 '21 at 16:47

2 Answers2

2

TL;DR;

sha3.New224() cannot be represented in uint64 type.


There are many hash types - and of differing sizes. Go standard library picks a very generic interface to cover all type of hashes: https://golang.org/pkg/hash/#Hash

type Hash interface {
    io.Writer
    Sum(b []byte) []byte
    Reset()
    Size() int
    BlockSize() int
}

Having said that some Go hash implementations optionally include extra methods like hash.Hash64:

type Hash64 interface {
    Hash
    Sum64() uint64
}

others may implement encoding.BinaryMarshaler:

type BinaryMarshaler interface {
    MarshalBinary() (data []byte, err error)
}

which one can use to preserve a hash state.

sha3.New224() does not implement the above 2 interfaces, but crc64 hash does. To do a runtime check:

h64, ok := h.(hash.Hash64)
if ok {
    fmt.Printf("64-bit: %d\n", h64.Sum64())
}

Working example: https://play.golang.org/p/uLUfw0gMZka

colm.anseo
  • 19,337
  • 4
  • 43
  • 52
0

(See Peter's comment for the simpler version of this.)

Interpreting a series of bytes as a big.Int is the same as interpreting a series of decimal digits as an arbitrarily large number. For example, to convert the digits 1234 into a "number", you'd do this:

  • Start with 0
  • Multiply by 10 = 0
  • Add 1 = 1
  • Multiply by 10 = 10
  • Add 2 = 12
  • Multiply by 10 = 120
  • Add 3 = 123
  • Multiply by 10 = 1230
  • Add 4 = 1234

The same applies to bytes. The "digits" are just base-256 rather than base-10:

val := big.NewInt(0)
for i := 0; i < h.Size(); i++ {
    val.Lsh(val, 8)
    val.Add(val, big.NewInt(int64(d[i])))
}

(Lsh is a left-shift. Left shifting by 8 bits is the same as multiplying by 256.)

Playground

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 5
    This should be the same as `val := new(big.Int).SetBytes(d)`. ["SetBytes interprets buf as the bytes of a big-endian unsigned integer."](https://golang.org/pkg/math/big/#Int.SetBytes) – Peter May 20 '21 at 15:33
  • @Peter hahaha; yes. I had assumed there was such a method and just couldn't find it (I kept expecting it to be under the New functions rather than a Set function). Thank you. Can you post this as an answer? – Rob Napier May 20 '21 at 15:55
  • 1
    Your (and Peters) solution is correct iff the bytes of the hash should be interpreted as big-endian unsigned. Litte-endian or signed (in two's complement or any other) or any other interpretation of that bit pattern (e.g. using the popcount as the value) would lead to a different value. – Volker May 21 '21 at 05:32