tawasuyu

tawasuyu/mirada

Sovereign tiling Wayland compositor + window manager in Rust, on Llimphi.

Rust 50Markdown 30TOML 211282 Definitions

⎇ 3dc85ebdcdd5fda0a1be0db5f8fbce5859266f2e shared/format/src/firma.rs Rust · 222 lines · 11.4 KB History Who touched what raw

feat: mirada standalone — compositor Wayland + WM sobre Llimphi (build magro) 3dc85ebdc · Sergio ·

1use super::*;
2
3// =============================================================================
4//  Fase 67 :: la CONCESION DE CAPACIDAD — "que binario puede hacer que", firmado
5// -----------------------------------------------------------------------------
6//  Hoy los permisos de una app viven en su `EntradaApp` del manifiesto: el
7//  manifiesto firmado dice "el bytecode X corre con permisos P". El binding es
8//  tan fuerte como el manifiesto — re-firmar un manifiesto nuevo basta para
9//  darle al MISMO binario permisos distintos. La concesion eleva ese binding a
10//  un hecho INDEPENDIENTE del manifiesto: una firma Ed25519 de una llave del
11//  `AGORA_AUTH_RING` sobre el par `(hash_bytecode, permisos)`. La firma viaja
12//  con el binario y NINGUN manifiesto puede escalar un binario mas alla de lo
13//  que su concesion autoriza —el kernel toma la INTERSECCION, ver
14//  [`permisos_efectivos`]—. Gemelo estructural de [`ManifiestoFirmado`]: la
15//  verificacion comparte el camino Ring 0 zero-alloc de `ed25519-compact`, pero
16//  el mensaje firmado es [`mensaje_capacidad`], no el hash pelado.
17// =============================================================================
18
19/// Una concesion de capacidad firmada: liga inmutablemente un bytecode (por su
20/// hash BLAKE3) a un bitfield de permisos, respaldada por la firma de una
21/// identidad soberana. Es un objeto del grafo (direccionado por contenido) que
22/// un `EntradaApp` referencia; el kernel la verifica contra el `AGORA_AUTH_RING`
23/// antes de enlazar capacidad alguna.
24#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
25pub struct ConcesionCapacidad {
26    /// Hash BLAKE3 del objeto-bytecode WASM al que esta concesion aplica. La
27    /// firma lo cubre: una concesion para el bytecode X jamas vale para Y.
28    pub bytecode: Hash,
29    /// Bitfield de permisos que esta concesion AUTORIZA para ese bytecode (ver
30    /// [`Permisos`] y las constantes `PERMISO_*`). Subir un bit invalida la firma.
31    pub permisos: Permisos,
32    /// Llave publica Ed25519 de quien concede. El kernel exige que habite el
33    /// `AGORA_AUTH_RING` antes de gastar un ciclo en criptografia.
34    pub autor: AgoraId,
35    /// Firma Ed25519 sobre [`mensaje_capacidad`]`(bytecode, permisos)`.
36    #[serde(with = "BigArray")]
37    pub firma: Firma,
38}
39
40impl ConcesionCapacidad {
41    /// Serializa la concesion a `postcard` — la carga util del objeto del grafo
42    /// que la aloja.
43    pub fn serializar(&self) -> Result<Vec<u8>, &'static str> {
44        postcard::to_allocvec(self)
45            .map_err(|_| "concesion_capacidad :: serializacion fallida")
46    }
47
48    /// Reconstruye una concesion desde su forma binaria. Tolera bytes
49    /// sobrantes tras la estructura — el relleno del registro.
50    pub fn deserializar(bytes: &[u8]) -> Result<ConcesionCapacidad, &'static str> {
51        postcard::take_from_bytes::<ConcesionCapacidad>(bytes)
52            .map(|(c, _)| c)
53            .map_err(|_| "concesion_capacidad :: deserializacion fallida")
54    }
55}
56
57// =============================================================================
58//  Overlay de revocacion del plano de CONTROL (SDD-rotacion-revocacion §4)
59// -----------------------------------------------------------------------------
60//  El AGORA_AUTH_RING del kernel es `const` en `.rodata`: rotar el ancla = reflash
61//  deliberado. Pero entre reflasheos una clave soberana puede filtrarse, y esperar
62//  al re-forjado deja una ventana abierta. El overlay la cierra: un objeto del
63//  grafo, anclado por el manifiesto (`Manifiesto::overlay_revocacion`), que lista
64//  revocaciones firmadas M-of-N por el RESTO del anillo. El kernel lo lee FRESH en
65//  el arranque y deniega en `autor_en_anillo` toda clave del anillo revocada.
66//
67//  Tipos `no_std + alloc`: el kernel los deserializa (postcard) y los verifica con
68//  `claves::verificar_revocacion` sobre el canonico de `mensaje_revocacion_clave`.
69//  El productor host-side (`agora-cli wawa revocar`) emite el mismo wire.
70//
71//  TIEMPO: el kernel hoy lleva ticks PIT, no wall-clock. Aplica la revocacion
72//  mientras este ANCLADA (fail-closed, deny-wins); `vence_en` entra en el canonico
73//  firmado pero la auto-caducidad temporal espera un RTC. Des-revocar = anclar un
74//  overlay nuevo sin esa entrada (gemelo de mover el puntero de `configuracion`).
75// =============================================================================
76
77/// Version del format del [`OverlayRevocacion`] serializado.
78pub const VERSION_OVERLAY: u32 = 1;
79
80/// Una firma individual dentro de una [`RevocacionFirmada`]: la pubkey del
81/// firmante y su firma Ed25519 sobre el canonico de la revocacion. Espejo
82/// minimo de `agora_core::SingleSig` (sin el `IdentityId` redundante: el kernel
83/// re-deriva la autoridad comparando la pubkey contra el `AGORA_AUTH_RING`).
84#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
85pub struct FirmaRevocacion {
86    /// Clave publica Ed25519 del firmante (un miembro del anillo, en control).
87    pub autor: AgoraId,
88    /// Firma Ed25519 sobre [`mensaje_revocacion_clave`]`(objetivo, motivo,
89    /// emitida_en, vence_en)`.
90    #[serde(with = "BigArray")]
91    pub firma: Firma,
92}
93
94/// Una revocacion de clave firmada por un quorum, en forma de wire para el
95/// overlay. Espejo de `agora_core::Revocation` aplanado para el kernel: el
96/// `motivo` es el discriminante estable de `RevReason` (0=Compromised,
97/// 1=Retired, 2=Superseded) y `firmantes` es la multifirma desnuda.
98#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
99pub struct RevocacionFirmada {
100    /// La clave que se revoca (en el plano de control, una del anillo).
101    pub objetivo: AgoraId,
102    /// Motivo (entra en el canonico firmado): 0=Compromised, 1=Retired, 2=Superseded.
103    pub motivo: u8,
104    /// Segundos UNIX desde cuando rige.
105    pub emitida_en: u64,
106    /// `None` ⇒ permanente; `Some(t)` ⇒ suspension hasta `t` (auto-caducidad
107    /// pendiente de RTC en el kernel — ver nota de tiempo arriba).
108    pub vence_en: Option<u64>,
109    /// Las firmas del quorum autorizador.
110    pub firmantes: Vec<FirmaRevocacion>,
111}
112
113/// El overlay de revocacion: la lista de revocaciones que el kernel consulta al
114/// arrancar. Objeto del grafo direccionado por contenido; el manifiesto guarda
115/// su hash en `overlay_revocacion`.
116#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
117pub struct OverlayRevocacion {
118    /// Version del format — debe ser [`VERSION_OVERLAY`].
119    pub version: u32,
120    /// Las revocaciones vigentes. El kernel aplica las que apunten a un slot del
121    /// anillo y reunan el quorum; ignora el resto (no son su jurisdiccion).
122    pub revocaciones: Vec<RevocacionFirmada>,
123}
124
125impl OverlayRevocacion {
126    /// Serializa el overlay a `postcard` — la carga util del objeto del grafo
127    /// que lo aloja.
128    pub fn serializar(&self) -> Result<Vec<u8>, &'static str> {
129        postcard::to_allocvec(self).map_err(|_| "overlay_revocacion :: serializacion fallida")
130    }
131
132    /// Reconstruye un overlay desde su forma binaria. Rechaza una version de
133    /// format desconocida en lugar de malinterpretarla. Tolera bytes sobrantes
134    /// tras la estructura — el relleno del registro.
135    pub fn deserializar(bytes: &[u8]) -> Result<OverlayRevocacion, &'static str> {
136        let (overlay, _) = postcard::take_from_bytes::<OverlayRevocacion>(bytes)
137            .map_err(|_| "overlay_revocacion :: deserializacion fallida")?;
138        if overlay.version != VERSION_OVERLAY {
139            return Err("overlay_revocacion :: version de format desconocida");
140        }
141        Ok(overlay)
142    }
143}
144
145// =============================================================================
146//  Fase 37 :: el sello criptografico del CUADERNO SOBERANO
147// -----------------------------------------------------------------------------
148//  La integridad de un cuaderno —un nodo del grafo cuyo payload es
149//  `Vec<CeldaWawa>` (Fase 43, modelo unificado)— se proteje en dos planos:
150//
151//    * Localmente, el direccionamiento por contenido garantiza que un
152//      bit alterado en cualquier celda cambia el hash del cuaderno
153//      —y ese hash es la identidad del nodo en el almacen—.
154//    * En la red capa-2 (Akasha), eso no basta: un peer hostil puede
155//      reescribir el cuaderno entero y reanunciarlo con su propio hash.
156//      Para que el sistema reconozca un cuaderno como SOBERANO del
157//      operador local, el peer ha de adjuntar una firma Ed25519 del
158//      cuaderno_raiz_hash producida con la clave privada que pertenece
159//      a la `AGORA_PUBLIC_KEY_LOCAL` empotrada en el binario del kernel.
160//
161//  Gemelo estructural de `ManifiestoFirmado`: la verificacion comparte
162//  el camino Ring 0 zero-alloc de `ed25519-compact`.
163// =============================================================================
164
165/// Sobre criptografico de un cuaderno: vincula su `hash` con un autor y
166/// una firma Ed25519. Sin este sobre, un cuaderno es solo un nodo mas
167/// del grafo — con el sobre, queda anclado como SOBERANO al usuario
168/// que firmo, y el kernel lo distingue de cualquier otro nodo cuaderno
169/// que viaje por la red.
170#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
171pub struct CuadernoFirmado {
172    /// Hash BLAKE3 del cuaderno propuesto. El payload del cuaderno es
173    /// `Vec<CeldaWawa>` serializado con postcard; este hash es el
174    /// resumen criptografico que va a engrapar la firma.
175    pub cuaderno_raiz_hash: Hash,
176    /// Llave publica Ed25519 del autor. El kernel la compara contra
177    /// `AGORA_PUBLIC_KEY_LOCAL` antes de gastar un ciclo en criptografia
178    /// — un autor ajeno cae con `CapacidadInsuficiente`.
179    pub autor: AgoraId,
180    /// Firma Ed25519 sobre los 32 bytes de `cuaderno_raiz_hash`.
181    #[serde(with = "BigArray")]
182    pub firma: Firma,
183}
184
185impl CuadernoFirmado {
186    /// Serializa el sobre a su forma binaria `postcard`. La forma cruda
187    /// ocupa 32 + 32 + 64 = 128 bytes; postcard agrega un preludio
188    /// minusculo (longitudes varint) que mantiene el sobre bajo 140 B.
189    pub fn serializar(&self) -> Result<Vec<u8>, &'static str> {
190        postcard::to_allocvec(self)
191            .map_err(|_| "cuaderno_firmado :: serializacion fallida")
192    }
193
194    /// Reconstruye un sobre desde su forma binaria. Tolera bytes
195    /// sobrantes tras la estructura — el relleno del registro o el
196    /// padding del payload del syscall.
197    pub fn deserializar(bytes: &[u8]) -> Result<CuadernoFirmado, &'static str> {
198        postcard::take_from_bytes::<CuadernoFirmado>(bytes)
199            .map(|(cf, _)| cf)
200            .map_err(|_| "cuaderno_firmado :: deserializacion fallida")
201    }
202}
203
204/// Una entrada del historial de un canal: una raiz de manifiesto, el instante
205/// en que el autor la propuso, y la firma Ed25519 con la que el autor la
206/// respalda. La firma se calcula sobre [`mensaje_a_firmar`].
207#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
208pub struct RaizFirmada {
209    /// Instante en que el autor propuso esta raiz, segundos desde UNIX epoch.
210    /// Un receptor desconfia de raices con timestamp futuro mas alla de un
211    /// margen razonable —proteccion barata contra anuncios envenenados—.
212    pub timestamp: u64,
213    /// El hash del [`Manifiesto`] que esta raiz inaugura. Re-anclar el
214    /// superbloque a este hash es, literalmente, "actualizar a esta version".
215    pub raiz_manifiesto: Hash,
216    /// La firma Ed25519 del autor del canal sobre [`mensaje_a_firmar`].
217    /// `serde` no derivara `Deserialize` para `[u8; 64]` sin ayuda —su soporte
218    /// directo se detiene en 32 bytes—; `serde-big-array` cierra ese hueco.
219    #[serde(with = "BigArray")]
220    pub firma: Firma,
221}
222