github.com/MerlinKodo/sing-shadowsocks@v0.2.6/shadowaead_2022/slidingwindow.go (about)

     1  package shadowaead_2022
     2  
     3  const (
     4  	swBlockBitLog = 6                  // 1<<6 == 64 bits
     5  	swBlockBits   = 1 << swBlockBitLog // must be power of 2
     6  	swRingBlocks  = 1 << 7             // must be power of 2
     7  	swBlockMask   = swRingBlocks - 1
     8  	swBitMask     = swBlockBits - 1
     9  	swSize        = (swRingBlocks - 1) * swBlockBits
    10  )
    11  
    12  // SlidingWindow maintains a sliding window of uint64 counters.
    13  type SlidingWindow struct {
    14  	last uint64
    15  	ring [swRingBlocks]uint64
    16  }
    17  
    18  // Reset resets the filter to its initial state.
    19  func (f *SlidingWindow) Reset() {
    20  	f.last = 0
    21  	f.ring[0] = 0
    22  }
    23  
    24  // Check checks whether counter can be accepted by the sliding window filter.
    25  func (f *SlidingWindow) Check(counter uint64) bool {
    26  	switch {
    27  	case counter > f.last: // ahead of window
    28  		return true
    29  	case f.last-counter > swSize: // behind window
    30  		return false
    31  	}
    32  
    33  	// In window. Check bit.
    34  	blockIndex := counter >> swBlockBitLog & swBlockMask
    35  	bitIndex := counter & swBitMask
    36  	return f.ring[blockIndex]>>bitIndex&1 == 0
    37  }
    38  
    39  // Add adds counter to the sliding window without checking if the counter is valid.
    40  // Call Check beforehand to make sure the counter is valid.
    41  func (f *SlidingWindow) Add(counter uint64) {
    42  	blockIndex := counter >> swBlockBitLog
    43  
    44  	// Check if counter is ahead of window.
    45  	if counter > f.last {
    46  		lastBlockIndex := f.last >> swBlockBitLog
    47  		diff := int(blockIndex - lastBlockIndex)
    48  		if diff > swRingBlocks {
    49  			diff = swRingBlocks
    50  		}
    51  
    52  		for i := 0; i < diff; i++ {
    53  			lastBlockIndex = (lastBlockIndex + 1) & swBlockMask
    54  			f.ring[lastBlockIndex] = 0
    55  		}
    56  
    57  		f.last = counter
    58  	}
    59  
    60  	blockIndex &= swBlockMask
    61  	bitIndex := counter & swBitMask
    62  	f.ring[blockIndex] |= 1 << bitIndex
    63  }