Skip to main content

ghostkey_common/
lib.rs

1use freenet_stdlib::prelude::*;
2use serde::{Deserialize, Serialize};
3
4#[cfg(feature = "crypto")]
5use ed25519_dalek::VerifyingKey;
6
7/// Compute fingerprint for a ghostkey verifying key.
8/// First 8 bytes of BLAKE3(verifying_key_bytes), base58-encoded.
9#[cfg(feature = "crypto")]
10pub fn fingerprint(verifying_key: &VerifyingKey) -> String {
11    let hash = blake3::hash(verifying_key.as_bytes());
12    bs58::encode(&hash.as_bytes()[..8]).into_string()
13}
14
15/// Serialize a value to CBOR bytes.
16pub fn to_cbor<T: Serialize>(value: &T) -> Result<Vec<u8>, String> {
17    let mut buf = Vec::new();
18    ciborium::into_writer(value, &mut buf).map_err(|e| format!("CBOR serialize: {e}"))?;
19    Ok(buf)
20}
21
22/// Deserialize a value from CBOR bytes.
23pub fn from_cbor<T: for<'de> Deserialize<'de>>(bytes: &[u8]) -> Result<T, String> {
24    ciborium::from_reader(bytes).map_err(|e| format!("CBOR deserialize: {e}"))
25}
26
27/// Who requested a ghostkey operation. Runtime-attested, can't be spoofed.
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
29pub enum SignatureRequestor {
30    /// A web application (UI) backed by this contract.
31    WebApp(ContractInstanceId),
32    /// Another delegate on the same node.
33    Delegate(DelegateKey),
34}
35
36/// What the ghostkey delegate actually signs. The raw payload is never signed
37/// alone -- always wrapped with the attested caller identity.
38#[derive(Serialize, Deserialize, Debug, Clone)]
39pub struct ScopedPayload {
40    pub requestor: SignatureRequestor,
41    pub payload: Vec<u8>,
42}
43
44/// Summary info about a stored ghostkey.
45#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
46pub struct GhostKeyInfo {
47    pub fingerprint: String,
48    pub label: Option<String>,
49    /// The delegate certificate info field (encodes donation tier).
50    pub delegate_info: String,
51}
52
53/// Requests from UI or other delegates to the ghostkey delegate.
54#[derive(Serialize, Deserialize, Debug, Clone)]
55pub enum GhostkeyRequest {
56    /// Import a ghostkey from PEM-armored certificate and signing key.
57    /// If master_verifying_key_pem is None, uses the hardcoded Freenet master key.
58    ImportGhostKey {
59        certificate_pem: String,
60        signing_key_pem: String,
61        #[serde(default)]
62        master_verifying_key_pem: Option<String>,
63    },
64    /// List all stored ghostkeys.
65    ListGhostKeys,
66    /// Get details for a specific ghostkey.
67    GetGhostKey { fingerprint: String },
68    /// Get just the public certificate (for sharing with counterparties).
69    GetCertificate { fingerprint: String },
70    /// Delete a stored ghostkey.
71    DeleteGhostKey { fingerprint: String },
72    /// Set a user-friendly label.
73    SetLabel { fingerprint: String, label: String },
74    /// Sign a message. The delegate scopes the signature to the requestor.
75    /// Returns a ScopedPayload signature, not a raw signature.
76    SignMessage {
77        fingerprint: String,
78        message: Vec<u8>,
79    },
80    /// Verify a signed message produced by this delegate.
81    VerifySignedMessage { signed_message: Vec<u8> },
82    /// Grant an application or delegate permission to use a ghostkey.
83    GrantPermission {
84        fingerprint: String,
85        requestor: SignatureRequestor,
86    },
87    /// Revoke a previously granted permission.
88    RevokePermission {
89        fingerprint: String,
90        requestor: SignatureRequestor,
91    },
92    /// List permissions for a ghostkey.
93    ListPermissions { fingerprint: String },
94}
95
96/// Responses from the ghostkey delegate.
97#[derive(Serialize, Deserialize, Debug, Clone)]
98pub enum GhostkeyResponse {
99    ImportResult {
100        fingerprint: String,
101        delegate_info: String,
102    },
103    GhostKeyList {
104        keys: Vec<GhostKeyInfo>,
105    },
106    GhostKeyDetail {
107        fingerprint: String,
108        certificate_pem: String,
109        label: Option<String>,
110        delegate_info: String,
111    },
112    Certificate {
113        fingerprint: String,
114        certificate_pem: String,
115    },
116    SignResult {
117        /// CBOR-serialized ScopedPayload
118        scoped_payload: Vec<u8>,
119        /// Ed25519 signature over the scoped_payload bytes
120        signature: Vec<u8>,
121        /// The certificate PEM, so the verifier has the full chain
122        certificate_pem: String,
123    },
124    VerifyResult {
125        valid: bool,
126        signer_fingerprint: Option<String>,
127        delegate_info: Option<String>,
128        requestor: Option<SignatureRequestor>,
129        message: Option<Vec<u8>>,
130    },
131    Deleted {
132        fingerprint: String,
133    },
134    LabelSet {
135        fingerprint: String,
136        label: String,
137    },
138    PermissionGranted {
139        fingerprint: String,
140        requestor: SignatureRequestor,
141    },
142    PermissionRevoked {
143        fingerprint: String,
144        requestor: SignatureRequestor,
145    },
146    PermissionList {
147        fingerprint: String,
148        requestors: Vec<SignatureRequestor>,
149    },
150    PermissionDenied {
151        fingerprint: String,
152        requestor: SignatureRequestor,
153    },
154    Error {
155        message: String,
156    },
157}