securedrop_protocol_minimal/keys/
fpf.rs1use rand_core::{CryptoRng, RngCore};
2
3use crate::sign::{DomainTag, Signature, SigningKey, VerifyingKey};
4
5pub struct FPFKeyPair {
7 sk: SigningKey,
8}
9
10#[cfg_attr(hax, hax_lib::exclude)]
13impl core::fmt::Debug for FPFKeyPair {
14 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15 f.debug_struct("FPFKeyPair")
16 .field("vk", &self.sk.vk)
17 .finish_non_exhaustive()
18 }
19}
20
21impl FPFKeyPair {
22 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 pub fn verifying_key(&self) -> VerifyingKey {
34 self.sk.vk
35 }
36
37 pub fn sign<D: DomainTag>(&self, msg: &[u8]) -> Signature<D> {
39 self.sk.sign(msg)
40 }
41
42 pub fn as_bytes(&self) -> [u8; SigningKey::SEED_LEN] {
44 self.sk.as_bytes()
45 }
46
47 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 fpf_keypair_seed_roundtrip(seed: [u8; SigningKey::SEED_LEN]) {
63 let kp = FPFKeyPair::from_bytes(seed);
64 prop_assert_eq!(kp.as_bytes(), seed);
65 let kp2 = FPFKeyPair::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}