securedrop_protocol_minimal/keys/
newsroom.rs1use rand_core::{CryptoRng, RngCore};
2
3use crate::sign::{DomainTag, Signature, SigningKey, VerifyingKey};
4
5pub struct NewsroomKeyPair {
7 sk: SigningKey,
8}
9
10#[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 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 pub fn verifying_key(&self) -> VerifyingKey {
30 self.sk.vk
31 }
32
33 pub fn sign<D: DomainTag>(&self, msg: &[u8]) -> Signature<D> {
35 self.sk.sign(msg)
36 }
37
38 pub fn as_bytes(&self) -> [u8; SigningKey::SEED_LEN] {
40 self.sk.as_bytes()
41 }
42
43 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}