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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use crate::crypto::{ciphersuite::CipherSuite, dh::DiffieHellman};
use crate::tree_math;

/// A node in a `RatchetTree` with ciphersuite `CS`. Every node must have a DH pubkey. It may also
/// optionally contain the corresponding private key and a secret octet string.
pub(crate) enum RatchetTreeNode<CS: CipherSuite> {
    Blank,
    Filled {
        // To explain this notation a bit: CS::DH is the associated DH type of the given
        // ciphersuite. This is a concrete type. However, we know that DH: DiffieHellman, and we
        // need to know that the Point type is, so we choose the DiffieHellman trait
        // representation, and pick the associated type there. Note that this explicit choice is
        // necessary, since if, hypothetically it were the case that DH: Foo + Bar and both Foo and
        // Bar had the associated type Baz, then DH::Baz would be ambiguous. Instead, you'd write
        // <DH as Foo>::Baz or <DH as Bar>::Baz.
        pubkey: <CS::DH as DiffieHellman>::Point,
        privkey: Option<<CS::DH as DiffieHellman>::Scalar>,
        secret: Option<Vec<u8>>,
    },
}

/// A left-balanced binary tree of `RatchetTreeNode`s
// Contains a vector of nodes that could optionally be blanks
pub(crate) struct RatchetTree<CS: CipherSuite> {
    nodes: Vec<RatchetTreeNode<CS>>,
}

impl<CS: CipherSuite> RatchetTree<CS> {
    /// Returns an new empty `RatchetTree`
    pub fn new() -> RatchetTree<CS> {
        RatchetTree { nodes: Vec::new() }
    }

    // It turns out that appending to the tree in this way preserves the left-balanced property
    // while keeping everything in place. Instead of a proof, stare this diagram where I add a new
    // leaf node to a tree of 3 leaves, and then add another leaf to that. The stars represent
    // non-leaf nodes.
    //        *                   *                        *
    //       / \                /   \                _____/ \
    //      /   \    Add(D)    /     \    Add(E)    /        |
    //     *     C   =====>   *       *   =====>   *         |
    //    / \                / \     / \         /   \       |
    //   A   B              A   B   C   D       /     \      |
    //   0 1 2 3 4          0 1 2 3 4 5 6      *       *     |
    //                                        / \     / \    |
    //                                       A   B   C   D   E
    //                                       0 1 2 3 4 5 6 7 8
    pub fn add_leaf_node(&mut self, node: RatchetTreeNode<CS>) {
        if self.nodes.is_empty() {
            self.nodes.push(node);
            return;
        } else {
            self.nodes.push(RatchetTreeNode::Blank);
            self.nodes.push(node);
        }
    }

    /// Returns the resolution of a given node: this an ordered list of non-blank nodes that
    /// collectively cover all non-blank descendants of the given node.
    fn resolution(&self, idx: usize) -> Vec<&RatchetTreeNode<CS>> {
        fn helper<'a, T: CipherSuite>(
            i: usize,
            nodes: &'a Vec<RatchetTreeNode<T>>,
            acc: &mut Vec<&'a RatchetTreeNode<T>>,
        ) {
            let num_leaves = tree_math::num_leaves_in_tree(nodes.len());
            match &nodes[i] {
                f @ RatchetTreeNode::Filled { .. } => {
                    acc.push(f);
                    return;
                }
                _ => (),
            }
            if tree_math::node_level(i) == 0 {
                return;
            }

            helper(tree_math::node_left_child(i), nodes, acc);
            helper(tree_math::node_right_child(i, num_leaves), nodes, acc);
        }

        let mut acc = Vec::new();
        helper(idx, &self.nodes, &mut acc);
        acc
    }

    // This has the same functionality as RatchetTreeIter, so one of them's got to go
    /// Turns a list of node indices into an iterator of tree nodes
    fn make_node_iter(&self, indices: Vec<usize>) -> impl Iterator<Item = &RatchetTreeNode<CS>> {
        indices
            .into_iter()
            .map(move |i| self.nodes.get(i).expect("invalid index encountered"))
    }
}

