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