praborrow_core/lib.rs
1//! Core primitives for distributed ownership enforcement.
2//!
3//! This crate provides `Sovereign<T>`, a wrapper type that tracks ownership
4//! across network boundaries. When a resource is "annexed" (moved to another node),
5//! local access is prohibited.
6//!
7//! # The Garuda Proof System
8//!
9//! With `praborrow-prover`, this crate now supports **formally verified** state
10//! transitions. Use `annex_verified()` to require SMT proof before annexation.
11//!
12//! # Safety
13//! Uses `UnsafeCell` and `AtomicU8` for interior mutability with thread-safety.
14//! The `Send`/`Sync` implementations are safe when `T` is `Send`/`Sync`.
15
16#![cfg_attr(not(feature = "std"), no_std)]
17
18extern crate alloc;
19
20use alloc::string::String;
21use alloc::collections::BTreeMap;
22use core::cell::UnsafeCell;
23use core::marker::PhantomData;
24use core::ops::{Deref, DerefMut};
25use core::sync::atomic::{AtomicU8, Ordering};
26
27/// The state of a Sovereign resource.
28/// 0: Domestic (Local jurisdiction)
29/// 1: Exiled (Foreign jurisdiction - moved to another node)
30#[derive(Debug, PartialEq, Eq, Clone, Copy)]
31#[repr(u8)]
32pub enum SovereignState {
33 Domestic = 0,
34 Exiled = 1,
35}
36
37/// A token that proves a resource has been returned to domestic jurisdiction.
38///
39/// This token is required to call `Sovereign::repatriate`. It can only be constructed
40/// by trusted system components (like the lease manager) that can guarantee the
41/// resource is safe to reclaim.
42pub struct RepatriationToken {
43 _private: (),
44}
45
46impl RepatriationToken {
47 /// Creates a new repatriation token.
48 ///
49 /// # Safety
50 ///
51 /// This function is unsafe because creating a token allows the holder to
52 /// repatriate a sovereign resource. The caller must guarantee that the
53 /// resource is indeed back in domestic jurisdiction and no longer accessed
54 /// remotely.
55 pub unsafe fn new() -> Self {
56 Self { _private: () }
57 }
58}
59
60/// A wrapper that enforces ownership semantics across network boundaries.
61///
62/// "Memory safety with sovereign integrity."
63pub struct Sovereign<T> {
64 inner: UnsafeCell<T>,
65 state: AtomicU8,
66}
67
68/// Error enforcing constitutional invariants.
69#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
70pub enum ConstitutionError {
71 #[error("Invariant violated: {expression}. Values: {values:?}")]
72 InvariantViolation {
73 expression: String,
74 values: BTreeMap<String, String>,
75 },
76}
77
78/// Error returned when accessing a Sovereign resource fails.
79#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
80pub enum SovereigntyError {
81 /// Resource is under foreign jurisdiction (Exiled).
82 #[error("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.")]
83 ForeignJurisdiction,
84}
85
86impl<T> Sovereign<T> {
87 /// Creates a new Sovereign resource under domestic jurisdiction.
88 ///
89 /// # Atomic Ordering
90 ///
91 /// Uses `SeqCst` ordering for maximum safety in distributed scenarios.
92 /// This ensures all threads see state changes in a consistent order,
93 /// which is critical for ownership semantics across network boundaries.
94 #[must_use = "Sovereign resources must be managed carefully"]
95 pub fn new(value: T) -> Self {
96 Self {
97 inner: UnsafeCell::new(value),
98 state: AtomicU8::new(SovereignState::Domestic as u8),
99 }
100 }
101
102 /// Creates a new Sovereign resource that is already under foreign jurisdiction.
103 ///
104 /// This is useful for nodes receiving data that has been transferred from
105 /// another node - the resource starts in an Exiled state.
106 ///
107 /// # Example
108 ///
109 /// ```
110 /// use praborrow_core::{Sovereign, SovereignState};
111 ///
112 /// let foreign_data = Sovereign::new_exiled(42i32);
113 /// assert!(foreign_data.is_exiled());
114 /// ```
115 #[must_use = "Sovereign resources must be managed carefully"]
116 pub fn new_exiled(value: T) -> Self {
117 Self {
118 inner: UnsafeCell::new(value),
119 state: AtomicU8::new(SovereignState::Exiled as u8),
120 }
121 }
122
123 /// Annexes the resource, moving it to foreign jurisdiction.
124 ///
125 /// Once annexed, the resource cannot be accessed locally.
126 /// Access attempts will result in a Sovereignty Violation.
127 #[must_use = "Annexation result should be checked"]
128 pub fn annex(&self) -> Result<(), AnnexError> {
129 let current = self.state.load(Ordering::SeqCst);
130 if current == SovereignState::Exiled as u8 {
131 return Err(AnnexError::AlreadyExiled);
132 }
133
134 // Diplomatically transition state
135 self.state
136 .store(SovereignState::Exiled as u8, Ordering::SeqCst);
137
138 tracing::debug!(
139 from = "Domestic",
140 to = "Exiled",
141 "Resource annexed to foreign jurisdiction"
142 );
143
144 Ok(())
145 }
146
147 /// Returns a reference to the inner value without jurisdiction check.
148 ///
149 /// # Safety
150 ///
151 /// This is safe because we're returning a shared reference and the caller
152 /// is responsible for ensuring the resource is domestic. Use `try_get()`
153 /// for safe access with jurisdiction verification.
154 pub fn inner_ref(&self) -> &T {
155 // SAFETY: We're only reading, and this is safe when called from
156 // contexts that have already verified jurisdiction.
157 unsafe { &*self.inner.get() }
158 }
159
160 /// Returns the current state of the resource.
161 #[inline]
162 pub fn state(&self) -> SovereignState {
163 match self.state.load(Ordering::SeqCst) {
164 0 => SovereignState::Domestic,
165 _ => SovereignState::Exiled,
166 }
167 }
168
169 /// Returns `true` if the resource is under domestic jurisdiction.
170 #[inline]
171 pub fn is_domestic(&self) -> bool {
172 self.state.load(Ordering::SeqCst) == SovereignState::Domestic as u8
173 }
174
175 /// Returns `true` if the resource is under foreign jurisdiction (exiled).
176 #[inline]
177 pub fn is_exiled(&self) -> bool {
178 self.state.load(Ordering::SeqCst) == SovereignState::Exiled as u8
179 }
180
181 /// Attempts to get a reference to the value, returning an error if Exiled.
182 #[must_use = "Check jurisdiction result"]
183 pub fn try_get(&self) -> Result<&T, SovereigntyError> {
184 if self.is_exiled() {
185 return Err(SovereigntyError::ForeignJurisdiction);
186 }
187 // SAFETY: We verified the resource is domestic.
188 unsafe { Ok(&*self.inner.get()) }
189 }
190
191 /// Attempts to get a mutable reference to the value, returning an error if Exiled.
192 #[must_use = "Check jurisdiction result"]
193 pub fn try_get_mut(&mut self) -> Result<&mut T, SovereigntyError> {
194 if self.is_exiled() {
195 return Err(SovereigntyError::ForeignJurisdiction);
196 }
197 // SAFETY: We verified resource is domestic and have &mut self.
198 unsafe { Ok(&mut *self.inner.get()) }
199 }
200
201 /// Repatriates a resource, transitioning it from Exiled back to Domestic.
202 ///
203 /// Requires a `RepatriationToken` as proof that the resource is safe to reclaim.
204 ///
205 /// # Example
206 ///
207 /// ```
208 /// use praborrow_core::{Sovereign, SovereignState, RepatriationToken};
209 ///
210 /// let resource = Sovereign::new(42i32);
211 /// resource.annex().unwrap();
212 /// assert!(resource.is_exiled());
213 ///
214 /// // ... resource is sent to foreign node and returned ...
215 ///
216 /// // SAFETY: construction of token implies safety verification
217 /// let token = unsafe { RepatriationToken::new() };
218 /// resource.repatriate(token);
219 /// assert!(resource.is_domestic());
220 /// ```
221 #[must_use = "Ensure resource is actually repatriated"]
222 pub fn repatriate(&self, _token: RepatriationToken) {
223 let previous = self
224 .state
225 .swap(SovereignState::Domestic as u8, Ordering::SeqCst);
226
227 if previous == SovereignState::Exiled as u8 {
228 tracing::debug!(
229 from = "Exiled",
230 to = "Domestic",
231 "Resource repatriated to domestic jurisdiction"
232 );
233 }
234 }
235
236 /// Checks if the resource is currently domestic, panicking if not.
237 ///
238 /// Used internally by Deref/DerefMut. Prefer `try_get()` for non-panicking access.
239 fn verify_jurisdiction(&self) {
240 if self.is_exiled() {
241 panic!("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.");
242 }
243 }
244}
245
246impl<T> Deref for Sovereign<T> {
247 type Target = T;
248
249 fn deref(&self) -> &Self::Target {
250 self.verify_jurisdiction();
251 // SAFETY: We've verified the resource is domestic, so access is valid.
252 unsafe { &*self.inner.get() }
253 }
254}
255
256impl<T> DerefMut for Sovereign<T> {
257 fn deref_mut(&mut self) -> &mut Self::Target {
258 self.verify_jurisdiction();
259 // SAFETY: We've verified the resource is domestic and have &mut self.
260 unsafe { &mut *self.inner.get() }
261 }
262}
263
264// SAFETY: Sovereign<T> is Send/Sync if T is Send/Sync, as we use AtomicU8 for state
265// and check it before access. The UnsafeCell is protected by the atomic state check.
266unsafe impl<T: Send> Send for Sovereign<T> {}
267unsafe impl<T: Sync> Sync for Sovereign<T> {}
268
269/// Protocol for enforcing constitutional invariants (runtime checks).
270///
271/// Types implementing this trait can validate their internal state against
272/// a set of invariants defined via the `#[derive(Constitution)]` macro.
273pub trait CheckProtocol {
274 /// Enforces all invariants, returning an error if any are violated.
275 ///
276 /// # Returns
277 ///
278 /// - `Ok(())` if all invariants are satisfied
279 /// - `Err(ConstitutionError)` containing a description of the violated invariant
280 ///
281 /// # Example
282 ///
283 /// ```ignore
284 /// use praborrow_core::CheckProtocol;
285 ///
286 /// let data = MyStruct { value: -1 };
287 /// match data.enforce_law() {
288 /// Ok(()) => println!("All invariants satisfied"),
289 /// Err(e) => println!("Invariant violated: {}", e),
290 /// }
291 /// ```
292 fn enforce_law(&self) -> Result<(), ConstitutionError>;
293}
294
295/// A value carrying cryptographic proof of verification.
296///
297/// This type can only be constructed by successful SMT verification.
298/// Its existence in a type signature proves that formal verification occurred.
299///
300/// # Type Safety Guarantee
301///
302/// `ProofCarrying<T>` cannot be forged - the private `_proof` field
303/// ensures only the prover crate can construct it.
304#[derive(Debug)]
305pub struct ProofCarrying<T> {
306 /// The carried value.
307 pub value: T,
308 /// Private marker ensuring construction only via verification.
309 _proof: PhantomData<()>,
310}
311
312impl<T> ProofCarrying<T> {
313 /// Creates a new proof-carrying value.
314 ///
315 /// This should only be called after successful verification.
316 #[doc(hidden)]
317 pub fn new_unchecked(value: T) -> Self {
318 Self {
319 value,
320 _proof: PhantomData,
321 }
322 }
323
324 /// Extracts the inner value, consuming the proof.
325 pub fn into_inner(self) -> T {
326 self.value
327 }
328}
329
330impl<T: Clone> Clone for ProofCarrying<T> {
331 fn clone(&self) -> Self {
332 Self {
333 value: self.value.clone(),
334 _proof: PhantomData,
335 }
336 }
337}
338
339/// Error type for verified annexation operations.
340#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
341pub enum AnnexError {
342 /// Resource is already under foreign jurisdiction.
343 #[error("Resource is already under foreign jurisdiction")]
344 AlreadyExiled,
345 /// SMT verification failed.
346 #[error("Verification failed: {0}")]
347 VerificationFailed(String),
348 /// Prover encountered an error.
349 #[error("Prover error: {0}")]
350 ProverError(String),
351}
352
353/// Error returned when a lease operation fails.
354#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
355pub enum LeaseError {
356 /// Resource is already leased to another holder.
357 #[error("Resource is already leased to another holder")]
358 AlreadyLeased,
359 /// Resource is under foreign jurisdiction.
360 #[error("Resource is under foreign jurisdiction")]
361 ForeignJurisdiction,
362 /// Lease duration must be non-zero.
363 #[error("Lease duration must be non-zero")]
364 InvalidDuration,
365}
366
367/// Represents a lease on a Sovereign resource.
368pub struct Lease<T> {
369 /// The holder's unique identifier.
370 pub holder: u128,
371 /// Duration of the lease.
372 pub duration: core::time::Duration,
373 /// Phantom data for the resource type.
374 _phantom: PhantomData<T>,
375}
376
377impl<T> Lease<T> {
378 /// Creates a new lease.
379 ///
380 /// # Duration Validation
381 ///
382 /// If `duration` is zero, returns `Err(LeaseError::InvalidDuration)`.
383 pub fn new(holder: u128, duration: core::time::Duration) -> Result<Self, LeaseError> {
384 if duration.is_zero() {
385 return Err(LeaseError::InvalidDuration);
386 }
387
388 Ok(Self {
389 holder,
390 duration,
391 _phantom: PhantomData,
392 })
393 }
394
395 /// Returns the duration of the lease.
396 #[inline]
397 pub fn duration(&self) -> core::time::Duration {
398 self.duration
399 }
400
401 /// Returns the holder ID.
402 #[inline]
403 pub fn holder(&self) -> u128 {
404 self.holder
405 }
406}
407
408/// Trait for distributed borrow operations.
409pub trait DistributedBorrow<T> {
410 /// Attempt to acquire a lease on the resource.
411 fn try_hire(
412 &self,
413 candidate_id: u128,
414 term: core::time::Duration,
415 ) -> Result<Lease<T>, LeaseError>;
416}
417
418impl<T> DistributedBorrow<T> for Sovereign<T> {
419 fn try_hire(
420 &self,
421 candidate_id: u128,
422 term: core::time::Duration,
423 ) -> Result<Lease<T>, LeaseError> {
424 let current = self.state.load(Ordering::SeqCst);
425 if current == SovereignState::Exiled as u8 {
426 return Err(LeaseError::AlreadyLeased);
427 }
428
429 // Transition to exiled state (leased)
430 self.state
431 .store(SovereignState::Exiled as u8, Ordering::SeqCst);
432 Lease::<T>::new(candidate_id, term)
433 }
434}
435
436/// Extension trait for Sovereign types whose inner types implement formal verification.
437///
438/// This trait is automatically implemented for `Sovereign<T>` where `T` can be
439/// formally verified via the Garuda Proof System.
440pub trait VerifiedAnnex<T> {
441 /// Annexes the resource after successful formal verification.
442 ///
443 /// Unlike `annex()`, this method requires mathematical proof that all
444 /// invariants are satisfied before the state transition occurs.
445 ///
446 /// # Returns
447 ///
448 /// - `Ok(ProofCarrying<()>)` - Verification passed, resource is now Exiled
449 /// - `Err(AnnexError)` - Verification failed or resource already Exiled
450 ///
451 /// # Example
452 ///
453 /// ```ignore
454 /// use praborrow_core::{Sovereign, VerifiedAnnex};
455 ///
456 /// let resource = Sovereign::new(MyVerifiableStruct { balance: 100 });
457 ///
458 /// // This will run SMT verification before annexing
459 /// match resource.annex_verified() {
460 /// Ok(proof) => println!("Annexation proven safe!"),
461 /// Err(e) => println!("Cannot annex: {}", e),
462 /// }
463 /// ```
464 fn annex_verified(&self) -> Result<ProofCarrying<()>, AnnexError>;
465}
466
467// Note: The actual implementation of VerifiedAnnex requires praborrow-prover,
468// which would create a circular dependency. Instead, the implementation is
469// provided via blanket impl in praborrow-prover or via the facade crate.
470//
471// Users should use the `praborrow` facade crate for full functionality.
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476
477 #[test]
478 fn test_sovereign_new() {
479 let s = Sovereign::new(42i32);
480 assert_eq!(s.state(), SovereignState::Domestic);
481 assert!(s.is_domestic());
482 assert!(!s.is_exiled());
483 }
484
485 #[test]
486 fn test_sovereign_new_exiled() {
487 let s = Sovereign::new_exiled(42i32);
488 assert_eq!(s.state(), SovereignState::Exiled);
489 assert!(s.is_exiled());
490 assert!(!s.is_domestic());
491 }
492
493 #[test]
494 fn test_sovereign_deref() {
495 let s = Sovereign::new(42i32);
496 assert_eq!(*s, 42);
497 }
498
499 #[test]
500 fn test_sovereign_deref_mut() {
501 let mut s = Sovereign::new(42i32);
502 *s = 100;
503 assert_eq!(*s, 100);
504 }
505
506 #[test]
507 fn test_sovereign_annex() {
508 let s = Sovereign::new(42i32);
509 assert!(s.annex().is_ok());
510 assert_eq!(s.state(), SovereignState::Exiled);
511 assert!(s.is_exiled());
512 }
513
514 #[test]
515 fn test_sovereign_double_annex() {
516 let s = Sovereign::new(42i32);
517 assert!(s.annex().is_ok());
518 assert!(s.annex().is_err());
519 }
520
521 #[test]
522 fn test_sovereign_repatriate() {
523 let s = Sovereign::new(42i32);
524 s.annex().unwrap();
525 assert!(s.is_exiled());
526
527 // SAFETY: In test context, we control both sides
528 // SAFETY: In test context, we control both sides
529 let token = unsafe { RepatriationToken::new() };
530 s.repatriate(token);
531 assert!(s.is_domestic());
532
533 // Should be able to access again
534 assert_eq!(*s, 42);
535 }
536
537 #[test]
538 #[should_panic(expected = "SOVEREIGNTY VIOLATION")]
539 fn test_sovereignty_violation() {
540 let s = Sovereign::new(42i32);
541 s.annex().unwrap();
542 let _ = *s; // This should panic
543 }
544
545 #[test]
546 fn test_try_get_domestic() {
547 let s = Sovereign::new(42i32);
548 assert_eq!(*s.try_get().unwrap(), 42);
549 }
550
551 #[test]
552 fn test_try_get_exiled() {
553 let s = Sovereign::new(42i32);
554 s.annex().unwrap();
555 assert!(matches!(
556 s.try_get(),
557 Err(SovereigntyError::ForeignJurisdiction)
558 ));
559 }
560
561 #[test]
562 fn test_proof_carrying() {
563 let proof = ProofCarrying::new_unchecked(42i32);
564 assert_eq!(proof.value, 42);
565 assert_eq!(proof.into_inner(), 42);
566 }
567
568 #[test]
569 fn test_annex_error_display() {
570 let e = AnnexError::AlreadyExiled;
571 assert!(e.to_string().contains("foreign jurisdiction"));
572
573 let e = AnnexError::VerificationFailed("test".to_string());
574 assert!(e.to_string().contains("test"));
575 }
576
577 #[test]
578 fn test_lease_zero_duration_fails() {
579 let lease = Lease::<i32>::new(1, core::time::Duration::ZERO);
580 assert!(matches!(lease, Err(LeaseError::InvalidDuration)));
581 }
582
583 #[test]
584 fn test_lease_normal_duration() {
585 let duration = core::time::Duration::from_secs(10);
586 let lease = Lease::<i32>::new(1, duration).unwrap();
587 assert_eq!(lease.duration(), duration);
588 assert_eq!(lease.holder(), 1);
589 }
590}