ratchetx2/ratchet/
mod.rs

1//! Double Ratchet Algorithm.
2
3mod dh_root;
4mod message;
5
6use dh_root::DhRootRatchet;
7use message::MessageRatchet;
8use ring::agreement::EphemeralPrivateKey;
9
10use crate::key::{HeaderKey, MessageKey, SecretKey};
11
12/// Double ratchet.
13/// # Example
14/// ```
15/// use ratchetx2::SharedKeys;
16/// use ratchetx2::rand::SystemRandom;
17/// use ratchetx2::agreement::{EphemeralPrivateKey, X25519};
18///
19/// let shared_keys = SharedKeys {
20///     secret_key: [0; 32],
21///     header_key_alice: [1; 32],
22///     header_key_bob: [2; 32],
23/// };
24/// let mut bob = shared_keys.bob(EphemeralPrivateKey::generate(&X25519, &SystemRandom::new()).unwrap());
25/// let mut alice = shared_keys.alice(&bob.public_key());
26///
27/// bob.step_dh_root(&alice.public_key());
28/// assert_eq!(alice, bob); // Alice and Bob have the "same" state
29/// assert_eq!(alice.step_msgs(), bob.step_msgr()); // returning the same message key
30/// assert_eq!(alice.step_msgs(), bob.step_msgr());
31///
32/// bob.step_dh_root(&alice.public_key());
33/// alice.step_dh_root(&bob.public_key());
34/// assert_eq!(alice, bob);
35/// assert_eq!(bob.step_msgs(), alice.step_msgr());
36/// assert_eq!(bob.step_msgs(), alice.step_msgr());
37///
38/// alice.step_dh_root(&bob.public_key());
39/// bob.step_dh_root(&alice.public_key());
40/// assert_eq!(alice, bob);
41/// assert_eq!(alice.step_msgs(), bob.step_msgr());
42/// assert_eq!(alice.step_msgs(), bob.step_msgr());
43/// ```
44#[derive(Debug)]
45pub struct Ratchetx2 {
46    dh_root: DhRootRatchet,
47    msgs: MessageRatchet,
48    msgr: MessageRatchet,
49    /// - true: next dh step will update msgs
50    /// - false: next dh step will update msgr
51    dh_step_s: bool,
52}
53
54impl PartialEq for Ratchetx2 {
55    /// Alice and Bob have the same DhRootRatchet,
56    /// and Alice's message sending ratchet is the same as Bob's message receiving ratchet,
57    /// so is Alice's receiving ratchet and Bob's sending ratchet.
58    ///
59    /// So, two Ratchets A and B are Eq only if they have the same DhRootRatchet,
60    /// and A.msgs == B.msgr && A.msgr == B.msgs.
61    fn eq(&self, other: &Self) -> bool {
62        self.dh_root == other.dh_root && self.msgs == other.msgr && self.msgr == other.msgs
63    }
64}
65
66impl Ratchetx2 {
67    /// New a party who sends message first.
68    /// # Args
69    /// - secret_key, header_key_alice, header_key_bob: shared keys for initialization
70    pub fn alice(
71        secret_key: SecretKey,
72        public_key: &[u8],
73        header_key_alice: HeaderKey,
74        header_key_bob: HeaderKey,
75    ) -> Self {
76        let mut this = Self {
77            dh_root: DhRootRatchet::alice(secret_key),
78            msgs: MessageRatchet::empty(header_key_alice),
79            msgr: MessageRatchet::empty(header_key_bob),
80            dh_step_s: true,
81        };
82        this.step_dh_root(public_key);
83        this
84    }
85
86    /// New a party who waits for the message first.
87    /// # Args
88    /// - secret_key, header_key_alice, header_key_bob: shared keys for initialization
89    ///
90    /// # Caution
91    /// Bob is initialized with [0; 32] as message key and header key, therefore,
92    /// step_dh_root to update message receiving chain before first receiving,
93    /// and step_dh_root again before first sending.
94    pub fn bob(
95        secret_key: SecretKey,
96        private_key: EphemeralPrivateKey,
97        header_key_alice: HeaderKey,
98        header_key_bob: HeaderKey,
99    ) -> Self {
100        Self {
101            dh_root: DhRootRatchet::bob(secret_key, private_key),
102            msgs: MessageRatchet::empty(header_key_bob),
103            msgr: MessageRatchet::empty(header_key_alice),
104            dh_step_s: false,
105        }
106    }
107
108    /// Get current public key.
109    pub fn public_key(&self) -> Vec<u8> {
110        self.dh_root.public_key()
111    }
112
113    /// Get current message sending HeaderKey.
114    pub fn header_key_s(&self) -> HeaderKey {
115        self.msgs.header_key
116    }
117
118    /// Get current message receiving HeaderKey.
119    pub fn header_key_r(&self) -> HeaderKey {
120        self.msgr.header_key
121    }
122
123    /// Get next message receiving HeaderKey.
124    /// Classically, if failed with current HeaderKey when decrypting enc-header,
125    /// one should try next HeaderKey, if succeed, do DhRootRatchet step and cache MessageKey
126    /// for future (for it's message out of order).
127    pub fn next_header_key_r(&self) -> HeaderKey {
128        self.msgr.next_header_key
129    }
130
131    /// Perform ratchet step on message sending ratchet.
132    /// Updating message sending ratchet's ChainKey, and return MessageKey.
133    pub fn step_msgs(&mut self) -> MessageKey {
134        self.msgs.step()
135    }
136
137    /// Perform ratchet step on message receiving ratchet.
138    /// Update message receiving ratchet's ChainKey, and return MessageKey.
139    pub fn step_msgr(&mut self) -> MessageKey {
140        self.msgr.step()
141    }
142
143    /// Perform ratchet step on DH-Root ratchet.
144    /// Update DH pair if needed, update root key, and update **one of** message ratchets.
145    /// # Caution
146    /// In the Signal document, one dh-root step will update both message sending and receiving chain,
147    /// however, notice that, when initialize Alice, only message sending chain is updated,
148    /// so in this implementation, dh-root step will update message sending and receiving chain in rotation.
149    ///
150    /// In other words, dh-root should step twice when receiving next-header-key encrypted header.
151    ///
152    /// Additionally, by doing so, it's more convenient to check whether states of parties are matching
153    /// when writing tests.
154    pub fn step_dh_root(&mut self, public_key: &[u8]) {
155        let (chain_key, next_header_key) = self.dh_root.step(public_key);
156        match self.dh_step_s {
157            true => {
158                self.msgs =
159                    MessageRatchet::from_key(chain_key, self.msgs.next_header_key, next_header_key)
160            }
161            false => {
162                self.msgr =
163                    MessageRatchet::from_key(chain_key, self.msgr.next_header_key, next_header_key)
164            }
165        }
166        self.dh_step_s = !self.dh_step_s;
167    }
168}