Skip to main content

securedrop_protocol_minimal/keys/
newsroom.rs

1use rand_core::{CryptoRng, RngCore};
2
3use crate::sign::{DomainTag, Signature, SigningKey, VerifyingKey};
4
5/// Newsroom keypair used for signing.
6pub struct NewsroomKeyPair {
7    sk: SigningKey,
8}
9
10// hax struggles with the debug format function signature, but it is
11// debug only, so we can exclude it from extraction
12#[cfg_attr(hax, hax_lib::exclude)]
13impl core::fmt::Debug for NewsroomKeyPair {
14    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15        // Redacts secret key
16        f.debug_struct("NewsroomKeyPair")
17            .field("vk", &self.sk.vk)
18            .finish_non_exhaustive()
19    }
20}
21
22impl NewsroomKeyPair {
23    pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self, anyhow::Error> {
24        let sk = SigningKey::new(rng)?;
25        Ok(Self { sk })
26    }
27
28    /// Returns the verification key.
29    pub fn verifying_key(&self) -> VerifyingKey {
30        self.sk.vk
31    }
32
33    /// Sign `msg` in domain `D` using the newsroom signing key.
34    pub fn sign<D: DomainTag>(&self, msg: &[u8]) -> Signature<D> {
35        self.sk.sign(msg)
36    }
37
38    /// The newsroom signing key used as a secret.
39    pub fn as_bytes(&self) -> [u8; SigningKey::SEED_LEN] {
40        self.sk.as_bytes()
41    }
42
43    /// Reconstruct a [`NewsroomKeyPair`] from its secret.
44    pub fn from_bytes(seed: [u8; SigningKey::SEED_LEN]) -> Self {
45        Self {
46            sk: SigningKey::from_seed(seed),
47        }
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use proptest::prelude::*;
55
56    proptest! {
57        #[test]
58        fn newsroom_keypair_seed_roundtrip(seed: [u8; SigningKey::SEED_LEN]) {
59            let kp = NewsroomKeyPair::from_bytes(seed);
60            prop_assert_eq!(kp.as_bytes(), seed);
61            let kp2 = NewsroomKeyPair::from_bytes(kp.as_bytes());
62            prop_assert_eq!(
63                kp.verifying_key().into_bytes(),
64                kp2.verifying_key().into_bytes()
65            );
66        }
67    }
68}