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}