securedrop_protocol_minimal/keys/
newsroom.rs1use rand_core::{CryptoRng, RngCore};
2
3use crate::sign::{DomainTag, Signature, SigningKey, VerifyingKey};
4
5pub struct NewsroomKeyPair {
7 vk: VerifyingKey,
8 sk: SigningKey,
9}
10
11#[cfg_attr(hax, hax_lib::exclude)]
14impl core::fmt::Debug for NewsroomKeyPair {
15 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16 f.debug_struct("NewsroomKeyPair")
18 .field("vk", &self.vk)
19 .finish_non_exhaustive()
20 }
21}
22
23impl NewsroomKeyPair {
24 pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self, anyhow::Error> {
25 let sk = SigningKey::new(rng)?;
26 let vk = sk.vk;
27 Ok(Self { sk, vk })
28 }
29
30 pub fn verifying_key(&self) -> VerifyingKey {
32 self.vk
33 }
34
35 pub fn sign<D: DomainTag>(&self, msg: &[u8]) -> Signature<D> {
37 self.sk.sign(msg)
38 }
39
40 pub fn as_bytes(&self) -> [u8; 32] {
42 self.sk.as_bytes()
43 }
44
45 pub fn from_bytes(seed: [u8; 32]) -> Self {
47 let sk = SigningKey::from_seed(seed);
48 let vk = sk.vk;
49 Self { vk, sk }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use proptest::prelude::*;
57
58 proptest! {
59 #[test]
60 fn newsroom_keypair_seed_roundtrip(seed: [u8; 32]) {
61 let kp = NewsroomKeyPair::from_bytes(seed);
62 prop_assert_eq!(kp.as_bytes(), seed);
63 let kp2 = NewsroomKeyPair::from_bytes(kp.as_bytes());
64 prop_assert_eq!(
65 kp.verifying_key().into_bytes(),
66 kp2.verifying_key().into_bytes()
67 );
68 }
69 }
70}