But even that need not be true. here is how you could design that dongle to require no persistent state on RX and still not allow simple replay.
TX code:
static u8 counter = 0;
tmp = randU12() * 16 + (counter++);
tmp2 = sha256(secret + tmp) & 0xffff;
send32((tmp << 16) + tmp2)
RX code:
static u16 prevSeenCodes[16];
static u8 idx = 0; tmp = recv32();
tmp2 = tmp & 0xffff;
tmp >>= 16;
if (sha256(secret + tmp) & 0xffff != tmp2)
fail();
if (tmp in prevSeenCodes)
fail();
prevSeenCodes[15 & idx++] = tmp;
now you need to replay at least a sequence of 16 codesthat array is in ram and need not persist across program runs. dongle can be powered off or can be left on. all will work