noise/
patterns.rs

1// Set of libraries for privacy-preserving networking apps
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2023 by
6//     Dr. Maxim Orlovsky <orlovsky@cyphernet.org>
7//
8// Copyright 2023 Cyphernet DAO, Switzerland
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22use cypher::Ecdh;
23
24#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
25pub enum InitiatorPattern {
26    #[display("N")]
27    No,
28
29    #[display("X")]
30    Xmitted,
31
32    #[display("K")]
33    Known,
34
35    #[display("I")]
36    Immediately,
37}
38
39#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
40pub enum OneWayPattern {
41    #[display("N")]
42    No,
43
44    #[display("X")]
45    Xmitted,
46
47    #[display("L")]
48    Known,
49}
50
51#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
52pub enum PreMsgKeyPat {
53    #[display("-> s")]
54    InitiatorStatic,
55
56    #[display("<- s")]
57    ResponderStatic,
58
59    #[display("")]
60    Empty,
61}
62
63#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
64#[display("{initiator}{responder}")]
65pub struct HandshakePattern {
66    pub initiator: InitiatorPattern,
67    pub responder: OneWayPattern,
68}
69
70impl HandshakePattern {
71    pub fn nn() -> Self {
72        Self {
73            initiator: InitiatorPattern::No,
74            responder: OneWayPattern::No,
75        }
76    }
77
78    pub fn pre_messages(self) -> &'static [PreMsgKeyPat] {
79        match (self.initiator, self.responder) {
80            (InitiatorPattern::No, OneWayPattern::No) => &[PreMsgKeyPat::Empty],
81            (InitiatorPattern::No, OneWayPattern::Known) => &[PreMsgKeyPat::ResponderStatic],
82            (InitiatorPattern::No, OneWayPattern::Xmitted) => &[PreMsgKeyPat::Empty],
83            (InitiatorPattern::Xmitted, OneWayPattern::No) => &[PreMsgKeyPat::Empty],
84            (InitiatorPattern::Xmitted, OneWayPattern::Known) => &[PreMsgKeyPat::ResponderStatic],
85            (InitiatorPattern::Xmitted, OneWayPattern::Xmitted) => &[PreMsgKeyPat::Empty],
86            (InitiatorPattern::Known, OneWayPattern::No) => &[PreMsgKeyPat::InitiatorStatic],
87            (InitiatorPattern::Known, OneWayPattern::Known) => {
88                &[PreMsgKeyPat::InitiatorStatic, PreMsgKeyPat::ResponderStatic]
89            }
90            (InitiatorPattern::Known, OneWayPattern::Xmitted) => &[PreMsgKeyPat::InitiatorStatic],
91            (InitiatorPattern::Immediately, OneWayPattern::No) => &[PreMsgKeyPat::Empty],
92            (InitiatorPattern::Immediately, OneWayPattern::Known) => {
93                &[PreMsgKeyPat::InitiatorStatic]
94            }
95            (InitiatorPattern::Immediately, OneWayPattern::Xmitted) => &[PreMsgKeyPat::Empty],
96        }
97    }
98
99    pub fn message_patterns(self, is_initiator: bool) -> &'static [&'static [MessagePattern]] {
100        if is_initiator {
101            match (self.initiator, self.responder) {
102                (InitiatorPattern::No, OneWayPattern::No) => &[&[MessagePattern::E]],
103                (InitiatorPattern::No, OneWayPattern::Known) => {
104                    &[&[MessagePattern::E, MessagePattern::ES]]
105                }
106                (InitiatorPattern::No, OneWayPattern::Xmitted) => &[&[MessagePattern::E]],
107                (InitiatorPattern::Xmitted, OneWayPattern::No) => {
108                    &[&[MessagePattern::E], &[MessagePattern::S, MessagePattern::SE]]
109                }
110                (InitiatorPattern::Xmitted, OneWayPattern::Known) => &[
111                    &[MessagePattern::E, MessagePattern::ES],
112                    &[MessagePattern::S, MessagePattern::SE],
113                ],
114                (InitiatorPattern::Xmitted, OneWayPattern::Xmitted) => {
115                    &[&[MessagePattern::E], &[MessagePattern::S, MessagePattern::SE]]
116                }
117                (InitiatorPattern::Known, OneWayPattern::No) => &[&[MessagePattern::E]],
118                (InitiatorPattern::Known, OneWayPattern::Known) => {
119                    &[&[MessagePattern::E, MessagePattern::ES, MessagePattern::SS]]
120                }
121                (InitiatorPattern::Known, OneWayPattern::Xmitted) => &[&[MessagePattern::E]],
122                (InitiatorPattern::Immediately, OneWayPattern::No) => {
123                    &[&[MessagePattern::E, MessagePattern::S]]
124                }
125                (InitiatorPattern::Immediately, OneWayPattern::Known) => &[&[
126                    MessagePattern::E,
127                    MessagePattern::ES,
128                    MessagePattern::S,
129                    MessagePattern::SS,
130                ]],
131                (InitiatorPattern::Immediately, OneWayPattern::Xmitted) => {
132                    &[&[MessagePattern::E, MessagePattern::S]]
133                }
134            }
135        } else {
136            match (self.initiator, self.responder) {
137                (InitiatorPattern::No, OneWayPattern::No) => {
138                    &[&[MessagePattern::E, MessagePattern::EE]]
139                }
140                (InitiatorPattern::No, OneWayPattern::Known) => {
141                    &[&[MessagePattern::E, MessagePattern::EE]]
142                }
143                (InitiatorPattern::No, OneWayPattern::Xmitted) => &[&[
144                    MessagePattern::E,
145                    MessagePattern::EE,
146                    MessagePattern::S,
147                    MessagePattern::ES,
148                ]],
149                (InitiatorPattern::Xmitted, OneWayPattern::No) => {
150                    &[&[MessagePattern::E, MessagePattern::EE]]
151                }
152                (InitiatorPattern::Xmitted, OneWayPattern::Known) => {
153                    &[&[MessagePattern::E, MessagePattern::EE]]
154                }
155                (InitiatorPattern::Xmitted, OneWayPattern::Xmitted) => &[&[
156                    MessagePattern::E,
157                    MessagePattern::EE,
158                    MessagePattern::S,
159                    MessagePattern::ES,
160                ]],
161                (InitiatorPattern::Known, OneWayPattern::No) => {
162                    &[&[MessagePattern::E, MessagePattern::EE, MessagePattern::SE]]
163                }
164                (InitiatorPattern::Known, OneWayPattern::Known) => {
165                    &[&[MessagePattern::E, MessagePattern::EE, MessagePattern::SE]]
166                }
167                (InitiatorPattern::Known, OneWayPattern::Xmitted) => &[&[
168                    MessagePattern::E,
169                    MessagePattern::EE,
170                    MessagePattern::SE,
171                    MessagePattern::S,
172                    MessagePattern::ES,
173                ]],
174                (InitiatorPattern::Immediately, OneWayPattern::No) => {
175                    &[&[MessagePattern::E, MessagePattern::EE, MessagePattern::SE]]
176                }
177                (InitiatorPattern::Immediately, OneWayPattern::Known) => {
178                    &[&[MessagePattern::E, MessagePattern::EE, MessagePattern::SE]]
179                }
180                (InitiatorPattern::Immediately, OneWayPattern::Xmitted) => &[&[
181                    MessagePattern::E,
182                    MessagePattern::EE,
183                    MessagePattern::SE,
184                    MessagePattern::S,
185                    MessagePattern::ES,
186                ]],
187            }
188        }
189    }
190}
191
192#[derive(Clone, Eq, PartialEq, Debug)]
193pub struct Keyset<E: Ecdh> {
194    pub e: E,
195    pub s: Option<E>,
196    pub re: Option<E::Pk>,
197    pub rs: Option<E::Pk>,
198}
199
200impl<E: Ecdh> Keyset<E> {
201    pub fn noise_nn() -> Self {
202        let pair = E::generate_keypair();
203        Self {
204            e: pair.0,
205            s: None,
206            re: None,
207            rs: None,
208        }
209    }
210
211    pub fn pre_message_key(&self, pmkp: PreMsgKeyPat, is_initiator: bool) -> Option<E::Pk> {
212        Some(match (pmkp, is_initiator) {
213            (PreMsgKeyPat::InitiatorStatic, true) | (PreMsgKeyPat::ResponderStatic, false) => {
214                self.expect_s().to_pk().expect("invalid static key")
215            }
216            (PreMsgKeyPat::ResponderStatic, true) | (PreMsgKeyPat::InitiatorStatic, false) => {
217                self.expect_rs().clone()
218            }
219            (PreMsgKeyPat::Empty, _) => return None,
220        })
221    }
222
223    pub fn expect_s(&self) -> &E { self.s.as_ref().expect("static key must be known") }
224
225    pub fn expect_re(&self) -> &E::Pk {
226        self.re.as_ref().expect("remote ephemeral key must be known at this stage")
227    }
228
229    pub fn expect_rs(&self) -> &E::Pk {
230        self.rs.as_ref().expect("remote static key must be known at this stage")
231    }
232}
233
234#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
235#[non_exhaustive] // Future specifications might introduce other tokens.
236pub enum MessagePattern {
237    #[display("e")]
238    E,
239
240    #[display("s")]
241    S,
242
243    #[display("ee")]
244    EE,
245
246    #[display("es")]
247    ES,
248
249    #[display("se")]
250    SE,
251
252    #[display("ss")]
253    SS,
254    // TODO: Support PSK pattern
255}