aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/md5-simd/md5-digest_amd64.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/md5-simd/md5-digest_amd64.go')
-rw-r--r--vendor/github.com/minio/md5-simd/md5-digest_amd64.go188
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/github.com/minio/md5-simd/md5-digest_amd64.go b/vendor/github.com/minio/md5-simd/md5-digest_amd64.go
new file mode 100644
index 0000000..5ea23a4
--- /dev/null
+++ b/vendor/github.com/minio/md5-simd/md5-digest_amd64.go
@@ -0,0 +1,188 @@
1//+build !noasm,!appengine,gc
2
3// Copyright (c) 2020 MinIO Inc. All rights reserved.
4// Use of this source code is governed by a license that can be
5// found in the LICENSE file.
6
7package md5simd
8
9import (
10 "encoding/binary"
11 "errors"
12 "fmt"
13 "sync"
14 "sync/atomic"
15)
16
17// md5Digest - Type for computing MD5 using either AVX2 or AVX512
18type md5Digest struct {
19 uid uint64
20 blocksCh chan blockInput
21 cycleServer chan uint64
22 x [BlockSize]byte
23 nx int
24 len uint64
25 buffers <-chan []byte
26}
27
28// NewHash - initialize instance for Md5 implementation.
29func (s *md5Server) NewHash() Hasher {
30 uid := atomic.AddUint64(&s.uidCounter, 1)
31 blockCh := make(chan blockInput, buffersPerLane)
32 s.newInput <- newClient{
33 uid: uid,
34 input: blockCh,
35 }
36 return &md5Digest{
37 uid: uid,
38 buffers: s.buffers,
39 blocksCh: blockCh,
40 cycleServer: s.cycle,
41 }
42}
43
44// Size - Return size of checksum
45func (d *md5Digest) Size() int { return Size }
46
47// BlockSize - Return blocksize of checksum
48func (d md5Digest) BlockSize() int { return BlockSize }
49
50func (d *md5Digest) Reset() {
51 if d.blocksCh == nil {
52 panic("reset after close")
53 }
54 d.nx = 0
55 d.len = 0
56 d.sendBlock(blockInput{uid: d.uid, reset: true}, false)
57}
58
59// write to digest
60func (d *md5Digest) Write(p []byte) (nn int, err error) {
61 if d.blocksCh == nil {
62 return 0, errors.New("md5Digest closed")
63 }
64
65 // break input into chunks of maximum internalBlockSize size
66 for {
67 l := len(p)
68 if l > internalBlockSize {
69 l = internalBlockSize
70 }
71 nnn, err := d.write(p[:l])
72 if err != nil {
73 return nn, err
74 }
75 nn += nnn
76 p = p[l:]
77
78 if len(p) == 0 {
79 break
80 }
81
82 }
83 return
84}
85
86func (d *md5Digest) write(p []byte) (nn int, err error) {
87
88 nn = len(p)
89 d.len += uint64(nn)
90 if d.nx > 0 {
91 n := copy(d.x[d.nx:], p)
92 d.nx += n
93 if d.nx == BlockSize {
94 // Create a copy of the overflow buffer in order to send it async over the channel
95 // (since we will modify the overflow buffer down below with any access beyond multiples of 64)
96 tmp := <-d.buffers
97 tmp = tmp[:BlockSize]
98 copy(tmp, d.x[:])
99 d.sendBlock(blockInput{uid: d.uid, msg: tmp}, len(p)-n < BlockSize)
100 d.nx = 0
101 }
102 p = p[n:]
103 }
104 if len(p) >= BlockSize {
105 n := len(p) &^ (BlockSize - 1)
106 buf := <-d.buffers
107 buf = buf[:n]
108 copy(buf, p)
109 d.sendBlock(blockInput{uid: d.uid, msg: buf}, len(p)-n < BlockSize)
110 p = p[n:]
111 }
112 if len(p) > 0 {
113 d.nx = copy(d.x[:], p)
114 }
115 return
116}
117
118func (d *md5Digest) Close() {
119 if d.blocksCh != nil {
120 close(d.blocksCh)
121 d.blocksCh = nil
122 }
123}
124
125var sumChPool sync.Pool
126
127func init() {
128 sumChPool.New = func() interface{} {
129 return make(chan sumResult, 1)
130 }
131}
132
133// Sum - Return MD5 sum in bytes
134func (d *md5Digest) Sum(in []byte) (result []byte) {
135 if d.blocksCh == nil {
136 panic("sum after close")
137 }
138
139 trail := <-d.buffers
140 trail = append(trail[:0], d.x[:d.nx]...)
141
142 length := d.len
143 // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
144 var tmp [64]byte
145 tmp[0] = 0x80
146 if length%64 < 56 {
147 trail = append(trail, tmp[0:56-length%64]...)
148 } else {
149 trail = append(trail, tmp[0:64+56-length%64]...)
150 }
151
152 // Length in bits.
153 length <<= 3
154 binary.LittleEndian.PutUint64(tmp[:], length) // append length in bits
155
156 trail = append(trail, tmp[0:8]...)
157 if len(trail)%BlockSize != 0 {
158 panic(fmt.Errorf("internal error: sum block was not aligned. len=%d, nx=%d", len(trail), d.nx))
159 }
160 sumCh := sumChPool.Get().(chan sumResult)
161 d.sendBlock(blockInput{uid: d.uid, msg: trail, sumCh: sumCh}, true)
162
163 sum := <-sumCh
164 sumChPool.Put(sumCh)
165
166 return append(in, sum.digest[:]...)
167}
168
169// sendBlock will send a block for processing.
170// If cycle is true we will block on cycle, otherwise we will only block
171// if the block channel is full.
172func (d *md5Digest) sendBlock(bi blockInput, cycle bool) {
173 if cycle {
174 select {
175 case d.blocksCh <- bi:
176 d.cycleServer <- d.uid
177 }
178 return
179 }
180 // Only block on cycle if we filled the buffer
181 select {
182 case d.blocksCh <- bi:
183 return
184 default:
185 d.cycleServer <- d.uid
186 d.blocksCh <- bi
187 }
188}