libsignal_protocol/keys/
public.rs

1use std::{
2    cmp::{Ord, Ordering},
3    ptr,
4};
5
6use failure::Error;
7
8use crate::{
9    errors::{FromInternalErrorCode, InternalError},
10    raw_ptr::Raw,
11    Context,
12};
13
14/// The public part of an elliptic curve key pair.
15#[derive(Clone, Debug)]
16pub struct PublicKey {
17    pub(crate) raw: Raw<sys::ec_public_key>,
18}
19
20impl PublicKey {
21    /// Deserialize a [`PublicKey`] from the raw key data.
22    pub fn decode_point(ctx: &Context, key: &[u8]) -> Result<PublicKey, Error> {
23        unsafe {
24            let mut raw = ptr::null_mut();
25            sys::curve_decode_point(
26                &mut raw,
27                key.as_ptr(),
28                key.len(),
29                ctx.raw(),
30            )
31            .into_result()?;
32
33            Ok(PublicKey {
34                raw: Raw::from_ptr(raw),
35            })
36        }
37    }
38
39    /// Use this public key to check whether a message matches its signature.
40    pub fn verify_signature(
41        &self,
42        message: &[u8],
43        signature: &[u8],
44    ) -> Result<(), Error> {
45        unsafe {
46            let result = sys::curve_verify_signature(
47                self.raw.as_const_ptr(),
48                message.as_ptr(),
49                message.len(),
50                signature.as_ptr(),
51                signature.len(),
52            );
53
54            if result == 1 {
55                Ok(())
56            } else if result == 0 {
57                Err(failure::err_msg("Invalid signature"))
58            } else if let Some(err) = InternalError::from_error_code(result) {
59                Err(err.into())
60            } else {
61                Err(failure::format_err!("Unknown error code: {}", result))
62            }
63        }
64    }
65}
66
67impl Ord for PublicKey {
68    fn cmp(&self, other: &PublicKey) -> Ordering {
69        let cmp = unsafe {
70            sys::ec_public_key_compare(
71                self.raw.as_const_ptr(),
72                other.raw.as_const_ptr(),
73            )
74        };
75
76        if cmp < 0 {
77            Ordering::Less
78        } else if cmp > 0 {
79            Ordering::Greater
80        } else {
81            Ordering::Equal
82        }
83    }
84}
85
86impl PartialEq for PublicKey {
87    fn eq(&self, other: &PublicKey) -> bool {
88        self.cmp(other) == Ordering::Equal
89    }
90}
91
92impl Eq for PublicKey {}
93
94impl PartialOrd for PublicKey {
95    fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering> {
96        Some(self.cmp(other))
97    }
98}
99
100impl_serializable!(PublicKey, ec_public_key_serialize, asd);
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[cfg(any(feature = "crypto-native", feature = "crypto-openssl"))]
107    #[test]
108    fn decode_from_binary() {
109        cfg_if::cfg_if! {
110            if #[cfg(feature = "crypto-native")] {
111                type Crypto = crate::crypto::DefaultCrypto;
112            } else if #[cfg(feature = "crypto-openssl")] {
113                type Crypto = crate::crypto::OpenSSLCrypto;
114            } else {
115                compile_error!("These tests require one of the crypto features to be enabled");
116            }
117        }
118        let ctx = Context::new(Crypto::default()).unwrap();
119        let public = &[
120            0x05, 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf,
121            0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78,
122            0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28,
123        ];
124
125        let _got = PublicKey::decode_point(&ctx, public).unwrap();
126    }
127}