mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-30 19:15:23 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| //+build !noasm,!appengine,gc
 | |
| 
 | |
| // Copyright (c) 2020 MinIO Inc. All rights reserved.
 | |
| // Use of this source code is governed by a license that can be
 | |
| // found in the LICENSE file.
 | |
| 
 | |
| package md5simd
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"sync"
 | |
| 	"sync/atomic"
 | |
| )
 | |
| 
 | |
| // md5Digest - Type for computing MD5 using either AVX2 or AVX512
 | |
| type md5Digest struct {
 | |
| 	uid         uint64
 | |
| 	blocksCh    chan blockInput
 | |
| 	cycleServer chan uint64
 | |
| 	x           [BlockSize]byte
 | |
| 	nx          int
 | |
| 	len         uint64
 | |
| 	buffers     <-chan []byte
 | |
| }
 | |
| 
 | |
| // NewHash - initialize instance for Md5 implementation.
 | |
| func (s *md5Server) NewHash() Hasher {
 | |
| 	uid := atomic.AddUint64(&s.uidCounter, 1)
 | |
| 	blockCh := make(chan blockInput, buffersPerLane)
 | |
| 	s.newInput <- newClient{
 | |
| 		uid:   uid,
 | |
| 		input: blockCh,
 | |
| 	}
 | |
| 	return &md5Digest{
 | |
| 		uid:         uid,
 | |
| 		buffers:     s.buffers,
 | |
| 		blocksCh:    blockCh,
 | |
| 		cycleServer: s.cycle,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Size - Return size of checksum
 | |
| func (d *md5Digest) Size() int { return Size }
 | |
| 
 | |
| // BlockSize - Return blocksize of checksum
 | |
| func (d md5Digest) BlockSize() int { return BlockSize }
 | |
| 
 | |
| func (d *md5Digest) Reset() {
 | |
| 	if d.blocksCh == nil {
 | |
| 		panic("reset after close")
 | |
| 	}
 | |
| 	d.nx = 0
 | |
| 	d.len = 0
 | |
| 	d.sendBlock(blockInput{uid: d.uid, reset: true}, false)
 | |
| }
 | |
| 
 | |
| // write to digest
 | |
| func (d *md5Digest) Write(p []byte) (nn int, err error) {
 | |
| 	if d.blocksCh == nil {
 | |
| 		return 0, errors.New("md5Digest closed")
 | |
| 	}
 | |
| 
 | |
| 	// break input into chunks of maximum internalBlockSize size
 | |
| 	for {
 | |
| 		l := len(p)
 | |
| 		if l > internalBlockSize {
 | |
| 			l = internalBlockSize
 | |
| 		}
 | |
| 		nnn, err := d.write(p[:l])
 | |
| 		if err != nil {
 | |
| 			return nn, err
 | |
| 		}
 | |
| 		nn += nnn
 | |
| 		p = p[l:]
 | |
| 
 | |
| 		if len(p) == 0 {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (d *md5Digest) write(p []byte) (nn int, err error) {
 | |
| 
 | |
| 	nn = len(p)
 | |
| 	d.len += uint64(nn)
 | |
| 	if d.nx > 0 {
 | |
| 		n := copy(d.x[d.nx:], p)
 | |
| 		d.nx += n
 | |
| 		if d.nx == BlockSize {
 | |
| 			// Create a copy of the overflow buffer in order to send it async over the channel
 | |
| 			// (since we will modify the overflow buffer down below with any access beyond multiples of 64)
 | |
| 			tmp := <-d.buffers
 | |
| 			tmp = tmp[:BlockSize]
 | |
| 			copy(tmp, d.x[:])
 | |
| 			d.sendBlock(blockInput{uid: d.uid, msg: tmp}, len(p)-n < BlockSize)
 | |
| 			d.nx = 0
 | |
| 		}
 | |
| 		p = p[n:]
 | |
| 	}
 | |
| 	if len(p) >= BlockSize {
 | |
| 		n := len(p) &^ (BlockSize - 1)
 | |
| 		buf := <-d.buffers
 | |
| 		buf = buf[:n]
 | |
| 		copy(buf, p)
 | |
| 		d.sendBlock(blockInput{uid: d.uid, msg: buf}, len(p)-n < BlockSize)
 | |
| 		p = p[n:]
 | |
| 	}
 | |
| 	if len(p) > 0 {
 | |
| 		d.nx = copy(d.x[:], p)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (d *md5Digest) Close() {
 | |
| 	if d.blocksCh != nil {
 | |
| 		close(d.blocksCh)
 | |
| 		d.blocksCh = nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var sumChPool sync.Pool
 | |
| 
 | |
| func init() {
 | |
| 	sumChPool.New = func() interface{} {
 | |
| 		return make(chan sumResult, 1)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Sum - Return MD5 sum in bytes
 | |
| func (d *md5Digest) Sum(in []byte) (result []byte) {
 | |
| 	if d.blocksCh == nil {
 | |
| 		panic("sum after close")
 | |
| 	}
 | |
| 
 | |
| 	trail := <-d.buffers
 | |
| 	trail = append(trail[:0], d.x[:d.nx]...)
 | |
| 
 | |
| 	length := d.len
 | |
| 	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
 | |
| 	var tmp [64]byte
 | |
| 	tmp[0] = 0x80
 | |
| 	if length%64 < 56 {
 | |
| 		trail = append(trail, tmp[0:56-length%64]...)
 | |
| 	} else {
 | |
| 		trail = append(trail, tmp[0:64+56-length%64]...)
 | |
| 	}
 | |
| 
 | |
| 	// Length in bits.
 | |
| 	length <<= 3
 | |
| 	binary.LittleEndian.PutUint64(tmp[:], length) // append length in bits
 | |
| 
 | |
| 	trail = append(trail, tmp[0:8]...)
 | |
| 	if len(trail)%BlockSize != 0 {
 | |
| 		panic(fmt.Errorf("internal error: sum block was not aligned. len=%d, nx=%d", len(trail), d.nx))
 | |
| 	}
 | |
| 	sumCh := sumChPool.Get().(chan sumResult)
 | |
| 	d.sendBlock(blockInput{uid: d.uid, msg: trail, sumCh: sumCh}, true)
 | |
| 
 | |
| 	sum := <-sumCh
 | |
| 	sumChPool.Put(sumCh)
 | |
| 
 | |
| 	return append(in, sum.digest[:]...)
 | |
| }
 | |
| 
 | |
| // sendBlock will send a block for processing.
 | |
| // If cycle is true we will block on cycle, otherwise we will only block
 | |
| // if the block channel is full.
 | |
| func (d *md5Digest) sendBlock(bi blockInput, cycle bool) {
 | |
| 	if cycle {
 | |
| 		select {
 | |
| 		case d.blocksCh <- bi:
 | |
| 			d.cycleServer <- d.uid
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 	// Only block on cycle if we filled the buffer
 | |
| 	select {
 | |
| 	case d.blocksCh <- bi:
 | |
| 		return
 | |
| 	default:
 | |
| 		d.cycleServer <- d.uid
 | |
| 		d.blocksCh <- bi
 | |
| 	}
 | |
| }
 |