hash.go raw

   1  package forkhash
   2  
   3  import (
   4  	"github.com/p9c/p9/pkg/fork"
   5  	"math/big"
   6  	
   7  	skein "github.com/enceve/crypto/skein/skein256"
   8  	gost "github.com/programmer10110/gostreebog"
   9  	"golang.org/x/crypto/argon2"
  10  	"golang.org/x/crypto/blake2b"
  11  	"golang.org/x/crypto/scrypt"
  12  	"golang.org/x/crypto/sha3"
  13  	"lukechampine.com/blake3"
  14  	
  15  	"github.com/p9c/p9/pkg/chainhash"
  16  )
  17  
  18  // HashReps allows the number of multiplication/division cycles to be repeated before the final hash, on release for
  19  // mainnet this is probably set to 9 or so to raise the difficulty to a reasonable level for the hard fork. at 5
  20  // repetitions (first plus repeats, thus 4), an example block header produces a number around 48kb in byte size and
  21  // ~119000 decimal digits, which is then finally hashed down to 32 bytes
  22  var HashReps = 2
  23  
  24  // Argon2i takes bytes, generates a Blake3 hash as salt, generates an argon2i key
  25  func Argon2i(bytes []byte) []byte {
  26  	return argon2.IDKey(reverse(bytes), bytes, 1, 4*1024, 1, 32)
  27  }
  28  
  29  // Blake2b takes bytes and returns a blake2b 256 bit hash
  30  func Blake2b(bytes []byte) []byte {
  31  	b := blake2b.Sum256(bytes)
  32  	return b[:]
  33  }
  34  //
  35  // // X11 takes bytes and returns a X11 256 bit hash
  36  // func X11(bytes []byte) (out []byte) {
  37  // 	hf := x11.New()
  38  // 	out = make([]byte, 32)
  39  // 	hf.Hash(bytes, out)
  40  // 	// D.F("x11 %x", out)
  41  // 	return
  42  // 	// return cryptonight.Sum(bytes, 2)
  43  // }
  44  
  45  func reverse(b []byte) []byte {
  46  	out := make([]byte, len(b))
  47  	for i := range b {
  48  		out[i] = b[len(b)-1-i]
  49  	}
  50  	return out
  51  }
  52  
  53  // DivHash first runs an arbitrary big number calculation involving a very large integer, and hashes the result. In this
  54  // way, this hash requires both one of 9 arbitrary hash functions plus a big number long division operation and three
  55  // multiplication operations, unlikely to be satisfied on anything other than CPU and GPU, with contrary advantages on
  56  // each - GPU division is 32 bits wide operations, CPU is 64, but GPU hashes about equal to a CPU to varying degrees of
  57  // memory hardness (and CPU cache size then improves CPU performance at some hashes)
  58  //
  59  // This hash generates very large random numbers from an 80 byte block using a procedure involving two squares of
  60  // recombined spliced halves, multiplied together and then divided by the original block, reversed, repeated 4 more
  61  // times, of over 48kb to represent the product, which is hashed afterwards. ( see example in fork/scratch/divhash.go )
  62  //
  63  // This would be around half of the available level 1 cache of a ryzen 5 1600, likely distributed as 6 using the 64kb
  64  // and 3 threads using the 32kb smaller ones. Here is a block diagram of Zen architecture:
  65  // https://en.wikichip.org/w/images/thumb/0/02/zen_block_diagram.svg/1178px-zen_block_diagram.svg.png This is one, with
  66  // Zen the cores are independently partitioned. But it shows that it has one divider per core. Thus for a 6 core, 6
  67  // would be the right number to use with it as other numbers will lead to contention and memory copies. Probably its
  68  // ability to branch twice per cycle will be a big boost for its performance in this task.
  69  //
  70  // Long division units are expensive and slow, and make a perfect application specific proof of work because a
  71  // substantial part of the cost as proportional to the relative surface area of circuitry it is substantially more than
  72  // 10% of the total logic on a CPU. There is low chances of putting these units into one package with half half IDIV and
  73  // IMUL units and enough cache for each one, would be economic or accessible to most chip manufacturers at a scale and
  74  // clock that beats the CPU price.
  75  //
  76  // Most GPUs still only have 32 bit integer divide units because the type of mathematics done by GPUs is mainly based on
  77  // multiplication, addition and subtraction, specifically, with matrixes, which are per-bit equivalent to big (128-512
  78  // bit) addition, built for walking graphs and generating directional or particle effects, under gravity, and the like.
  79  // Video is very parallelisable so generally speaking GPU's main bulk of processing capability does not help here,
  80  // caches holding a fraction of the number at a time as it is computed, and only 32 bits wide at a time for the special
  81  // purpose dividers, that are relatively swamped by stream processors in big grids.
  82  //
  83  // The cheaper arithmetic units can be programmed to also perform the calculations but they are going to be funny letter
  84  // log differences to the point it adds up to less than 10% better due to complexity of the code and scheduling it.
  85  //
  86  // Long story short, this hash function should be the end of big margin ASIC mining, and a lot of R&D funds going to
  87  // improving smaller fabs for spewing out such processors.
  88  func DivHash(hf func([]byte) []byte, blockbytes []byte, howmany int) []byte {
  89  	blocklen := len(blockbytes)
  90  	rfb := reverse(blockbytes[:blocklen/2])
  91  	firsthalf := append(blockbytes, rfb...)
  92  	fhc := make([]byte, len(firsthalf))
  93  	copy(fhc, firsthalf)
  94  	secondhalf := append(blockbytes, reverse(blockbytes[blocklen/2:])...)
  95  	shc := make([]byte, len(secondhalf))
  96  	copy(shc, secondhalf)
  97  	bbb := make([]byte, len(blockbytes))
  98  	copy(bbb, blockbytes)
  99  	bl := big.NewInt(0).SetBytes(bbb)
 100  	fh := big.NewInt(0).SetBytes(fhc)
 101  	sh := big.NewInt(0).SetBytes(shc)
 102  	sqfh := fh.Mul(fh, fh)
 103  	sqsh := sh.Mul(sh, sh)
 104  	sqsq := fh.Mul(sqfh, sqsh)
 105  	divd := sqsq.Div(sqsq, bl)
 106  	divdb := divd.Bytes()
 107  	dlen := len(divdb)
 108  	ddd := make([]byte, dlen)
 109  	copy(ddd, reverse(divdb))
 110  	// this allows us run this operation an arbitrary number of times
 111  	// log.Printf("%d bytes %x\n", len(ddd), ddd)
 112  	if howmany > 0 {
 113  		return DivHash(hf, append(ddd, reverse(ddd)...), howmany-1)
 114  	}
 115  	// return X11(hf(ddd))
 116  	return hf(ddd)
 117  }
 118  
 119  // Hash computes the hash of bytes using the named hash
 120  func Hash(bytes []byte, name string, height int32) (out chainhash.Hash) {
 121  	hR := HashReps
 122  	if fork.IsTestnet {
 123  		switch {
 124  		case height == 1:
 125  			hR = 0
 126  			// case height < 10:
 127  			//	hR = 6
 128  		}
 129  	}
 130  	switch name {
 131  	case fork.Scrypt:
 132  		if fork.GetCurrent(height) > 0 {
 133  			_ = out.SetBytes(DivHash(ScryptHash, bytes, hR))
 134  		} else {
 135  			_ = out.SetBytes(ScryptHash(bytes))
 136  		}
 137  	case fork.SHA256d:
 138  		if fork.GetCurrent(height) > 0 {
 139  			_ = out.SetBytes(DivHash(chainhash.DoubleHashB, bytes, hR))
 140  		} else {
 141  			_ = out.SetBytes(
 142  				chainhash.DoubleHashB(
 143  					bytes,
 144  				),
 145  			)
 146  		}
 147  	default:
 148  		_ = out.SetBytes(DivHash(Blake3, bytes, hR))
 149  	}
 150  	return
 151  }
 152  
 153  // Keccak takes bytes and returns a keccak (sha-3) 256 bit hash
 154  func Keccak(bytes []byte) []byte {
 155  	sum := sha3.Sum256(bytes)
 156  	return sum[:]
 157  }
 158  
 159  // Blake3 takes bytes and returns a lyra2rev2 256 bit hash
 160  func Blake3(bytes []byte) []byte {
 161  	b := blake3.Sum256(bytes)
 162  	return b[:]
 163  }
 164  
 165  // ScryptHash takes bytes and returns a scrypt 256 bit hash
 166  func ScryptHash(bytes []byte) []byte {
 167  	b := bytes
 168  	c := make([]byte, len(b))
 169  	copy(c, b)
 170  	var e error
 171  	var dk []byte
 172  	dk, e = scrypt.Key(c, c, 1024, 1, 1, 32)
 173  	if e != nil {
 174  		E.Ln(e)
 175  		return make([]byte, 32)
 176  	}
 177  	o := make([]byte, 32)
 178  	for i := range dk {
 179  		o[i] = dk[len(dk)-1-i]
 180  	}
 181  	copy(o, dk)
 182  	return o
 183  }
 184  
 185  // Skein takes bytes and returns a skein 256 bit hash
 186  func Skein(bytes []byte) []byte {
 187  	var out [32]byte
 188  	skein.Sum256(&out, bytes, nil)
 189  	return out[:]
 190  }
 191  
 192  // Stribog takes bytes and returns a double GOST Stribog 256 bit hash
 193  func Stribog(bytes []byte) []byte {
 194  	return gost.Hash(bytes, "256")
 195  }
 196