Sliding replay window.
[champa.git] / noise / replay.go
blob4fc278f5ca211d6f0eca157758cfea41aa1dff3b
1 package noise
3 // replayWindow is a sliding window tracking previously used nonces.
4 type replayWindow struct {
5 // It is a coincidence that bitmap and highest have the same integer
6 // type. highest must be uint64 because that is the type of Noise
7 // nonces; but bitmap could conceptually be larger or smaller.
8 bitmap uint64
9 highest uint64
12 // CheckAndUpdate checks whether a nonce is acceptable, given the current state
13 // of the replay window. If acceptable, updates the state to mark the nonce as
14 // used.
16 // This function must be called only after verifying the integrity of the
17 // enclosed message.
18 func (rw *replayWindow) CheckAndUpdate(nonce uint64) bool {
19 // The algorithm is adapted from
20 // https://datatracker.ietf.org/doc/html/rfc2401#appendix-C.
21 // See also the last paragraph of Section 5.4.6 of
22 // https://www.wireguard.com/papers/wireguard.pdf.
23 if nonce <= rw.highest {
24 // nonce is in the past.
25 diff := rw.highest - nonce
26 if diff >= 64 {
27 // nonce is before the window.
28 return false
30 mask := uint64(1) << diff
31 if rw.bitmap&mask != 0 {
32 // nonce is within the window, but already used.
33 return false
35 // nonce is within the window, and not yet used. Mark it used.
36 rw.bitmap |= mask
37 return true
38 } else {
39 // nonce is in the future.
40 diff := nonce - rw.highest
41 // Shift the window.
42 rw.bitmap <<= diff // If the shift overflows, bitmap becomes 0.
43 rw.highest = nonce
44 // Mark this most recent nonce used.
45 rw.bitmap |= 1
46 return true