// This has the same functionality as make_node_iter, so one of them's got to go
/// An iterator that holds a queue of indices into a RatchetTree, and returns references to the
/// corresponding nodes in the tree.
struct RatchetTreeIter<'a, CS: CipherSuite> {
    underlying_tree: &'a RatchetTree<CS>,
    index_iter: std::vec::IntoIter<usize>,
}

impl<'a, CS: CipherSuite> RatchetTreeIter<'a, CS> {
    fn new(underlying_tree: &'a RatchetTree<CS>, indices: Vec<usize>) -> RatchetTreeIter<'a, CS> {
        let index_iter = indices.into_iter();

        RatchetTreeIter {
            underlying_tree,
            index_iter,
        }
    }
}

impl<'a, CS: CipherSuite> Iterator for RatchetTreeIter<'a, CS> {
    type Item = &'a RatchetTreeNode<CS>;

    fn next(&mut self) -> Option<&'a RatchetTreeNode<CS>> {
        self.index_iter.next().map(|idx| {
            self.underlying_tree
                .nodes
                .get(idx)
                .expect("RatchetTreeIter got a bad node index")
        })
    }
}

/// An iterator that holds a queue of indices into a RatchetTree, and returns references to the
/// corresponding nodes in the tree.
struct RatchetTreeIterMut<'a, CS: CipherSuite> {
    underlying_tree: &'a mut RatchetTree<CS>,
    index_iter: std::vec::IntoIter<usize>,
}

impl<'a, CS: CipherSuite> RatchetTreeIterMut<'a, CS> {
    fn new(
        underlying_tree: &'a mut RatchetTree<CS>,
        mut indices: Vec<usize>,
    ) -> RatchetTreeIterMut<'a, CS> {
        // We can't return a &mut to the same node twice, since that would violate aliasing
        // guarantees, i.e., we'd have two mutable references to the same data, which is Bad. So
        // dedup the vector beforehand. Remember that an index uniquely identifies a node, so we're
        // in the clear.
        indices.dedup();
        let index_iter = indices.into_iter();

        RatchetTreeIterMut {
            underlying_tree,
            index_iter,
        }
    }
}

// This needs unsafe code in order to exist. I might delete this if there's little use for it.
impl<'a, CS: CipherSuite> Iterator for RatchetTreeIterMut<'a, CS> {
    type Item = &'a mut RatchetTreeNode<CS>;

    fn next(&mut self) -> Option<&'a mut RatchetTreeNode<CS>> {
        self.index_iter.next().map(|idx| {
            let mut_ref = self
                .underlying_tree
                .nodes
                .get_mut(idx)
                .expect("RatchetTreeIterMut got a bad node index");

            // Okay I can explain this. It's not currently possible to have an iterator that
            // returns mutable references to the thing it's iterating over. Niko Matsakis talks
            // about it here:
            // http://smallcultfollowing.com/babysteps/blog/2013/10/24/iterators-yielding-mutable-references/
            //
            // The reason I can't just return mut_ref is because its lifetime 'a outlives the
            // lifetime of &mut self. The compiler can ensure that mut_ref is a unique mutable
            // reference for the duration of this function call, but cannot guarantee uniqueness
            // after it returns. And indeed it might not be unique. Consider the following code and
            // assume that `tree` is a mut RatchetTree<CS> for some CS:
            //     let mut iter = RatchetTreeIterMut::new(&mut tree, vec![0]);
            //     let first_mut_ref = iter.next();
            //     let another_first_mut_ref = iter.underlying_tree.get_mut(0);
            //  Since I'm able to reach back into the iterator for another mutable reference, I can
            //  force first_mut_ref and another_first_mut_ref to alias.
            //
            //  Now our job is to make sure that you cannot access `iter.underlying_tree`, and also
            //  that the iterator itself does not return the same node multiple times. We do the
            //  former by making `underlying_tree` a private member and "being careful" in this
            //  module. We do the latter by deduping the vectors of indices upon initialization.
            unsafe { std::mem::transmute(mut_ref) }
        })
    }
}