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