1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#![no_std]

#[derive(Debug)]
pub struct Demon {
    /// The last sample observed by the demon
    pub last_sample: u32,

    /// The last sample used by the demon for mixing
    pub last_mixing_sample: u32,

    /// The number of consecutive samples with the same value
    pub run: u32,

    /// The current key-in-progress
    pub key: u32,

    /// The current mixing value
    pub mix: u32,

    /// The number of operations remaining to obtain a good key
    pub ops_remaining: u32,

    /// The number of samples remaining before a timeout will be raise
    pub samples_remaining: u32,
}

#[derive(Debug)]
pub enum Error {
    NeedMoreSamples,
    Timeout,
}

pub type Result<T> = core::result::Result<T, Error>;

impl Default for Demon {
    fn default() -> Self {
        Demon {
            key: 0xACACACAC,
            last_sample: 0,
            last_mixing_sample: 0,
            mix: 0xF0F0F0F0,
            run: 0,
            ops_remaining: 100,
            samples_remaining: 100_000,
        }
    }
}

impl Demon {
    pub fn take_sample(&mut self, sample: u32) -> Result<[u8; 4]> {
        // println!("{:X?} - {:X?}", self, sample);

        self.samples_remaining = self.samples_remaining.saturating_sub(1);

        // If we received the same value as the last sample, increase
        // the run streak
        if sample == self.last_sample {
            self.run = self.run.saturating_add(1);
            return Err(Error::NeedMoreSamples);
        }

        self.last_sample = sample;

        if self.run != 0 {
            // println!("mix_run");
            self.mix = self.mix.saturating_add(1 << (self.run & 31));
            self.mix = self.mix.rotate_right(self.run);
        }

        // Reset the run streak to zero, as we have new data
        self.run = 0;

        // Compare the
        let sample_bits = sample & 0b11;
        let candidate_bits = (self.last_mixing_sample & 0b11) ^ sample_bits;

        let changed_data = candidate_bits != 0;
        let new_mix = self.mix.rotate_right(candidate_bits) ^ sample_bits;

        match (changed_data, (new_mix != 0)) {
            (true, true) => {
                self.key = self.key.wrapping_add(new_mix);
                self.key ^= self.mix;
                self.key = self.key.rotate_left((candidate_bits << 2) | sample_bits);

                // Store the current sample as the last one used for mixing
                self.last_mixing_sample = sample;
                self.mix = new_mix;

                // Increment the number of change operations
                self.ops_remaining = self.ops_remaining.saturating_sub(1);
            }
            (true, false) => {
                // println!("rol");
                // Data has changed, but the new mix would be zero. Rotate Left a bit
                self.key = self.key.rotate_left(7);
            }
            (false, true) => {
                // println!("ror");
                // Data hasn't changed, but the new mix would be non-zero. Rotate Right a bit
                self.key = self.key.rotate_right(7);
            }
            (false, false) => {
                // println!("invert");
                // Everything is terrible. Invert the key
                self.key = !self.key;
            }
        }


        if self.ops_remaining == 0 {
            Ok(self.key.to_ne_bytes())
        } else if self.samples_remaining == 0 {
            Err(Error::Timeout)
        } else {
            Err(Error::NeedMoreSamples)
        }
    }
}