Skip to main content

deaddrop_core/
sealed.rs

1//! Sealed Drops: application policy until a condition holds.
2//!
3//! `dd.seal-until` is **not** a cryptographic time-lock. Honest nodes refuse to
4//! decrypt before `until`. A dishonest recipient who already has the CEK wrap
5//! can ignore the extension. Prefer key-release / quorum receipts when available.
6
7use crate::store::unix_now;
8use crate::{DdError, DropEnvelope, ErrorCode, Result};
9
10pub const SEAL_UNTIL_EXT: &str = "dd.seal-until";
11pub const SEAL_QUORUM_EXT: &str = "dd.seal-quorum";
12
13pub fn seal_until(env: &DropEnvelope) -> Option<u64> {
14    env.extensions
15        .iter()
16        .find(|e| e.name == SEAL_UNTIL_EXT)
17        .and_then(|e| {
18            if e.data.len() == 8 {
19                Some(u64::from_be_bytes(e.data.clone().try_into().ok()?))
20            } else {
21                None
22            }
23        })
24}
25
26pub fn seal_quorum(env: &DropEnvelope) -> Option<u32> {
27    env.extensions
28        .iter()
29        .find(|e| e.name == SEAL_QUORUM_EXT)
30        .and_then(|e| {
31            if e.data.len() == 4 {
32                Some(u32::from_be_bytes(e.data.clone().try_into().ok()?))
33            } else {
34                None
35            }
36        })
37}
38
39pub fn enforce(env: &DropEnvelope, now: u64, receipt_issuers: u32) -> Result<()> {
40    if let Some(until) = seal_until(env)
41        && now < until
42    {
43        return Err(DdError::protocol(
44            ErrorCode::Ddp1009Sealed,
45            format!("sealed until {until} (policy; not a crypto time-lock)"),
46        ));
47    }
48    if let Some(need) = seal_quorum(env)
49        && receipt_issuers < need
50    {
51        return Err(DdError::protocol(
52            ErrorCode::Ddp1009Sealed,
53            format!("sealed until {need} receipts (have {receipt_issuers})"),
54        ));
55    }
56    let _ = unix_now;
57    Ok(())
58}