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