Skip to main content

rose_squared_sdk/crypto/
primitives.rs

1// Foundation types for the RO(SE)² + SWiSSSE protocol.
2// Every byte that crosses a trust boundary goes through these types.
3// All secret values implement `Zeroize` so they are wiped from memory on drop.
4
5use zeroize::{Zeroize, ZeroizeOnDrop};
6use serde::{Deserialize, Serialize};
7
8// ── Security parameter ─────────────────────────────────────────────────────────
9/// λ = 256 bits.  All PRF outputs, keys, and tags are this length.
10pub const LAMBDA: usize = 32;
11
12// ── Secret key types ───────────────────────────────────────────────────────────
13
14/// A 256-bit secret key.  Wiped from memory the moment it goes out of scope.
15///
16/// Never clone, print, or log this value.
17#[derive(Zeroize, ZeroizeOnDrop)]
18pub struct SecretKey(pub [u8; LAMBDA]);
19
20impl SecretKey {
21    /// Create from raw bytes (e.g., from HKDF output).
22    pub fn from_bytes(bytes: [u8; LAMBDA]) -> Self {
23        Self(bytes)
24    }
25
26    /// View the raw bytes for use in HMAC/HKDF — no copy.
27    pub fn as_bytes(&self) -> &[u8; LAMBDA] {
28        &self.0
29    }
30}
31
32// ── EDB address tag ────────────────────────────────────────────────────────────
33
34/// A pseudorandom tag that acts as the *address* of one entry in the server EDB.
35///
36/// Derived as:  tag = PRF(K_tag, "tag:" || keyword || index || epoch)
37///
38/// To the server this is indistinguishable from random bytes — it reveals
39/// nothing about the keyword, document, or time of write.
40#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
41pub struct Tag(pub [u8; LAMBDA]);
42
43// ── Encrypted value ────────────────────────────────────────────────────────────
44
45/// An AES-256-GCM ciphertext stored at a Tag address on the server.
46/// Contains:  nonce (12 B) || ciphertext || GCM tag (16 B)
47#[derive(Clone, Debug, Serialize, Deserialize)]
48pub struct EncValue(pub Vec<u8>);
49
50// ── Entry operation ────────────────────────────────────────────────────────────
51
52/// What an EDB entry represents after decryption.
53#[derive(Clone, Debug, Serialize, Deserialize)]
54pub enum EntryOp {
55    /// This keyword indexes this document — a live "add" record.
56    Add,
57}
58
59/// The plaintext payload encrypted inside each `EncValue`.
60/// After decryption the client learns the doc_id this entry refers to.
61#[derive(Clone, Debug, Serialize, Deserialize)]
62pub struct EntryPayload {
63    pub doc_id:    uuid::Uuid,
64    pub op:        EntryOp,
65    /// Milliseconds since UNIX epoch — used for result ordering, never sent in clear.
66    pub timestamp: u64,
67}
68
69// ── Search token ───────────────────────────────────────────────────────────────
70
71/// A SearchToken authorises exactly one search query.
72///
73/// It contains a list of (EDB address, decryption key) pairs — one per live
74/// result.  The server fetches each Tag; the client decrypts each value.
75///
76/// **Forward security**: a token generated at time T cannot read entries
77/// written after T (they have different tags from fresh indices).
78///
79/// **Backward security**: a token generated after a deletion cannot read
80/// the deleted entry (its tag was retired with the old epoch).
81pub struct SearchToken {
82    /// One pair per live entry for this keyword.
83    pub pairs: Vec<(Tag, [u8; LAMBDA])>,
84}
85
86// ── Epoch ──────────────────────────────────────────────────────────────────────
87
88/// A deletion-epoch counter per keyword.
89///
90/// Every time a document is deleted from a keyword's result set the epoch
91/// increments.  All EDB tags for that keyword are re-derived under the new
92/// epoch, so old server entries become permanently unreachable — this gives
93/// **Backward Security Type-II** as defined in the RO(SE)² paper.
94pub type Epoch = u64;