package md5x16 import ( "crypto/md5" "encoding/hex" "math/rand" "testing" "testing/quick" "golang.org/x/sys/cpu" ) func RequireISA(t *testing.T) { t.Helper() if !cpu.X86.HasAVX512F { t.Skip("requires AVX512F instruction set") } } func TestVectors(t *testing.T) { RequireISA(t) cases := []struct { Data string HexDigest string }{ {"", "d41d8cd98f00b204e9800998ecf8427e"}, {"The quick brown fox jumps over the lazy dog", "9e107d9d372bb6826bd81d3542a419d6"}, {"The quick brown fox jumps over the lazy dog.", "e4d909c290d0fb1ca068ffaddf22cbd0"}, } for _, c := range cases { digest := Single(t, []byte(c.Data)) got := hex.EncodeToString(digest[:]) if got != c.HexDigest { t.Errorf("Sum(%#v) = %s; expect %s", c.Data, got, c.HexDigest) } } } func TestCmp(t *testing.T) { RequireISA(t) sum := func(data []byte) [Size]byte { return Single(t, data) } if err := quick.CheckEqual(sum, md5.Sum, nil); err != nil { t.Fatal(err) } } func TestLengths(t *testing.T) { RequireISA(t) const max = BlockSize << 6 data := make([]byte, max) rand.Read(data) for n := 0; n <= max; n++ { got := Single(t, data[:n]) expect := md5.Sum(data[:n]) if got != expect { t.Fatalf("failed on length %d", n) } } } // Single hashes a single data buffer in all 16 lanes and returns the result, // after asserting that all lanes are the same. func Single(t *testing.T, d []byte) [Size]byte { // Place the same data in every lane. var data [Lanes][]byte for l := range data { data[l] = d } if err := Validate(data); err != nil { t.Fatal(err) } // Hash and check the lanes are the same. digest := Sum(data) for l := range data { if digest[0] != digest[l] { t.Logf("lane %02d: %x", 0, digest[0]) t.Logf("lane %02d: %x", l, digest[l]) t.Fatal("lane mismatch") } } return digest[0] } func TestActiveLanes(t *testing.T) { RequireISA(t) const trials = 1 << 10 const maxlen = BlockSize << 6 for trial := 0; trial < trials; trial++ { // Pick active lanes. lanes := 1 + rand.Intn(Lanes-1) active := rand.Perm(Lanes)[:lanes] // Fill active lanes with random data. n := rand.Intn(maxlen) buffer := make([]byte, lanes*n) rand.Read(buffer) var data [Lanes][]byte for i, l := range active { data[l] = buffer[i*n : (i+1)*n] } // Hash. digest := Sum(data) // Verify correct result in active lanes. for _, l := range active { expect := md5.Sum(data[l]) if digest[l] != expect { t.Fatalf("lane %02d: mismatch", l) } } // Verify other lanes are zero. isactive := map[int]bool{} for _, l := range active { isactive[l] = true } for l := 0; l < Lanes; l++ { if !isactive[l] { var zero [Size]byte if digest[l] != zero { t.Fatalf("inactive lane %d is non-zero", l) } } } } }