github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/cryptonight/cryptonightv7.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package cryptonight 18 19 //import "fmt" 20 import "unsafe" 21 22 import "encoding/binary" 23 import "github.com/aead/skein" 24 import "github.com/dchest/blake256" 25 26 // see this commit https://github.com/monero-project/monero/commit/e136bc6b8a480426f7565b721ca2ccf75547af62#diff-7000dc02c792439471da62856f839d62 27 func cryptonightv7(input []byte, variant int) []byte { 28 29 var dummy [256]byte 30 var S [25]uint64 31 32 var key1 [64]uint32 33 var key2 [64]uint32 34 35 var a [2]uint64 36 var b [2]uint64 37 var c [2]uint64 38 39 nonce64 := VARIANT1_INIT64(variant, input) // init variant 1 40 41 a_uint32 := (*(*[4]uint32)(unsafe.Pointer(&a[0])))[:len(a)*2] 42 //b_uint32 := (*(*[4]uint32)(unsafe.Pointer(&b[0])))[:len(b)*2] 43 c_uint32 := (*(*[4]uint32)(unsafe.Pointer(&c[0])))[:len(c)*2] 44 45 // same array is accessed as 3 different ways, buts it bettter than copying 46 var ScratchPad = make([]uint64, 1<<18, 1<<18) 47 ScratchPad_uint32 := (*(*[MAX_ARRAY_LIMIT]uint32)(unsafe.Pointer(&ScratchPad[0])))[:len(ScratchPad)*2] 48 // ScratchPad_byte := (*(*[MAX_ARRAY_LIMIT]byte)(unsafe.Pointer(&ScratchPad[0])))[:len(ScratchPad)*8] 49 50 copy(dummy[:], input) 51 52 for i := 0; i < 16; i++ { 53 S[i] = binary.LittleEndian.Uint64(dummy[i<<3:]) 54 } 55 S[16] = 0x8000000000000000 56 57 keccakf(&S) 58 59 // lets convert everything back to bytes 60 for i := 0; i < 25; i++ { 61 binary.LittleEndian.PutUint64(dummy[i<<3:], S[i]) 62 } 63 64 // extract keys 65 /*for i := 0 ; i <8;i++{ 66 key1[i] = binary.LittleEndian.Uint32(dummy[i<<2:]) 67 key2[i] = binary.LittleEndian.Uint32(dummy[32+(i<<2):]) 68 }*/ 69 70 expandKeyGo(dummy[0:32], key1[:], nil) 71 expandKeyGo(dummy[32:64], key2[:], nil) 72 73 /* for i :=0; i< 60;i++{ 74 fmt.Printf("%2d %X\n", i, key2[i]) 75 }*/ 76 77 // var text [128]byte 78 var text_uint32 [32]uint32 79 //copy(text[:],dummy[64:64+128]) // copy 128 bytes 80 81 for i := 0; i < 32; i++ { 82 text_uint32[i] = binary.LittleEndian.Uint32(dummy[64+(i<<2):]) 83 } 84 85 tweak_12 := binary.LittleEndian.Uint64(dummy[192:]) ^ nonce64 // v7 tweak 86 87 /* for i :=0; i< 32;i++{ 88 fmt.Printf("%2d %X i %08X %08X\n", i, text_uint32[i] , key1[i],key1[i<<1]) 89 }*/ 90 91 for i := 0; i < 0x4000; i++ { 92 for j := 0; j < 8; j++ { 93 CNAESTransform((text_uint32[(j << 2):]), key1[:]) 94 } 95 96 //memcpy(CNCtx.Scratchpad + (i << 4), text, 128); 97 copy(ScratchPad_uint32[i*32:], text_uint32[:]) 98 } 99 100 a[0] = S[0] ^ S[4] 101 a[1] = S[1] ^ S[5] 102 b[0] = S[2] ^ S[6] 103 b[1] = S[3] ^ S[7] 104 105 var variant1_scratch [16]byte 106 // the big slow round 107 for i := 0; i < 0x80000; i++ { 108 // { 109 c[0] = ScratchPad[((a[0]&0x1FFFF0)>>3)+0] 110 c[1] = ScratchPad[((a[0]&0x1FFFF0)>>3)+1] 111 112 CNAESRnd(c_uint32, a_uint32) 113 114 b[0] ^= c[0] 115 b[1] ^= c[1] 116 117 // TODO optimize it 118 // 1 patch comes here VARIANT1_1 119 if variant > 0 { 120 /// binary.LittleEndian.PutUint64(variant1_scratch[:],b[0]) 121 binary.LittleEndian.PutUint64(variant1_scratch[8:], b[1]) 122 /* // unoptimisez original version 123 * tmp := variant1_scratch[11] 124 tmp1 := (tmp>>4)&1 125 tmp2 := (tmp>>5)&1 126 tmp3 := tmp1^tmp2; 127 tmp0 := tmp3 128 if (tmp & 1) == 1 { 129 tmp0 = tmp3 130 }else{ 131 tmp0 = ((((tmp2<<1)|tmp1) + 1)&3) 132 } 133 134 if (tmp & 1) == 1{ 135 variant1_scratch[11] = ((tmp & 0xef) | (tmp0<<4)) 136 }else{ 137 variant1_scratch[11] = ((tmp & 0xcf) | (tmp0<<4)) 138 } 139 */ 140 tmp := variant1_scratch[11] 141 table := uint32(0x75310) 142 143 index := (((tmp >> 3) & 6) | (tmp & 1)) << 1 144 variant1_scratch[11] = tmp ^ (byte(table>>index) & 0x30) 145 146 //ScratchPad[((a[0]&0x1FFFF0)>>3)+0] = binary.LittleEndian.Uint64(variant1_scratch[:]) 147 ScratchPad[((a[0]&0x1FFFF0)>>3)+0] = b[0] 148 ScratchPad[((a[0]&0x1FFFF0)>>3)+1] = binary.LittleEndian.Uint64(variant1_scratch[8:]) 149 150 } else { 151 152 ScratchPad[((a[0]&0x1FFFF0)>>3)+0] = b[0] 153 ScratchPad[((a[0]&0x1FFFF0)>>3)+1] = b[1] 154 } 155 156 b[0] = ScratchPad[((c[0]&0x1FFFF0)>>3)+0] 157 b[1] = ScratchPad[((c[0]&0x1FFFF0)>>3)+1] 158 159 // time to do 64 bit * 64 bit multiply 160 var lower64, upper64 uint64 161 { 162 163 x := c[0] 164 y := b[0] 165 166 a := x >> 32 167 b := x & 0xffffffff 168 c := y >> 32 169 d := y & 0xffffffff 170 171 ac := a * c 172 bc := b * c 173 ad := a * d 174 bd := b * d 175 176 mid34 := (bd >> 32) + (bc & 0xffffffff) + (ad & 0xffffffff) 177 178 upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32) 179 lower64 = (mid34 << 32) | (bd & 0xffffffff) 180 _ = lower64 181 _ = upper64 182 183 } 184 185 a[1] += lower64 186 a[0] += upper64 187 188 ScratchPad[((c[0]&0x1FFFF0)>>3)+0] = a[0] 189 ScratchPad[((c[0]&0x1FFFF0)>>3)+1] = a[1] 190 191 // v2 patch comes here VARIANT1_2 192 if variant > 0 { 193 // 3rd uint32 ( based on pointer) needs to be xored with nonce 194 //ScratchPad[((c[0]&0x1FFFF0)>>3)+1] = (a[1] ^ nonce64)&0xffffffff| (a[1]>>32)<<32 // use last 4 bytes 195 //_ = nonce64 196 ScratchPad[((c[0]&0x1FFFF0)>>3)+1] = a[1] ^ tweak_12 197 } 198 199 a[0] ^= b[0] 200 a[1] ^= b[1] 201 202 b[0] = c[0] 203 b[1] = c[1] 204 205 } 206 207 // fmt.Printf(" a %X %X\n", a[0],a[1]); 208 // fmt.Printf(" b %X %X\n", b[0],b[1]); 209 210 for i := 0; i < 32; i++ { 211 text_uint32[i] = binary.LittleEndian.Uint32(dummy[64+(i<<2):]) 212 } 213 214 for i := 0; i < 0x4000; i++ { 215 216 for j := 0; j < 32; j++ { 217 text_uint32[j] ^= ScratchPad_uint32[(i*32)+j] 218 219 } 220 for j := 0; j < 8; j++ { 221 CNAESTransform((text_uint32[(j << 2):]), key2[:]) 222 } 223 224 } 225 226 /*for i :=0; i< 32;i++{ 227 fmt.Printf("%2d %X\n", i, text_uint32[i]) 228 }*/ 229 230 for i := 0; i < 32; i++ { 231 binary.LittleEndian.PutUint32(dummy[64+(i<<2):], text_uint32[i]) 232 } 233 234 for i := 8; i < 25; i++ { 235 S[i] = binary.LittleEndian.Uint64(dummy[i<<3:]) 236 } 237 238 keccakf(&S) // do the keccak round 239 /* for i :=0; i< 25;i++{ 240 fmt.Printf("S %02d %X\n", i, S[i]) 241 }*/ 242 243 // lets convert everything back to bytes 244 for i := 0; i < 25; i++ { 245 binary.LittleEndian.PutUint64(dummy[i<<3:], S[i]) 246 } 247 248 var resulthash []byte 249 250 switch S[0] & 3 { 251 252 case 0: 253 // fmt.Printf("blake\n") 254 255 // blake 256 blakehash := blake256.New() 257 blakehash.Write(dummy[:200]) 258 resulthash = blakehash.Sum(nil) //matching 259 260 case 1: // groestl 261 // fmt.Printf("groestl not implemented\n") 262 var output [32]byte 263 var input = dummy[:200] 264 crypto_hash(output[:], input, uint64(len(input))) 265 resulthash = output[:] 266 case 2: // jh 267 //fmt.Printf("jh not implemented\n") 268 269 myjhash := NewJhash256() 270 myjhash.Write(dummy[:200]) 271 resulthash = myjhash.Sum(nil) 272 273 case 3: // skein 274 // fmt.Printf("skein\n") 275 skeinhash := skein.New256(nil) 276 skeinhash.Write(dummy[:200]) 277 resulthash = skeinhash.Sum(nil) //matchin 278 279 } 280 281 //fmt.Printf("result hash %x\n", resulthash) 282 283 return resulthash 284 285 } 286 287 func SlowHashv7(msg []byte) []byte { 288 289 hash := cryptonightv7(append(msg, byte(0x01)), 1) 290 // hash := cryptonight(msg) 291 return hash 292 293 } 294 295 func VARIANT1_INIT64(variant int, data []byte) (nonce uint64) { 296 if variant > 0 && len(data) < 43 { 297 panic("Cryptonight variants need at least 43 bytes of data") 298 } 299 300 if variant > 0 { 301 nonce = binary.LittleEndian.Uint64(data[35:]) 302 } 303 304 return 305 }