Codebase list golang-github-minio-sha256-simd / cf60717
Moved AVX512 testing code to seperate test file (amd64 specific) frankw 6 years ago
2 changed file(s) with 414 addition(s) and 389 deletion(s). Raw diff Collapse all Expand all
4949 package sha256
5050
5151 import (
52 "bytes"
53 "encoding/binary"
5452 "encoding/hex"
5553 "fmt"
56 "hash"
57 "reflect"
5854 "strings"
59 "sync"
6055 "testing"
6156 )
6257
22162211 for _, g := range golden {
22172212 s := fmt.Sprintf("%x", Sum256([]byte(g.in)))
22182213 if Sum256([]byte(g.in)) != g.out {
2219 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
2214 t.Fatalf("AVX2: Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
22202215 }
22212216 }
22222217 avx2 = false
22252220 for _, g := range golden {
22262221 s := fmt.Sprintf("%x", Sum256([]byte(g.in)))
22272222 if Sum256([]byte(g.in)) != g.out {
2228 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
2223 t.Fatalf("AVX: Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
22292224 }
22302225 }
22312226 avx = false
22342229 for _, g := range golden {
22352230 s := fmt.Sprintf("%x", Sum256([]byte(g.in)))
22362231 if Sum256([]byte(g.in)) != g.out {
2237 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
2232 t.Fatalf("SSSE3: Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
22382233 }
2239 }
2240 }
2241 }
2242
2243 func TestGoldenAVX512(t *testing.T) {
2244
2245 if !avx512 {
2246 t.SkipNow()
2247 return
2248 }
2249
2250 server := NewAvx512Server()
2251 h512 := NewAvx512(server)
2252
2253 for _, g := range golden {
2254 h512.Reset()
2255 h512.Write([]byte(g.in))
2256 digest := h512.Sum([]byte{})
2257 s := fmt.Sprintf("%x", digest)
2258 if !reflect.DeepEqual(digest, g.out[:]) {
2259 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
22602234 }
22612235 }
22622236 }
22932267 func BenchmarkHash1MAvx2(b *testing.B) { benchmarkSize(b, 1024*1024) }
22942268 func BenchmarkHash5MAvx2(b *testing.B) { benchmarkSize(b, 5*1024*1024) }
22952269 func BenchmarkHash10MAvx2(b *testing.B) { benchmarkSize(b, 10*1024*1024) }
2296
2297 func createInputs(size int) [16][]byte {
2298 input := [16][]byte{}
2299 for i := 0; i < 16; i++ {
2300 input[i] = make([]byte, size)
2301 }
2302 return input
2303 }
2304
2305 func initDigests() *[512]byte {
2306 digests := [512]byte{}
2307 for i := 0; i < 16; i++ {
2308 binary.LittleEndian.PutUint32(digests[(i+0*16)*4:], init0)
2309 binary.LittleEndian.PutUint32(digests[(i+1*16)*4:], init1)
2310 binary.LittleEndian.PutUint32(digests[(i+2*16)*4:], init2)
2311 binary.LittleEndian.PutUint32(digests[(i+3*16)*4:], init3)
2312 binary.LittleEndian.PutUint32(digests[(i+4*16)*4:], init4)
2313 binary.LittleEndian.PutUint32(digests[(i+5*16)*4:], init5)
2314 binary.LittleEndian.PutUint32(digests[(i+6*16)*4:], init6)
2315 binary.LittleEndian.PutUint32(digests[(i+7*16)*4:], init7)
2316 }
2317 return &digests
2318 }
2319
2320 func testSha256Avx512(t *testing.T, offset, padding int) [16][]byte {
2321
2322 if !avx512 {
2323 t.SkipNow()
2324 return [16][]byte{}
2325 }
2326
2327 l := uint(len(golden[offset].in))
2328 extraBlock := uint(0)
2329 if padding == 0 {
2330 extraBlock += 9
2331 } else {
2332 extraBlock += 64
2333 }
2334 input := createInputs(int(l + extraBlock))
2335 for i := 0; i < 16; i++ {
2336 copy(input[i], golden[offset+i].in)
2337 input[i][l] = 0x80
2338 copy(input[i][l+1:], bytes.Repeat([]byte{0}, padding))
2339
2340 // Length in bits.
2341 len := uint64(l)
2342 len <<= 3
2343 for ii := uint(0); ii < 8; ii++ {
2344 input[i][l+1+uint(padding)+ii] = byte(len >> (56 - 8*ii))
2345 }
2346 }
2347 mask := make([]uint64, len(input[0])>>6)
2348 for m := range mask {
2349 mask[m] = 0xffff
2350 }
2351 output := blockAvx512(initDigests(), input, mask)
2352 for i := 0; i < 16; i++ {
2353 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
2354 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
2355 }
2356 }
2357 return input
2358 }
2359
2360 func TestAvx512_1Block(t *testing.T) { testSha256Avx512(t, 31, 0) }
2361 func TestAvx512_3Blocks(t *testing.T) { testSha256Avx512(t, 47, 55) }
2362
2363 func TestAvx512_MixedBlocks(t *testing.T) {
2364
2365 if !avx512 {
2366 t.SkipNow()
2367 return
2368 }
2369
2370 inputSingleBlock := testSha256Avx512(t, 31, 0)
2371 inputMultiBlock := testSha256Avx512(t, 47, 55)
2372
2373 input := [16][]byte{}
2374
2375 for i := range input {
2376 if i%2 == 0 {
2377 input[i] = inputMultiBlock[i]
2378 } else {
2379 input[i] = inputSingleBlock[i]
2380 }
2381 }
2382
2383 mask := [3]uint64{0xffff, 0x5555, 0x5555}
2384 output := blockAvx512(initDigests(), input, mask[:])
2385 var offset int
2386 for i := 0; i < len(output); i++ {
2387 if i%2 == 0 {
2388 offset = 47
2389 } else {
2390 offset = 31
2391 }
2392 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
2393 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
2394 }
2395 }
2396 }
2397
2398 func TestAvx512_MixedWithNilBlocks(t *testing.T) {
2399
2400 if !avx512 {
2401 t.SkipNow()
2402 return
2403 }
2404
2405 inputSingleBlock := testSha256Avx512(t, 31, 0)
2406 inputMultiBlock := testSha256Avx512(t, 47, 55)
2407
2408 input := [16][]byte{}
2409
2410 for i := range input {
2411 if i%3 == 0 {
2412 input[i] = inputMultiBlock[i]
2413 } else if i%3 == 1 {
2414 input[i] = inputSingleBlock[i]
2415 } else {
2416 input[i] = nil
2417 }
2418 }
2419
2420 mask := [3]uint64{0xb6db, 0x9249, 0x9249}
2421 output := blockAvx512(initDigests(), input, mask[:])
2422 var offset int
2423 for i := 0; i < len(output); i++ {
2424 if i%3 == 2 { // for nil inputs
2425 initvec := [32]byte{0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85,
2426 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a,
2427 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c,
2428 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19}
2429 if bytes.Compare(output[i][:], initvec[:]) != 0 {
2430 t.Fatalf("Sum256 function: sha256 for nil vector = %s want %s", hex.EncodeToString(output[i][:]), hex.EncodeToString(initvec[:]))
2431 }
2432 continue
2433 }
2434 if i%3 == 0 {
2435 offset = 47
2436 } else {
2437 offset = 31
2438 }
2439 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
2440 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
2441 }
2442 }
2443 }
2444
2445 func TestAvx512Server(t *testing.T) {
2446
2447 if !avx512 {
2448 t.SkipNow()
2449 return
2450 }
2451
2452 const offset = 31 + 16
2453 server := NewAvx512Server()
2454
2455 // First block of 64 bytes
2456 for i := 0; i < 16; i++ {
2457 input := make([]byte, 64)
2458 copy(input, golden[offset+i].in)
2459 server.Write(uint64(Avx512ServerUid+i), input)
2460 }
2461
2462 // Second block of 64 bytes
2463 for i := 0; i < 16; i++ {
2464 input := make([]byte, 64)
2465 copy(input, golden[offset+i].in[64:])
2466 server.Write(uint64(Avx512ServerUid+i), input)
2467 }
2468
2469 wg := sync.WaitGroup{}
2470 wg.Add(16)
2471
2472 // Third and final block
2473 for i := 0; i < 16; i++ {
2474 input := make([]byte, 64)
2475 input[0] = 0x80
2476 copy(input[1:], bytes.Repeat([]byte{0}, 63-8))
2477
2478 // Length in bits.
2479 len := uint64(128)
2480 len <<= 3
2481 for ii := uint(0); ii < 8; ii++ {
2482 input[63-8+1+ii] = byte(len >> (56 - 8*ii))
2483 }
2484 go func(i int, uid uint64, input []byte) {
2485 output := server.Sum(uid, input)
2486 if bytes.Compare(output[:], golden[offset+i].out[:]) != 0 {
2487 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[:]), hex.EncodeToString(golden[offset+i].out[:]))
2488 }
2489 wg.Done()
2490 }(i, uint64(Avx512ServerUid+i), input)
2491 }
2492
2493 wg.Wait()
2494 }
2495
2496 func TestAvx512Digest(t *testing.T) {
2497
2498 if !avx512 {
2499 t.SkipNow()
2500 return
2501 }
2502
2503 server := NewAvx512Server()
2504
2505 const tests = 16
2506 h512 := [16]hash.Hash{}
2507 for i := 0; i < tests; i++ {
2508 h512[i] = NewAvx512(server)
2509 }
2510
2511 const offset = 31 + 16
2512 for i := 0; i < tests; i++ {
2513 input := make([]byte, 64)
2514 copy(input, golden[offset+i].in)
2515 h512[i].Write(input)
2516 }
2517 for i := 0; i < tests; i++ {
2518 input := make([]byte, 64)
2519 copy(input, golden[offset+i].in[64:])
2520 h512[i].Write(input)
2521 }
2522 for i := 0; i < tests; i++ {
2523 output := h512[i].Sum([]byte{})
2524 if bytes.Compare(output[:], golden[offset+i].out[:]) != 0 {
2525 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[:]), hex.EncodeToString(golden[offset+i].out[:]))
2526 }
2527 }
2528 }
2529
2530 func benchmarkAvx512SingleCore(h512 []hash.Hash, body []byte) {
2531
2532 for i := 0; i < len(h512); i++ {
2533 h512[i].Write(body)
2534 }
2535 for i := 0; i < len(h512); i++ {
2536 _ = h512[i].Sum([]byte{})
2537 }
2538 }
2539
2540 func benchmarkAvx512(b *testing.B, size int) {
2541
2542 if !avx512 {
2543 b.SkipNow()
2544 return
2545 }
2546
2547 server := NewAvx512Server()
2548
2549 const tests = 16
2550 body := make([]byte, size)
2551
2552 b.SetBytes(int64(len(body) * tests))
2553 b.ResetTimer()
2554
2555 for i := 0; i < b.N; i++ {
2556 h512 := make([]hash.Hash, tests)
2557 for i := 0; i < tests; i++ {
2558 h512[i] = NewAvx512(server)
2559 }
2560
2561 benchmarkAvx512SingleCore(h512, body)
2562 }
2563 }
2564
2565 func BenchmarkAvx512_05M(b *testing.B) { benchmarkAvx512(b, 512*1024) }
2566 func BenchmarkAvx512_1M(b *testing.B) { benchmarkAvx512(b, 1*1024*1024) }
2567 func BenchmarkAvx512_5M(b *testing.B) { benchmarkAvx512(b, 5*1024*1024) }
2568 func BenchmarkAvx512_10M(b *testing.B) { benchmarkAvx512(b, 10*1024*1024) }
2569
2570 func benchmarkAvx512MultiCore(b *testing.B, size, cores int) {
2571
2572 if !avx512 {
2573 b.SkipNow()
2574 return
2575 }
2576
2577 servers := make([]*Avx512Server, cores)
2578 for c := 0; c < cores; c++ {
2579 servers[c] = NewAvx512Server()
2580 }
2581
2582 const tests = 16
2583
2584 body := make([]byte, size)
2585
2586 h512 := make([]hash.Hash, tests*cores)
2587 for i := 0; i < tests*cores; i++ {
2588 h512[i] = NewAvx512(servers[i>>4])
2589 }
2590
2591 b.SetBytes(int64(size * 16 * cores))
2592 b.ResetTimer()
2593
2594 var wg sync.WaitGroup
2595
2596 for i := 0; i < b.N; i++ {
2597 wg.Add(cores)
2598 for c := 0; c < cores; c++ {
2599 go func(c int) { benchmarkAvx512SingleCore(h512[c*tests:(c+1)*tests], body); wg.Done() }(c)
2600 }
2601 wg.Wait()
2602 }
2603 }
2604
2605 func BenchmarkAvx512_5M_2Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 2) }
2606 func BenchmarkAvx512_5M_4Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 4) }
2607 func BenchmarkAvx512_5M_6Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 6) }
2608
2609 type maskTest struct {
2610 in [16]int
2611 out [16]maskRounds
2612 }
2613
2614 var goldenMask = []maskTest{
2615 {[16]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [16]maskRounds{}},
2616 {[16]int{64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0}, [16]maskRounds{{0x5555, 1}}},
2617 {[16]int{0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64}, [16]maskRounds{{0xaaaa, 1}}},
2618 {[16]int{64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, [16]maskRounds{{0xffff, 1}}},
2619 {[16]int{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, [16]maskRounds{{0xffff, 2}}},
2620 {[16]int{64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128}, [16]maskRounds{{0xffff, 1}, {0xaaaa, 1}}},
2621 {[16]int{128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64}, [16]maskRounds{{0xffff, 1}, {0x5555, 1}}},
2622 {[16]int{64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192}, [16]maskRounds{{0xffff, 1}, {0xaaaa, 2}}},
2623 //
2624 // >= 64 0110=6 1011=b 1101=d 0110=6
2625 // >=128 0100=4 0010=2 1001=9 0100=4
2626 {[16]int{0, 64, 128, 0, 64, 128, 0, 64, 128, 0, 64, 128, 0, 64, 128, 0}, [16]maskRounds{{0x6db6, 1}, {0x4924, 1}}},
2627 {[16]int{1 * 64, 2 * 64, 3 * 64, 4 * 64, 5 * 64, 6 * 64, 7 * 64, 8 * 64, 9 * 64, 10 * 64, 11 * 64, 12 * 64, 13 * 64, 14 * 64, 15 * 64, 16 * 64},
2628 [16]maskRounds{{0xffff, 1}, {0xfffe, 1}, {0xfffc, 1}, {0xfff8, 1}, {0xfff0, 1}, {0xffe0, 1}, {0xffc0, 1}, {0xff80, 1},
2629 {0xff00, 1}, {0xfe00, 1}, {0xfc00, 1}, {0xf800, 1}, {0xf000, 1}, {0xe000, 1}, {0xc000, 1}, {0x8000, 1}}},
2630 {[16]int{2 * 64, 1 * 64, 3 * 64, 4 * 64, 5 * 64, 6 * 64, 7 * 64, 8 * 64, 9 * 64, 10 * 64, 11 * 64, 12 * 64, 13 * 64, 14 * 64, 15 * 64, 16 * 64},
2631 [16]maskRounds{{0xffff, 1}, {0xfffd, 1}, {0xfffc, 1}, {0xfff8, 1}, {0xfff0, 1}, {0xffe0, 1}, {0xffc0, 1}, {0xff80, 1},
2632 {0xff00, 1}, {0xfe00, 1}, {0xfc00, 1}, {0xf800, 1}, {0xf000, 1}, {0xe000, 1}, {0xc000, 1}, {0x8000, 1}}},
2633 {[16]int{10 * 64, 20 * 64, 30 * 64, 40 * 64, 50 * 64, 60 * 64, 70 * 64, 80 * 64, 90 * 64, 100 * 64, 110 * 64, 120 * 64, 130 * 64, 140 * 64, 150 * 64, 160 * 64},
2634 [16]maskRounds{{0xffff, 10}, {0xfffe, 10}, {0xfffc, 10}, {0xfff8, 10}, {0xfff0, 10}, {0xffe0, 10}, {0xffc0, 10}, {0xff80, 10},
2635 {0xff00, 10}, {0xfe00, 10}, {0xfc00, 10}, {0xf800, 10}, {0xf000, 10}, {0xe000, 10}, {0xc000, 10}, {0x8000, 10}}},
2636 {[16]int{10 * 64, 19 * 64, 27 * 64, 34 * 64, 40 * 64, 45 * 64, 49 * 64, 52 * 64, 54 * 64, 55 * 64, 57 * 64, 60 * 64, 64 * 64, 69 * 64, 75 * 64, 82 * 64},
2637 [16]maskRounds{{0xffff, 10}, {0xfffe, 9}, {0xfffc, 8}, {0xfff8, 7}, {0xfff0, 6}, {0xffe0, 5}, {0xffc0, 4}, {0xff80, 3},
2638 {0xff00, 2}, {0xfe00, 1}, {0xfc00, 2}, {0xf800, 3}, {0xf000, 4}, {0xe000, 5}, {0xc000, 6}, {0x8000, 7}}},
2639 }
2640
2641 func TestMaskGen(t *testing.T) {
2642 input := [16][]byte{}
2643 for gcase, g := range goldenMask {
2644 for i, l := range g.in {
2645 buf := make([]byte, l)
2646 input[i] = buf[:]
2647 }
2648
2649 mr := genMask(input)
2650
2651 if !reflect.DeepEqual(mr, g.out) {
2652 t.Fatalf("case %d: got %04x\n want %04x", gcase, mr, g.out)
2653 }
2654 }
2655 }
0 /*
1 * Minio Cloud Storage, (C) 2017 Minio, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 // +build amd64
17
18 package sha256
19
20 import (
21 "bytes"
22 "encoding/binary"
23 "encoding/hex"
24 "fmt"
25 "hash"
26 "reflect"
27 "sync"
28 "testing"
29 )
30
31 func TestGoldenAVX512(t *testing.T) {
32
33 if !avx512 {
34 t.SkipNow()
35 return
36 }
37
38 server := NewAvx512Server()
39 h512 := NewAvx512(server)
40
41 for _, g := range golden {
42 h512.Reset()
43 h512.Write([]byte(g.in))
44 digest := h512.Sum([]byte{})
45 s := fmt.Sprintf("%x", digest)
46 if !reflect.DeepEqual(digest, g.out[:]) {
47 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, hex.EncodeToString(g.out[:]))
48 }
49 }
50 }
51
52 func createInputs(size int) [16][]byte {
53 input := [16][]byte{}
54 for i := 0; i < 16; i++ {
55 input[i] = make([]byte, size)
56 }
57 return input
58 }
59
60 func initDigests() *[512]byte {
61 digests := [512]byte{}
62 for i := 0; i < 16; i++ {
63 binary.LittleEndian.PutUint32(digests[(i+0*16)*4:], init0)
64 binary.LittleEndian.PutUint32(digests[(i+1*16)*4:], init1)
65 binary.LittleEndian.PutUint32(digests[(i+2*16)*4:], init2)
66 binary.LittleEndian.PutUint32(digests[(i+3*16)*4:], init3)
67 binary.LittleEndian.PutUint32(digests[(i+4*16)*4:], init4)
68 binary.LittleEndian.PutUint32(digests[(i+5*16)*4:], init5)
69 binary.LittleEndian.PutUint32(digests[(i+6*16)*4:], init6)
70 binary.LittleEndian.PutUint32(digests[(i+7*16)*4:], init7)
71 }
72 return &digests
73 }
74
75 func testSha256Avx512(t *testing.T, offset, padding int) [16][]byte {
76
77 if !avx512 {
78 t.SkipNow()
79 return [16][]byte{}
80 }
81
82 l := uint(len(golden[offset].in))
83 extraBlock := uint(0)
84 if padding == 0 {
85 extraBlock += 9
86 } else {
87 extraBlock += 64
88 }
89 input := createInputs(int(l + extraBlock))
90 for i := 0; i < 16; i++ {
91 copy(input[i], golden[offset+i].in)
92 input[i][l] = 0x80
93 copy(input[i][l+1:], bytes.Repeat([]byte{0}, padding))
94
95 // Length in bits.
96 len := uint64(l)
97 len <<= 3
98 for ii := uint(0); ii < 8; ii++ {
99 input[i][l+1+uint(padding)+ii] = byte(len >> (56 - 8*ii))
100 }
101 }
102 mask := make([]uint64, len(input[0])>>6)
103 for m := range mask {
104 mask[m] = 0xffff
105 }
106 output := blockAvx512(initDigests(), input, mask)
107 for i := 0; i < 16; i++ {
108 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
109 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
110 }
111 }
112 return input
113 }
114
115 func TestAvx512_1Block(t *testing.T) { testSha256Avx512(t, 31, 0) }
116 func TestAvx512_3Blocks(t *testing.T) { testSha256Avx512(t, 47, 55) }
117
118 func TestAvx512_MixedBlocks(t *testing.T) {
119
120 if !avx512 {
121 t.SkipNow()
122 return
123 }
124
125 inputSingleBlock := testSha256Avx512(t, 31, 0)
126 inputMultiBlock := testSha256Avx512(t, 47, 55)
127
128 input := [16][]byte{}
129
130 for i := range input {
131 if i%2 == 0 {
132 input[i] = inputMultiBlock[i]
133 } else {
134 input[i] = inputSingleBlock[i]
135 }
136 }
137
138 mask := [3]uint64{0xffff, 0x5555, 0x5555}
139 output := blockAvx512(initDigests(), input, mask[:])
140 var offset int
141 for i := 0; i < len(output); i++ {
142 if i%2 == 0 {
143 offset = 47
144 } else {
145 offset = 31
146 }
147 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
148 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
149 }
150 }
151 }
152
153 func TestAvx512_MixedWithNilBlocks(t *testing.T) {
154
155 if !avx512 {
156 t.SkipNow()
157 return
158 }
159
160 inputSingleBlock := testSha256Avx512(t, 31, 0)
161 inputMultiBlock := testSha256Avx512(t, 47, 55)
162
163 input := [16][]byte{}
164
165 for i := range input {
166 if i%3 == 0 {
167 input[i] = inputMultiBlock[i]
168 } else if i%3 == 1 {
169 input[i] = inputSingleBlock[i]
170 } else {
171 input[i] = nil
172 }
173 }
174
175 mask := [3]uint64{0xb6db, 0x9249, 0x9249}
176 output := blockAvx512(initDigests(), input, mask[:])
177 var offset int
178 for i := 0; i < len(output); i++ {
179 if i%3 == 2 { // for nil inputs
180 initvec := [32]byte{0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85,
181 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a,
182 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c,
183 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19}
184 if bytes.Compare(output[i][:], initvec[:]) != 0 {
185 t.Fatalf("Sum256 function: sha256 for nil vector = %s want %s", hex.EncodeToString(output[i][:]), hex.EncodeToString(initvec[:]))
186 }
187 continue
188 }
189 if i%3 == 0 {
190 offset = 47
191 } else {
192 offset = 31
193 }
194 if bytes.Compare(output[i][:], golden[offset+i].out[:]) != 0 {
195 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[i][:]), hex.EncodeToString(golden[offset+i].out[:]))
196 }
197 }
198 }
199
200 func TestAvx512Server(t *testing.T) {
201
202 if !avx512 {
203 t.SkipNow()
204 return
205 }
206
207 const offset = 31 + 16
208 server := NewAvx512Server()
209
210 // First block of 64 bytes
211 for i := 0; i < 16; i++ {
212 input := make([]byte, 64)
213 copy(input, golden[offset+i].in)
214 server.Write(uint64(Avx512ServerUid+i), input)
215 }
216
217 // Second block of 64 bytes
218 for i := 0; i < 16; i++ {
219 input := make([]byte, 64)
220 copy(input, golden[offset+i].in[64:])
221 server.Write(uint64(Avx512ServerUid+i), input)
222 }
223
224 wg := sync.WaitGroup{}
225 wg.Add(16)
226
227 // Third and final block
228 for i := 0; i < 16; i++ {
229 input := make([]byte, 64)
230 input[0] = 0x80
231 copy(input[1:], bytes.Repeat([]byte{0}, 63-8))
232
233 // Length in bits.
234 len := uint64(128)
235 len <<= 3
236 for ii := uint(0); ii < 8; ii++ {
237 input[63-8+1+ii] = byte(len >> (56 - 8*ii))
238 }
239 go func(i int, uid uint64, input []byte) {
240 output := server.Sum(uid, input)
241 if bytes.Compare(output[:], golden[offset+i].out[:]) != 0 {
242 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[:]), hex.EncodeToString(golden[offset+i].out[:]))
243 }
244 wg.Done()
245 }(i, uint64(Avx512ServerUid+i), input)
246 }
247
248 wg.Wait()
249 }
250
251 func TestAvx512Digest(t *testing.T) {
252
253 if !avx512 {
254 t.SkipNow()
255 return
256 }
257
258 server := NewAvx512Server()
259
260 const tests = 16
261 h512 := [16]hash.Hash{}
262 for i := 0; i < tests; i++ {
263 h512[i] = NewAvx512(server)
264 }
265
266 const offset = 31 + 16
267 for i := 0; i < tests; i++ {
268 input := make([]byte, 64)
269 copy(input, golden[offset+i].in)
270 h512[i].Write(input)
271 }
272 for i := 0; i < tests; i++ {
273 input := make([]byte, 64)
274 copy(input, golden[offset+i].in[64:])
275 h512[i].Write(input)
276 }
277 for i := 0; i < tests; i++ {
278 output := h512[i].Sum([]byte{})
279 if bytes.Compare(output[:], golden[offset+i].out[:]) != 0 {
280 t.Fatalf("Sum256 function: sha256(%s) = %s want %s", golden[offset+i].in, hex.EncodeToString(output[:]), hex.EncodeToString(golden[offset+i].out[:]))
281 }
282 }
283 }
284
285 func benchmarkAvx512SingleCore(h512 []hash.Hash, body []byte) {
286
287 for i := 0; i < len(h512); i++ {
288 h512[i].Write(body)
289 }
290 for i := 0; i < len(h512); i++ {
291 _ = h512[i].Sum([]byte{})
292 }
293 }
294
295 func benchmarkAvx512(b *testing.B, size int) {
296
297 if !avx512 {
298 b.SkipNow()
299 return
300 }
301
302 server := NewAvx512Server()
303
304 const tests = 16
305 body := make([]byte, size)
306
307 b.SetBytes(int64(len(body) * tests))
308 b.ResetTimer()
309
310 for i := 0; i < b.N; i++ {
311 h512 := make([]hash.Hash, tests)
312 for i := 0; i < tests; i++ {
313 h512[i] = NewAvx512(server)
314 }
315
316 benchmarkAvx512SingleCore(h512, body)
317 }
318 }
319
320 func BenchmarkAvx512_05M(b *testing.B) { benchmarkAvx512(b, 512*1024) }
321 func BenchmarkAvx512_1M(b *testing.B) { benchmarkAvx512(b, 1*1024*1024) }
322 func BenchmarkAvx512_5M(b *testing.B) { benchmarkAvx512(b, 5*1024*1024) }
323 func BenchmarkAvx512_10M(b *testing.B) { benchmarkAvx512(b, 10*1024*1024) }
324
325 func benchmarkAvx512MultiCore(b *testing.B, size, cores int) {
326
327 if !avx512 {
328 b.SkipNow()
329 return
330 }
331
332 servers := make([]*Avx512Server, cores)
333 for c := 0; c < cores; c++ {
334 servers[c] = NewAvx512Server()
335 }
336
337 const tests = 16
338
339 body := make([]byte, size)
340
341 h512 := make([]hash.Hash, tests*cores)
342 for i := 0; i < tests*cores; i++ {
343 h512[i] = NewAvx512(servers[i>>4])
344 }
345
346 b.SetBytes(int64(size * 16 * cores))
347 b.ResetTimer()
348
349 var wg sync.WaitGroup
350
351 for i := 0; i < b.N; i++ {
352 wg.Add(cores)
353 for c := 0; c < cores; c++ {
354 go func(c int) { benchmarkAvx512SingleCore(h512[c*tests:(c+1)*tests], body); wg.Done() }(c)
355 }
356 wg.Wait()
357 }
358 }
359
360 func BenchmarkAvx512_5M_2Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 2) }
361 func BenchmarkAvx512_5M_4Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 4) }
362 func BenchmarkAvx512_5M_6Cores(b *testing.B) { benchmarkAvx512MultiCore(b, 5*1024*1024, 6) }
363
364 type maskTest struct {
365 in [16]int
366 out [16]maskRounds
367 }
368
369 var goldenMask = []maskTest{
370 {[16]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [16]maskRounds{}},
371 {[16]int{64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0}, [16]maskRounds{{0x5555, 1}}},
372 {[16]int{0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64}, [16]maskRounds{{0xaaaa, 1}}},
373 {[16]int{64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, [16]maskRounds{{0xffff, 1}}},
374 {[16]int{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, [16]maskRounds{{0xffff, 2}}},
375 {[16]int{64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128}, [16]maskRounds{{0xffff, 1}, {0xaaaa, 1}}},
376 {[16]int{128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64, 128, 64}, [16]maskRounds{{0xffff, 1}, {0x5555, 1}}},
377 {[16]int{64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192, 64, 192}, [16]maskRounds{{0xffff, 1}, {0xaaaa, 2}}},
378 //
379 // >= 64 0110=6 1011=b 1101=d 0110=6
380 // >=128 0100=4 0010=2 1001=9 0100=4
381 {[16]int{0, 64, 128, 0, 64, 128, 0, 64, 128, 0, 64, 128, 0, 64, 128, 0}, [16]maskRounds{{0x6db6, 1}, {0x4924, 1}}},
382 {[16]int{1 * 64, 2 * 64, 3 * 64, 4 * 64, 5 * 64, 6 * 64, 7 * 64, 8 * 64, 9 * 64, 10 * 64, 11 * 64, 12 * 64, 13 * 64, 14 * 64, 15 * 64, 16 * 64},
383 [16]maskRounds{{0xffff, 1}, {0xfffe, 1}, {0xfffc, 1}, {0xfff8, 1}, {0xfff0, 1}, {0xffe0, 1}, {0xffc0, 1}, {0xff80, 1},
384 {0xff00, 1}, {0xfe00, 1}, {0xfc00, 1}, {0xf800, 1}, {0xf000, 1}, {0xe000, 1}, {0xc000, 1}, {0x8000, 1}}},
385 {[16]int{2 * 64, 1 * 64, 3 * 64, 4 * 64, 5 * 64, 6 * 64, 7 * 64, 8 * 64, 9 * 64, 10 * 64, 11 * 64, 12 * 64, 13 * 64, 14 * 64, 15 * 64, 16 * 64},
386 [16]maskRounds{{0xffff, 1}, {0xfffd, 1}, {0xfffc, 1}, {0xfff8, 1}, {0xfff0, 1}, {0xffe0, 1}, {0xffc0, 1}, {0xff80, 1},
387 {0xff00, 1}, {0xfe00, 1}, {0xfc00, 1}, {0xf800, 1}, {0xf000, 1}, {0xe000, 1}, {0xc000, 1}, {0x8000, 1}}},
388 {[16]int{10 * 64, 20 * 64, 30 * 64, 40 * 64, 50 * 64, 60 * 64, 70 * 64, 80 * 64, 90 * 64, 100 * 64, 110 * 64, 120 * 64, 130 * 64, 140 * 64, 150 * 64, 160 * 64},
389 [16]maskRounds{{0xffff, 10}, {0xfffe, 10}, {0xfffc, 10}, {0xfff8, 10}, {0xfff0, 10}, {0xffe0, 10}, {0xffc0, 10}, {0xff80, 10},
390 {0xff00, 10}, {0xfe00, 10}, {0xfc00, 10}, {0xf800, 10}, {0xf000, 10}, {0xe000, 10}, {0xc000, 10}, {0x8000, 10}}},
391 {[16]int{10 * 64, 19 * 64, 27 * 64, 34 * 64, 40 * 64, 45 * 64, 49 * 64, 52 * 64, 54 * 64, 55 * 64, 57 * 64, 60 * 64, 64 * 64, 69 * 64, 75 * 64, 82 * 64},
392 [16]maskRounds{{0xffff, 10}, {0xfffe, 9}, {0xfffc, 8}, {0xfff8, 7}, {0xfff0, 6}, {0xffe0, 5}, {0xffc0, 4}, {0xff80, 3},
393 {0xff00, 2}, {0xfe00, 1}, {0xfc00, 2}, {0xf800, 3}, {0xf000, 4}, {0xe000, 5}, {0xc000, 6}, {0x8000, 7}}},
394 }
395
396 func TestMaskGen(t *testing.T) {
397 input := [16][]byte{}
398 for gcase, g := range goldenMask {
399 for i, l := range g.in {
400 buf := make([]byte, l)
401 input[i] = buf[:]
402 }
403
404 mr := genMask(input)
405
406 if !reflect.DeepEqual(mr, g.out) {
407 t.Fatalf("case %d: got %04x\n want %04x", gcase, mr, g.out)
408 }
409 }
410 }