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 }