nx_twin_key.nx source
↩ module page · 220 lines · 7583 B
1// nx_twin_key.nx -- two-party authorized bypass (Captain Moroni).
2//
3// Per [[feedback-captain-moroni-doctrine]]: "Twin-key authorized for
4// any operation that could harm... family-controlled override
5// mechanism: when genuine self-defense requires non-default capability,
6// the family (twin-key holders) can authorize a TIME-LIMITED bypass.
7// All bypass events logged in books. Audit trail accessible to
8// family."
9//
10// THE FAMILY OVERRIDE PRIMITIVE. Some operations (e.g., SANCTUARY-
11// mode emergency cellular activation, drone deployment in extremis,
12// temporary capability grant beyond cell's default brane) require
13// TWO party signatures from designated key-holders. Time-limited.
14// Loud journaling. Captain Moroni's discipline of legitimate
15// self-defense.
16//
17// Composes:
18// nx_intent -- twin-key authorizes Defensive intent in restricted contexts
19// nx_brane -- post-twin-key grant becomes a time-limited capability
20// nx_transponder_quiescence -- SANCTUARY emergency authorize_emergency
21// is the consumer
22// nx_drone_doctrine -- twin-key required for real-world flight (V2)
23// nx_evict_journal -- every twin-key event logged loudly
24
25import "nx_syscalls.nx"
26import "nx_tier.nx"
27
28const NX_TK_OK: nx_int = 0
29const NX_TK_ERR_FULL: nx_int = 1
30const NX_TK_ERR_BAD_HOLDERS: nx_int = 2 // same key-holder cannot self-sign
31const NX_TK_ERR_NOT_PENDING: nx_int = 3
32const NX_TK_ERR_EXPIRED: nx_int = 4
33const NX_TK_ERR_BAD_PURPOSE: nx_int = 5
34const NX_TK_ERR_NOT_FOUND: nx_int = 6
35const NX_TK_GRANTED: nx_int = 7
36
37// ===== Sealed enum: NxTwinKeyPurpose ===============================
38
39const NX_TKP_EMERGENCY_CELLULAR: nx_int = 0
40const NX_TKP_DRONE_DEPLOYMENT: nx_int = 1
41const NX_TKP_SANCTUARY_TEMP_OPEN: nx_int = 2
42const NX_TKP_CAP_GRANT_OVERRIDE: nx_int = 3
43const NX_TKP_FIRMWARE_UPDATE: nx_int = 4
44const NX_TKP_FAMILY_DATA_MIGRATION: nx_int = 5
45const NX_TKP_N_PURPOSES: nx_int = 6
46
47// ===== Sealed enum: NxTwinKeyState =================================
48
49const NX_TKS_PROPOSED: nx_int = 0
50const NX_TKS_PARTIAL: nx_int = 1 // one signature received
51const NX_TKS_AUTHORIZED: nx_int = 2 // both signatures received
52const NX_TKS_EXPIRED: nx_int = 3
53const NX_TKS_REVOKED: nx_int = 4
54const NX_TKS_N_STATES: nx_int = 5
55
56// ===== Struct: NxTwinKeyRequest ====================================
57
58struct NxTwinKeyRequest {
59 request_id: nx_int,
60 purpose: nx_int,
61 key_holder_a: nx_int, // first authorized signer
62 key_holder_b: nx_int, // second authorized signer
63 signed_by_a: nx_int,
64 signed_by_b: nx_int,
65 state: nx_int,
66 proposed_us: nx_size,
67 expires_us: nx_size,
68}
69
70struct NxTwinKeyLedger {
71 requests: *NxTwinKeyRequest,
72 capacity: nx_size,
73 count: nx_size,
74}
75
76const NX_TK_REQ_BYTES: nx_size = 72
77
78func nx_tkp_is_valid(p: nx_int) -> nx_int {
79 if p < 0 { return 0 }
80 if p >= NX_TKP_N_PURPOSES { return 0 }
81 return 1
82}
83
84func nx_tks_is_valid(s: nx_int) -> nx_int {
85 if s < 0 { return 0 }
86 if s >= NX_TKS_N_STATES { return 0 }
87 return 1
88}
89
90func nx_twin_key_ledger_new(capacity: nx_size) -> *NxTwinKeyLedger {
91 let l: *NxTwinKeyLedger = (sys_mmap(24)) as *NxTwinKeyLedger
92 let bytes: nx_size = capacity * NX_TK_REQ_BYTES
93 l.requests = (sys_mmap(bytes)) as *NxTwinKeyRequest
94 l.capacity = capacity
95 l.count = 0
96 return l
97}
98
99func _tk_at(l: *NxTwinKeyLedger, idx: nx_size) -> *NxTwinKeyRequest {
100 return (l.requests as i64 + (idx as i64) * NX_TK_REQ_BYTES) as *NxTwinKeyRequest
101}
102
103func _tk_find(l: *NxTwinKeyLedger, request_id: nx_int) -> nx_int {
104 var i: nx_size = 0
105 while i < l.count {
106 let r: *NxTwinKeyRequest = _tk_at(l, i)
107 if r.request_id == request_id { return i as i64 }
108 i = i + 1
109 }
110 return -1
111}
112
113// ===== nx_twin_key_propose =========================================
114
115func nx_twin_key_propose(l: *NxTwinKeyLedger,
116 request_id: nx_int,
117 purpose: nx_int,
118 key_holder_a: nx_int,
119 key_holder_b: nx_int,
120 now_us: nx_size,
121 ttl_us: nx_size) -> nx_int {
122 if nx_tkp_is_valid(purpose) == 0 { return NX_TK_ERR_BAD_PURPOSE }
123 if key_holder_a == key_holder_b { return NX_TK_ERR_BAD_HOLDERS }
124 if l.count >= l.capacity { return NX_TK_ERR_FULL }
125 let r: *NxTwinKeyRequest = _tk_at(l, l.count)
126 r.request_id = request_id
127 r.purpose = purpose
128 r.key_holder_a = key_holder_a
129 r.key_holder_b = key_holder_b
130 r.signed_by_a = 0
131 r.signed_by_b = 0
132 r.state = NX_TKS_PROPOSED
133 r.proposed_us = now_us
134 r.expires_us = now_us + ttl_us
135 l.count = l.count + 1
136 return NX_TK_OK
137}
138
139// ===== nx_twin_key_sign =============================================
140//
141// One key-holder signs. Transitions PROPOSED -> PARTIAL on first
142// signature; PARTIAL -> AUTHORIZED on second. Wrong-holder rejected.
143
144func nx_twin_key_sign(l: *NxTwinKeyLedger,
145 request_id: nx_int,
146 signer_id: nx_int,
147 now_us: nx_size) -> nx_int {
148 let idx: nx_int = _tk_find(l, request_id)
149 if idx < 0 { return NX_TK_ERR_NOT_FOUND }
150 let r: *NxTwinKeyRequest = _tk_at(l, idx as nx_size)
151 if now_us > r.expires_us {
152 r.state = NX_TKS_EXPIRED
153 return NX_TK_ERR_EXPIRED
154 }
155 if r.state == NX_TKS_AUTHORIZED { return NX_TK_OK } // idempotent
156 if r.state == NX_TKS_EXPIRED { return NX_TK_ERR_EXPIRED }
157 if r.state == NX_TKS_REVOKED { return NX_TK_ERR_NOT_PENDING }
158
159 if signer_id == r.key_holder_a {
160 r.signed_by_a = 1
161 } else {
162 if signer_id == r.key_holder_b {
163 r.signed_by_b = 1
164 } else {
165 return NX_TK_ERR_NOT_PENDING
166 }
167 }
168 if r.signed_by_a == 1 {
169 if r.signed_by_b == 1 {
170 r.state = NX_TKS_AUTHORIZED
171 return NX_TK_GRANTED
172 }
173 }
174 r.state = NX_TKS_PARTIAL
175 return NX_TK_OK
176}
177
178// ===== nx_twin_key_check ============================================
179//
180// Predicate: is request currently AUTHORIZED + not expired?
181// Returns NX_TK_GRANTED if so.
182
183func nx_twin_key_check(l: *NxTwinKeyLedger,
184 request_id: nx_int,
185 now_us: nx_size) -> nx_int {
186 let idx: nx_int = _tk_find(l, request_id)
187 if idx < 0 { return NX_TK_ERR_NOT_FOUND }
188 let r: *NxTwinKeyRequest = _tk_at(l, idx as nx_size)
189 if now_us > r.expires_us {
190 r.state = NX_TKS_EXPIRED
191 return NX_TK_ERR_EXPIRED
192 }
193 if r.state == NX_TKS_AUTHORIZED { return NX_TK_GRANTED }
194 return NX_TK_ERR_NOT_PENDING
195}
196
197// ===== nx_twin_key_revoke ===========================================
198
199func nx_twin_key_revoke(l: *NxTwinKeyLedger, request_id: nx_int) -> nx_int {
200 let idx: nx_int = _tk_find(l, request_id)
201 if idx < 0 { return NX_TK_ERR_NOT_FOUND }
202 let r: *NxTwinKeyRequest = _tk_at(l, idx as nx_size)
203 r.state = NX_TKS_REVOKED
204 return NX_TK_OK
205}
206
207func nx_twin_key_count(l: *NxTwinKeyLedger) -> nx_size {
208 return l.count
209}
210
211func nx_twin_key_count_by_state(l: *NxTwinKeyLedger, state: nx_int) -> nx_int {
212 var hits: nx_int = 0
213 var i: nx_size = 0
214 while i < l.count {
215 let r: *NxTwinKeyRequest = _tk_at(l, i)
216 if r.state == state { hits = hits + 1 }
217 i = i + 1
218 }
219 return hits
220}