Skip to main content

matrix_sdk_qrcode/
types.rs

1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::io::{Cursor, Read};
16
17use byteorder::{BigEndian, ReadBytesExt};
18use qrcode::QrCode;
19use ruma::serde::Base64;
20use vodozemac::Ed25519PublicKey;
21
22use crate::{
23    error::{DecodingError, EncodingError},
24    utils::{HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION, to_bytes, to_qr_code},
25};
26
27/// An enum representing the different modes for a QR verification code.
28#[derive(Clone, Debug, PartialEq, Eq)]
29pub enum QrVerificationData {
30    /// The QR verification is verifying another user.
31    ///
32    /// It relies on both devices already trusting or owning the master
33    /// cross-signing key for the corresponding user.
34    ///
35    /// In this case, the QR code data includes:
36    ///
37    /// - The master cross-signing key of the displaying device's user.
38    /// - What the displaying device believes is the master cross-signing key of
39    ///   the scanning device's user.
40    ///
41    /// After a successful verification, each device will trust the
42    /// cross-signing key of the other user, and will upload a cross-signature
43    /// of that key.
44    Verification(VerificationData),
45
46    /// The QR verification is self-verifying and the device displaying the QR
47    /// code trusts or owns the master cross-signing key.
48    ///
49    /// This normally happens when the displaying device is an existing device,
50    /// and the scanning device is new.
51    ///
52    /// In this case, the QR code data includes:
53    ///
54    /// - The master cross-signing key (which is trusted by the displaying
55    ///   device).
56    /// - What the displaying device believes is the device key of the scanning
57    ///   device.
58    ///
59    /// After a successful verification, the scanning device will be able to
60    /// trust the master key, and the displaying device will be able to trust
61    /// the scanning device's device key.
62    ///
63    /// Since the displaying device should be cross-signed already, this means
64    /// that the scanning device will now trust the displaying device.
65    ///
66    /// The displaying device will then upload a cross-signature of the scanning
67    /// device (assuming it has the private key), and will send the secret keys
68    /// to the scanning device.
69    SelfVerification(SelfVerificationData),
70
71    /// The QR verification is self-verifying in which the current device does
72    /// not yet trust the master key.
73    ///
74    /// This normally happens when the displaying device is new, and the
75    /// scanning device is an existing device.
76    ///
77    /// In this case, the QR code data includes:
78    ///
79    /// - The displaying device's device key.
80    /// - What the displaying device believes is the master cross-signing key.
81    ///
82    /// If the verification is successful, the scanning device will be able to
83    /// trust the displaying device's device key, and the displaying device will
84    /// be able to trust the master key.
85    ///
86    /// Since the scanning device should be cross-signed already, this means
87    /// that the displaying device will now trust the scanning device.
88    ///
89    /// The scanning device will then upload a cross-signature of the displaying
90    /// device (assuming it has the private key), and will send the secret keys
91    /// to the displaying device.
92    SelfVerificationNoMasterKey(SelfVerificationNoMasterKey),
93}
94
95impl TryFrom<&[u8]> for QrVerificationData {
96    type Error = DecodingError;
97
98    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
99        Self::from_bytes(value)
100    }
101}
102
103impl TryFrom<Vec<u8>> for QrVerificationData {
104    type Error = DecodingError;
105
106    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
107        Self::from_bytes(value)
108    }
109}
110
111impl QrVerificationData {
112    /// Parse the decoded payload of a QR code in byte slice form as a
113    /// `QrVerificationData`
114    ///
115    /// This method is useful if you would like to do your own custom QR code
116    /// decoding.
117    ///
118    /// # Arguments
119    ///
120    /// - `bytes` - The raw bytes of a decoded QR code.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
126    /// # fn main() -> Result<(), DecodingError> {
127    /// let data = b"MATRIX\
128    ///              \x02\x02\x00\x07\
129    ///              FLOW_ID\
130    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
131    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
132    ///              SHARED_SECRET";
133    ///
134    /// let result = QrVerificationData::from_bytes(data)?;
135    /// # Ok(())
136    /// # }
137    /// ```
138    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
139        Self::decode_bytes(bytes)
140    }
141
142    /// Encode the `QrVerificationData` into a `QrCode`.
143    ///
144    /// This method turns the `QrVerificationData` into a QR code that can be
145    /// rendered and presented to be scanned.
146    ///
147    /// The encoding can fail if the data doesn't fit into a QR code or if the
148    /// identity keys that should be encoded into the QR code are not valid
149    /// base64.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
155    /// # fn main() -> Result<(), DecodingError> {
156    /// let data = b"MATRIX\
157    ///              \x02\x02\x00\x07\
158    ///              FLOW_ID\
159    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
160    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
161    ///              SHARED_SECRET";
162    ///
163    /// let result = QrVerificationData::from_bytes(data)?;
164    /// let encoded = result.to_qr_code().unwrap();
165    /// # Ok(())
166    /// # }
167    /// ```
168    pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
169        match self {
170            QrVerificationData::Verification(v) => v.to_qr_code(),
171            QrVerificationData::SelfVerification(v) => v.to_qr_code(),
172            QrVerificationData::SelfVerificationNoMasterKey(v) => v.to_qr_code(),
173        }
174    }
175
176    /// Encode the `QrVerificationData` into a vector of bytes that can be
177    /// encoded as a QR code.
178    ///
179    /// The encoding can fail if the identity keys that should be encoded are
180    /// not valid base64.
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
186    /// # fn main() -> Result<(), DecodingError> {
187    /// let data = b"MATRIX\
188    ///              \x02\x02\x00\x07\
189    ///              FLOW_ID\
190    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
191    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
192    ///              SHARED_SECRET";
193    ///
194    /// let result = QrVerificationData::from_bytes(data)?;
195    /// let encoded = result.to_bytes().unwrap();
196    ///
197    /// assert_eq!(data.as_ref(), encoded.as_slice());
198    /// # Ok(())
199    /// # }
200    /// ```
201    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
202        match self {
203            QrVerificationData::Verification(v) => v.to_bytes(),
204            QrVerificationData::SelfVerification(v) => v.to_bytes(),
205            QrVerificationData::SelfVerificationNoMasterKey(v) => v.to_bytes(),
206        }
207    }
208
209    /// Decode the byte slice containing the decoded QR code data.
210    ///
211    /// The format is defined in the [spec].
212    ///
213    /// The byte slice consists of the following parts:
214    ///
215    /// - the ASCII string MATRIX
216    /// - one byte indicating the QR code version (must be 0x02)
217    /// - one byte indicating the QR code verification mode. one of the
218    ///   following values:
219    ///   - 0x00 verifying another user with cross-signing
220    ///   - 0x01 self-verifying in which the current device does trust the
221    ///     master key
222    ///   - 0x02 self-verifying in which the current device does not yet trust
223    ///     the master key
224    /// - the event ID or transaction_id of the associated verification request
225    ///   event, encoded as:
226    ///   - two bytes in network byte order (big-endian) indicating the length
227    ///     in bytes of the ID as a UTF-8 string
228    ///   - the ID as a UTF-8 string
229    /// - the first key, as 32 bytes
230    /// - the second key, as 32 bytes
231    /// - a random shared secret, as a byte string. as we do not share the
232    ///   length of the secret, and it is not a fixed size, clients will just
233    ///   use the remainder of binary string as the shared secret.
234    ///
235    /// [spec]: https://spec.matrix.org/unstable/client-server-api/#qr-code-format
236    fn decode_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
237        let mut decoded = Cursor::new(bytes);
238
239        let mut header = [0u8; 6];
240        let mut first_key = [0u8; 32];
241        let mut second_key = [0u8; 32];
242
243        decoded.read_exact(&mut header)?;
244        let version = decoded.read_u8()?;
245        let mode = decoded.read_u8()?;
246
247        if header != HEADER {
248            return Err(DecodingError::Header);
249        } else if version != VERSION {
250            return Err(DecodingError::Version(version));
251        } else if mode > MAX_MODE {
252            return Err(DecodingError::Mode(mode));
253        }
254
255        let flow_id_len = decoded.read_u16::<BigEndian>()?;
256        let mut flow_id = vec![0; flow_id_len.into()];
257
258        decoded.read_exact(&mut flow_id)?;
259        decoded.read_exact(&mut first_key)?;
260        decoded.read_exact(&mut second_key)?;
261
262        let mut shared_secret = Vec::new();
263
264        decoded.read_to_end(&mut shared_secret)?;
265
266        if shared_secret.len() < MIN_SECRET_LEN {
267            return Err(DecodingError::SharedSecret(shared_secret.len()));
268        }
269
270        let first_key = Ed25519PublicKey::from_slice(&first_key)?;
271        let second_key = Ed25519PublicKey::from_slice(&second_key)?;
272
273        QrVerificationData::new(mode, flow_id, first_key, second_key, shared_secret)
274    }
275
276    fn new(
277        mode: u8,
278        flow_id: Vec<u8>,
279        first_key: Ed25519PublicKey,
280        second_key: Ed25519PublicKey,
281        shared_secret: Vec<u8>,
282    ) -> Result<Self, DecodingError> {
283        let flow_id = String::from_utf8(flow_id)?;
284        let shared_secret = Base64::new(shared_secret);
285
286        match mode {
287            VerificationData::QR_MODE => {
288                Ok(VerificationData::new(flow_id, first_key, second_key, shared_secret).into())
289            }
290            SelfVerificationData::QR_MODE => {
291                Ok(SelfVerificationData::new(flow_id, first_key, second_key, shared_secret).into())
292            }
293            SelfVerificationNoMasterKey::QR_MODE => {
294                Ok(SelfVerificationNoMasterKey::new(flow_id, first_key, second_key, shared_secret)
295                    .into())
296            }
297            m => Err(DecodingError::Mode(m)),
298        }
299    }
300
301    /// Get the flow id for this `QrVerificationData`.
302    ///
303    /// This represents the ID as a string even if it is a `EventId`.
304    pub fn flow_id(&self) -> &str {
305        match self {
306            QrVerificationData::Verification(v) => v.flow_id.as_str(),
307            QrVerificationData::SelfVerification(v) => &v.transaction_id,
308            QrVerificationData::SelfVerificationNoMasterKey(v) => &v.transaction_id,
309        }
310    }
311
312    /// Get the first key of this `QrVerificationData`.
313    pub fn first_key(&self) -> Ed25519PublicKey {
314        match self {
315            QrVerificationData::Verification(v) => v.first_master_key,
316            QrVerificationData::SelfVerification(v) => v.master_key,
317            QrVerificationData::SelfVerificationNoMasterKey(v) => v.device_key,
318        }
319    }
320
321    /// Get the second key of this `QrVerificationData`.
322    pub fn second_key(&self) -> Ed25519PublicKey {
323        match self {
324            QrVerificationData::Verification(v) => v.second_master_key,
325            QrVerificationData::SelfVerification(v) => v.device_key,
326            QrVerificationData::SelfVerificationNoMasterKey(v) => v.master_key,
327        }
328    }
329
330    /// Get the secret of this `QrVerificationData`.
331    pub fn secret(&self) -> &Base64 {
332        match self {
333            QrVerificationData::Verification(v) => &v.shared_secret,
334            QrVerificationData::SelfVerification(v) => &v.shared_secret,
335            QrVerificationData::SelfVerificationNoMasterKey(v) => &v.shared_secret,
336        }
337    }
338}
339
340/// The non-encoded data for the first mode of QR code verification.
341///
342/// This mode is used for verification between two users using their master
343/// cross signing keys.
344#[derive(Clone, Debug, PartialEq, Eq)]
345pub struct VerificationData {
346    flow_id: String,
347    first_master_key: Ed25519PublicKey,
348    second_master_key: Ed25519PublicKey,
349    shared_secret: Base64,
350}
351
352impl VerificationData {
353    const QR_MODE: u8 = 0x00;
354
355    /// Create a new `VerificationData` struct that can be encoded as a QR code.
356    ///
357    /// # Arguments
358    ///
359    /// - `flow_id` - The event ID or transaction ID of the
360    ///   `m.key.verification.request` event that initiated the verification
361    ///   flow this QR code should be part of.
362    ///
363    /// - `first_master_key` - Our own cross signing master key.
364    /// - `second_master_key` - The cross signing master key of the other user.
365    /// - `shared_secret` - A random bytestring encoded as unpadded base64,
366    ///   needs to be at least 8 bytes long.
367    pub fn new(
368        flow_id: String,
369        first_master_key: Ed25519PublicKey,
370        second_master_key: Ed25519PublicKey,
371        shared_secret: Base64,
372    ) -> Self {
373        Self { flow_id, first_master_key, second_master_key, shared_secret }
374    }
375
376    /// Encode the `VerificationData` into a vector of bytes that can be encoded
377    /// as a QR code.
378    ///
379    /// The encoding can fail if the master keys that should be encoded are not
380    /// valid base64.
381    ///
382    /// # Examples
383    ///
384    /// ```
385    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
386    /// # fn main() -> Result<(), DecodingError> {
387    /// let data = b"MATRIX\
388    ///              \x02\x00\x00\x0f\
389    ///              $test:localhost\
390    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
391    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
392    ///              SHARED_SECRET";
393    ///
394    /// let result = QrVerificationData::from_bytes(data)?;
395    /// if let QrVerificationData::Verification(decoded) = result {
396    ///     let encoded = decoded.to_bytes().unwrap();
397    ///     assert_eq!(data.as_ref(), encoded.as_slice());
398    /// } else {
399    ///     panic!("Data was encoded as an incorrect mode");
400    /// }
401    /// # Ok(())
402    /// # }
403    /// ```
404    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
405        to_bytes(
406            Self::QR_MODE,
407            self.flow_id.as_str(),
408            self.first_master_key,
409            self.second_master_key,
410            &self.shared_secret,
411        )
412    }
413
414    /// Encode the `VerificationData` into a `QrCode`.
415    ///
416    /// This method turns the `VerificationData` into a QR code that can be
417    /// rendered and presented to be scanned.
418    ///
419    /// The encoding can fail if the data doesn't fit into a QR code or if the
420    /// keys that should be encoded into the QR code are not valid base64.
421    pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
422        to_qr_code(
423            Self::QR_MODE,
424            self.flow_id.as_str(),
425            self.first_master_key,
426            self.second_master_key,
427            &self.shared_secret,
428        )
429    }
430}
431
432impl From<VerificationData> for QrVerificationData {
433    fn from(data: VerificationData) -> Self {
434        Self::Verification(data)
435    }
436}
437
438/// The non-encoded data for the second mode of QR code verification.
439///
440/// This mode is used for verification between two devices of the same user
441/// where this device, that is creating this QR code, is trusting or owning the
442/// cross signing master key.
443#[derive(Clone, Debug, PartialEq, Eq)]
444pub struct SelfVerificationData {
445    transaction_id: String,
446    master_key: Ed25519PublicKey,
447    device_key: Ed25519PublicKey,
448    shared_secret: Base64,
449}
450
451impl SelfVerificationData {
452    const QR_MODE: u8 = 0x01;
453
454    /// Create a new `SelfVerificationData` struct that can be encoded as a QR
455    /// code.
456    ///
457    /// # Arguments
458    ///
459    /// - `transaction_id` - The transaction id of this verification flow, the
460    ///   transaction id was sent by the `m.key.verification.request` event that
461    ///   initiated the verification flow this QR code should be part of.
462    ///
463    /// - `master_key` - Our own cross signing master key.
464    /// - `device_key` - The ed25519 key of the other device.
465    /// - `shared_secret` - A random bytestring encoded as unpadded base64,
466    ///   needs to be at least 8 bytes long.
467    pub fn new(
468        transaction_id: String,
469        master_key: Ed25519PublicKey,
470        device_key: Ed25519PublicKey,
471        shared_secret: Base64,
472    ) -> Self {
473        Self { transaction_id, master_key, device_key, shared_secret }
474    }
475
476    /// Encode the `SelfVerificationData` into a vector of bytes that can be
477    /// encoded as a QR code.
478    ///
479    /// The encoding can fail if the keys that should be encoded are not valid
480    /// base64.
481    ///
482    /// # Examples
483    ///
484    /// ```
485    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
486    /// # fn main() -> Result<(), DecodingError> {
487    /// let data = b"MATRIX\
488    ///              \x02\x01\x00\x06\
489    ///              FLOWID\
490    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
491    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
492    ///              SHARED_SECRET";
493    ///
494    /// let result = QrVerificationData::from_bytes(data)?;
495    /// if let QrVerificationData::SelfVerification(decoded) = result {
496    ///     let encoded = decoded.to_bytes().unwrap();
497    ///     assert_eq!(data.as_ref(), encoded.as_slice());
498    /// } else {
499    ///     panic!("Data was encoded as an incorrect mode");
500    /// }
501    /// # Ok(())
502    /// # }
503    /// ```
504    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
505        to_bytes(
506            Self::QR_MODE,
507            &self.transaction_id,
508            self.master_key,
509            self.device_key,
510            &self.shared_secret,
511        )
512    }
513
514    /// Encode the `SelfVerificationData` into a `QrCode`.
515    ///
516    /// This method turns the `SelfVerificationData` into a QR code that can be
517    /// rendered and presented to be scanned.
518    ///
519    /// The encoding can fail if the data doesn't fit into a QR code or if the
520    /// keys that should be encoded into the QR code are not valid base64.
521    pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
522        to_qr_code(
523            Self::QR_MODE,
524            &self.transaction_id,
525            self.master_key,
526            self.device_key,
527            &self.shared_secret,
528        )
529    }
530}
531
532impl From<SelfVerificationData> for QrVerificationData {
533    fn from(data: SelfVerificationData) -> Self {
534        Self::SelfVerification(data)
535    }
536}
537
538/// The non-encoded data for the third mode of QR code verification.
539///
540/// This mode is used for verification between two devices of the same user
541/// where this device, that is creating this QR code, is not trusting the cross
542/// signing master key.
543#[derive(Clone, Debug, PartialEq, Eq)]
544pub struct SelfVerificationNoMasterKey {
545    transaction_id: String,
546    device_key: Ed25519PublicKey,
547    master_key: Ed25519PublicKey,
548    shared_secret: Base64,
549}
550
551impl SelfVerificationNoMasterKey {
552    const QR_MODE: u8 = 0x02;
553
554    /// Create a new `SelfVerificationData` struct that can be encoded as a QR
555    /// code.
556    ///
557    /// # Arguments
558    ///
559    /// - `transaction_id` - The transaction id of this verification flow, the
560    ///   transaction id was sent by the `m.key.verification.request` event that
561    ///   initiated the verification flow this QR code should be part of.
562    ///
563    /// - `device_key` - The ed25519 key of our own device.
564    /// - `master_key` - Our own cross signing master key.
565    /// - `shared_secret` - A random bytestring encoded as unpadded base64,
566    ///   needs to be at least 8 bytes long.
567    pub fn new(
568        transaction_id: String,
569        device_key: Ed25519PublicKey,
570        master_key: Ed25519PublicKey,
571        shared_secret: Base64,
572    ) -> Self {
573        Self { transaction_id, device_key, master_key, shared_secret }
574    }
575
576    /// Encode the `SelfVerificationNoMasterKey` into a vector of bytes that can
577    /// be encoded as a QR code.
578    ///
579    /// The encoding can fail if the keys that should be encoded are not valid
580    /// base64.
581    ///
582    /// # Examples
583    ///
584    /// ```
585    /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
586    /// # fn main() -> Result<(), DecodingError> {
587    /// let data = b"MATRIX\
588    ///              \x02\x02\x00\x06\
589    ///              FLOWID\
590    ///              kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
591    ///              \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
592    ///              SHARED_SECRET";
593    ///
594    /// let result = QrVerificationData::from_bytes(data)?;
595    /// if let QrVerificationData::SelfVerificationNoMasterKey(decoded) = result {
596    ///     let encoded = decoded.to_bytes().unwrap();
597    ///     assert_eq!(data.as_ref(), encoded.as_slice());
598    /// } else {
599    ///     panic!("Data was encoded as an incorrect mode");
600    /// }
601    /// # Ok(())
602    /// # }
603    /// ```
604    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
605        to_bytes(
606            Self::QR_MODE,
607            &self.transaction_id,
608            self.device_key,
609            self.master_key,
610            &self.shared_secret,
611        )
612    }
613
614    /// Encode the `SelfVerificationNoMasterKey` into a `QrCode`.
615    ///
616    /// This method turns the `SelfVerificationNoMasterKey` into a QR code that
617    /// can be rendered and presented to be scanned.
618    ///
619    /// The encoding can fail if the data doesn't fit into a QR code or if the
620    /// keys that should be encoded into the QR code are not valid base64.
621    pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
622        to_qr_code(
623            Self::QR_MODE,
624            &self.transaction_id,
625            self.device_key,
626            self.master_key,
627            &self.shared_secret,
628        )
629    }
630}
631
632impl From<SelfVerificationNoMasterKey> for QrVerificationData {
633    fn from(data: SelfVerificationNoMasterKey) -> Self {
634        Self::SelfVerificationNoMasterKey(data)
635    }
636}