Skip to main content

sumchain_primitives/
legal.rs

1//! SRC-85X Court & Legal Process, Government Benefits Domain
2//!
3//! Privacy-first infrastructure for:
4//! - SRC-851: Case/Docket Anchor
5//! - SRC-852: Legal Process Events
6//! - SRC-853: Court Orders/Judgments
7//! - SRC-854: Government Benefit Determinations
8//! - SRC-855: 85X Proof Profiles
9
10use serde::{Deserialize, Serialize};
11use crate::{Address, BlockHeight, Timestamp};
12use crate::agreement::{AttachmentRef, EncryptionMeta};
13
14// =============================================================================
15// Type Aliases
16// =============================================================================
17
18/// Unique case identifier
19pub type CaseId = [u8; 32];
20/// Legal process event identifier
21pub type ProcessEventId = [u8; 32];
22/// Court order identifier
23pub type OrderId = [u8; 32];
24/// Benefit determination identifier
25pub type BenefitId = [u8; 32];
26/// Policy identifier (SRC-803 compatible)
27pub type PolicyId = [u8; 32];
28/// Proof identifier (SRC-806 compatible)
29pub type ProofId = [u8; 32];
30/// Subject identifier (SRC-801 compatible)
31pub type SubjectId = [u8; 32];
32
33// =============================================================================
34// Domain Separators (for deterministic hashing)
35// =============================================================================
36
37pub const CASE_DOMAIN_SEP: &[u8] = b"SRC851-CASE:";
38pub const CASE_COMMITMENT_SEP: &[u8] = b"SRC851-COMMITMENT:v1:";
39pub const PROCESS_EVENT_DOMAIN_SEP: &[u8] = b"SRC852-EVENT:";
40pub const EVENT_COMMITMENT_SEP: &[u8] = b"SRC852-COMMITMENT:v1:";
41pub const ORDER_DOMAIN_SEP: &[u8] = b"SRC853-ORDER:";
42pub const ORDER_COMMITMENT_SEP: &[u8] = b"SRC853-COMMITMENT:v1:";
43pub const BENEFIT_DOMAIN_SEP: &[u8] = b"SRC854-BENEFIT:";
44pub const DETERMINATION_COMMITMENT_SEP: &[u8] = b"SRC854-DETERMINATION:v1:";
45pub const LEGAL_PROOF_DOMAIN_SEP: &[u8] = b"SRC855-PROOF:";
46
47// =============================================================================
48// SRC-851: Case/Docket Anchor
49// =============================================================================
50
51/// Case type classification
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
53#[repr(u8)]
54pub enum CaseType {
55    /// Civil litigation
56    Civil = 0,
57    /// Criminal proceeding
58    Criminal = 1,
59    /// Administrative proceeding
60    Administrative = 2,
61    /// Family law
62    Family = 3,
63    /// Probate/Estate
64    Probate = 4,
65    /// Bankruptcy
66    Bankruptcy = 5,
67    /// Small claims
68    SmallClaims = 6,
69    /// Arbitration
70    Arbitration = 7,
71    /// Mediation
72    Mediation = 8,
73    /// Regulatory
74    Regulatory = 9,
75    /// Tax court
76    TaxCourt = 10,
77    /// Immigration
78    Immigration = 11,
79    /// Other
80    Other = 255,
81}
82
83/// Case status
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
85#[repr(u8)]
86pub enum CaseStatus {
87    /// Case filed
88    Filed = 0,
89    /// Case active/pending
90    Active = 1,
91    /// Case stayed
92    Stayed = 2,
93    /// Case closed
94    Closed = 3,
95    /// Case dismissed
96    Dismissed = 4,
97    /// Case settled
98    Settled = 5,
99    /// Case consolidated
100    Consolidated = 6,
101    /// Case transferred
102    Transferred = 7,
103    /// Case on appeal
104    OnAppeal = 8,
105    /// Case sealed
106    Sealed = 9,
107}
108
109/// Issuer class for legal process (SRC-802 compatible)
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
111#[repr(u8)]
112pub enum LegalIssuerClass {
113    /// Court system (official)
114    CourtSystem = 0,
115    /// Government agency (official)
116    GovernmentAgency = 1,
117    /// Tribunal
118    Tribunal = 2,
119    /// Arbitration body
120    ArbitrationBody = 3,
121    /// Law firm (Phase 1 - higher risk)
122    LawFirm = 10,
123    /// Notary (Phase 1 - higher risk)
124    Notary = 11,
125    /// Auditor (Phase 1 - higher risk)
126    Auditor = 12,
127    /// Legal aid organization
128    LegalAid = 13,
129    /// Process server
130    ProcessServer = 14,
131    /// Court reporter
132    CourtReporter = 15,
133    /// Guardian ad litem
134    GuardianAdLitem = 16,
135    /// Mediator
136    Mediator = 17,
137    /// Other authorized
138    Other = 255,
139}
140
141impl LegalIssuerClass {
142    /// Check if this is an official (Phase 2) issuer
143    pub fn is_official(&self) -> bool {
144        matches!(self, Self::CourtSystem | Self::GovernmentAgency | Self::Tribunal)
145    }
146
147    /// Check if this is a Phase 1 (lowkey) issuer
148    pub fn is_lowkey(&self) -> bool {
149        matches!(
150            self,
151            Self::LawFirm
152                | Self::Notary
153                | Self::Auditor
154                | Self::LegalAid
155                | Self::ProcessServer
156        )
157    }
158}
159
160/// SRC-851 Case/Docket Anchor
161#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
162pub struct CaseAnchor {
163    /// Unique case identifier
164    pub case_id: CaseId,
165    /// BLAKE3 commitment of case details
166    pub case_commitment: [u8; 32],
167    /// Jurisdiction code (e.g., "US-NY-SDNY", "UK-EWHC")
168    pub jurisdiction_code: String,
169    /// Case type
170    pub case_type: Option<CaseType>,
171    /// Optional public reference (only if user opts in)
172    pub public_reference: Option<String>,
173    /// Policy ID governing this case
174    pub policy_id: PolicyId,
175    /// Issuer class that created this
176    pub issuer_class: LegalIssuerClass,
177    /// Issuer address
178    pub issuer_address: Address,
179    /// Current status
180    pub status: CaseStatus,
181    /// Creation timestamp
182    pub created_at: Timestamp,
183    /// Last update timestamp
184    pub updated_at: Timestamp,
185    /// Block height when anchored
186    pub anchored_at_height: BlockHeight,
187    /// Related case IDs (e.g., for appeals, consolidation)
188    pub related_cases: Vec<CaseId>,
189}
190
191impl CaseAnchor {
192    /// Generate deterministic case ID
193    pub fn generate_id(
194        issuer: &Address,
195        case_commitment: &[u8; 32],
196        jurisdiction: &str,
197        nonce: &[u8; 32],
198    ) -> CaseId {
199        let mut hasher = blake3::Hasher::new();
200        hasher.update(CASE_DOMAIN_SEP);
201        hasher.update(b":v1:");
202        hasher.update(issuer.as_ref());
203        hasher.update(case_commitment);
204        hasher.update(jurisdiction.as_bytes());
205        hasher.update(nonce);
206        *hasher.finalize().as_bytes()
207    }
208
209    /// Generate case commitment from case details
210    pub fn generate_commitment(
211        case_number: &str,
212        parties_commitment: &[u8; 32],
213        filing_date: Timestamp,
214        additional_data: Option<&[u8]>,
215    ) -> [u8; 32] {
216        let mut hasher = blake3::Hasher::new();
217        hasher.update(CASE_COMMITMENT_SEP);
218        hasher.update(case_number.as_bytes());
219        hasher.update(parties_commitment);
220        hasher.update(&filing_date.to_le_bytes());
221        if let Some(data) = additional_data {
222            hasher.update(data);
223        }
224        *hasher.finalize().as_bytes()
225    }
226}
227
228// =============================================================================
229// SRC-852: Legal Process Events
230// =============================================================================
231
232/// Legal process event type
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
234#[repr(u8)]
235pub enum ProcessEventType {
236    // Filing Events (0-9)
237    /// Initial complaint/petition filed
238    Filed = 0,
239    /// Answer/response filed
240    AnswerFiled = 1,
241    /// Motion filed
242    MotionFiled = 2,
243    /// Amendment filed
244    AmendmentFiled = 3,
245    /// Discovery filed
246    DiscoveryFiled = 4,
247    /// Appeal filed
248    AppealFiled = 5,
249
250    // Service Events (10-19)
251    /// Summons served
252    Served = 10,
253    /// Notice delivered
254    NoticeDelivered = 11,
255    /// Subpoena served
256    SubpoenaServed = 12,
257    /// Publication completed
258    PublicationCompleted = 13,
259
260    // Hearing Events (20-29)
261    /// Hearing scheduled
262    HearingScheduled = 20,
263    /// Hearing held
264    HearingHeld = 21,
265    /// Hearing continued
266    HearingContinued = 22,
267    /// Hearing cancelled
268    HearingCancelled = 23,
269    /// Trial started
270    TrialStarted = 24,
271    /// Trial concluded
272    TrialConcluded = 25,
273
274    // Order Events (30-39)
275    /// Order issued
276    OrderIssued = 30,
277    /// Judgment entered
278    JudgmentEntered = 31,
279    /// Ruling issued
280    RulingIssued = 32,
281    /// Verdict rendered
282    VerdictRendered = 33,
283
284    // Status Events (40-49)
285    /// Case stayed
286    CaseStayed = 40,
287    /// Stay lifted
288    StayLifted = 41,
289    /// Case sealed
290    CaseSealed = 42,
291    /// Case unsealed
292    CaseUnsealed = 43,
293    /// Case dismissed
294    CaseDismissed = 44,
295    /// Case settled
296    CaseSettled = 45,
297    /// Case closed
298    CaseClosed = 46,
299    /// Case reopened
300    CaseReopened = 47,
301
302    // Other Events (50-59)
303    /// Evidence admitted
304    EvidenceAdmitted = 50,
305    /// Witness testimony
306    WitnessTestimony = 51,
307    /// Expert opinion
308    ExpertOpinion = 52,
309    /// Mediation completed
310    MediationCompleted = 53,
311    /// Settlement conference
312    SettlementConference = 54,
313
314    /// Other event
315    Other = 255,
316}
317
318/// Event status
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
320#[repr(u8)]
321pub enum ProcessEventStatus {
322    /// Event recorded
323    Recorded = 0,
324    /// Event superseded by later event
325    Superseded = 1,
326    /// Event revoked/withdrawn
327    Revoked = 2,
328    /// Event corrected
329    Corrected = 3,
330}
331
332/// SRC-852 Legal Process Event
333#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
334pub struct ProcessEvent {
335    /// Unique event identifier
336    pub event_id: ProcessEventId,
337    /// Case this event belongs to
338    pub case_id: CaseId,
339    /// Event type
340    pub event_type: ProcessEventType,
341    /// BLAKE3 commitment of event details
342    pub event_commitment: [u8; 32],
343    /// Issuer (must satisfy policy)
344    pub issuer_address: Address,
345    /// Issuer class
346    pub issuer_class: LegalIssuerClass,
347    /// Event time window (start)
348    pub event_time_start: Option<Timestamp>,
349    /// Event time window (end)
350    pub event_time_end: Option<Timestamp>,
351    /// Attachments (encrypted references)
352    pub attachments: Vec<AttachmentRef>,
353    /// Policy ID for this event
354    pub policy_id: PolicyId,
355    /// Revocation reference (SRC-805 compatible)
356    pub revocation_ref: Option<[u8; 32]>,
357    /// Status
358    pub status: ProcessEventStatus,
359    /// Creation timestamp
360    pub created_at: Timestamp,
361    /// Block height when recorded
362    pub recorded_at_height: BlockHeight,
363    /// Supersedes event ID (if this corrects/updates another)
364    pub supersedes: Option<ProcessEventId>,
365}
366
367impl ProcessEvent {
368    /// Generate event ID
369    pub fn generate_id(
370        case_id: &CaseId,
371        event_type: ProcessEventType,
372        issuer: &Address,
373        nonce: &[u8; 32],
374    ) -> ProcessEventId {
375        let mut hasher = blake3::Hasher::new();
376        hasher.update(PROCESS_EVENT_DOMAIN_SEP);
377        hasher.update(b":v1:");
378        hasher.update(case_id);
379        hasher.update(&[event_type as u8]);
380        hasher.update(issuer.as_ref());
381        hasher.update(nonce);
382        *hasher.finalize().as_bytes()
383    }
384
385    /// Generate event commitment
386    pub fn generate_commitment(
387        event_details: &[u8],
388        timestamp: Timestamp,
389        participants_commitment: Option<&[u8; 32]>,
390    ) -> [u8; 32] {
391        let mut hasher = blake3::Hasher::new();
392        hasher.update(EVENT_COMMITMENT_SEP);
393        hasher.update(event_details);
394        hasher.update(&timestamp.to_le_bytes());
395        if let Some(pc) = participants_commitment {
396            hasher.update(pc);
397        }
398        *hasher.finalize().as_bytes()
399    }
400}
401
402// =============================================================================
403// SRC-853: Court Order/Judgment
404// =============================================================================
405
406/// Order type
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
408#[repr(u8)]
409pub enum OrderType {
410    // Preliminary Orders (0-9)
411    /// Temporary restraining order
412    Tro = 0,
413    /// Preliminary injunction
414    PreliminaryInjunction = 1,
415    /// Protective order
416    ProtectiveOrder = 2,
417    /// Discovery order
418    DiscoveryOrder = 3,
419    /// Scheduling order
420    SchedulingOrder = 4,
421
422    // Judgment Types (10-19)
423    /// Default judgment
424    DefaultJudgment = 10,
425    /// Summary judgment
426    SummaryJudgment = 11,
427    /// Final judgment
428    FinalJudgment = 12,
429    /// Consent judgment
430    ConsentJudgment = 13,
431    /// Declaratory judgment
432    DeclaratoryJudgment = 14,
433
434    // Injunctions (20-29)
435    /// Permanent injunction
436    PermanentInjunction = 20,
437    /// Mandatory injunction
438    MandatoryInjunction = 21,
439    /// Prohibitory injunction
440    ProhibitoryInjunction = 22,
441
442    // Financial Orders (30-39)
443    /// Money judgment
444    MoneyJudgment = 30,
445    /// Garnishment order
446    GarnishmentOrder = 31,
447    /// Attachment order
448    AttachmentOrder = 32,
449    /// Restitution order
450    RestitutionOrder = 33,
451    /// Cost order
452    CostOrder = 34,
453
454    // Family/Probate (40-49)
455    /// Child custody order
456    ChildCustodyOrder = 40,
457    /// Support order
458    SupportOrder = 41,
459    /// Divorce decree
460    DivorceDecree = 42,
461    /// Probate order
462    ProbateOrder = 43,
463    /// Guardianship order
464    GuardianshipOrder = 44,
465
466    // Criminal (50-59)
467    /// Sentence
468    Sentence = 50,
469    /// Bail order
470    BailOrder = 51,
471    /// Probation order
472    ProbationOrder = 52,
473    /// Expungement order
474    ExpungementOrder = 53,
475
476    // Administrative (60-69)
477    /// Administrative order
478    AdministrativeOrder = 60,
479    /// Consent decree
480    ConsentDecree = 61,
481    /// Compliance order
482    ComplianceOrder = 62,
483
484    /// Other order type
485    Other = 255,
486}
487
488/// Order status
489#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
490#[repr(u8)]
491pub enum OrderStatus {
492    /// Order is active
493    Active = 0,
494    /// Order is stayed pending appeal
495    Stayed = 1,
496    /// Order has been vacated
497    Vacated = 2,
498    /// Order superseded by another
499    Superseded = 3,
500    /// Order has expired
501    Expired = 4,
502    /// Order fully satisfied/completed
503    Satisfied = 5,
504    /// Order modified
505    Modified = 6,
506    /// Order reversed on appeal
507    Reversed = 7,
508    /// Order affirmed on appeal
509    Affirmed = 8,
510}
511
512/// SRC-853 Court Order/Judgment
513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
514pub struct CourtOrder {
515    /// Unique order identifier
516    pub order_id: OrderId,
517    /// Case this order belongs to
518    pub case_id: CaseId,
519    /// Order type
520    pub order_type: OrderType,
521    /// BLAKE3 commitment of order content
522    pub order_commitment: [u8; 32],
523    /// Issuer address (court/tribunal)
524    pub issuer_address: Address,
525    /// Issuer class
526    pub issuer_class: LegalIssuerClass,
527    /// Current status
528    pub status: OrderStatus,
529    /// When order becomes effective
530    pub effective_from: Timestamp,
531    /// When order expires (if applicable)
532    pub expiry: Option<Timestamp>,
533    /// Policy ID
534    pub policy_id: PolicyId,
535    /// Revocation/expiry reference (SRC-805 compatible)
536    pub revocation_ref: Option<[u8; 32]>,
537    /// Creation timestamp
538    pub created_at: Timestamp,
539    /// Last status change
540    pub updated_at: Timestamp,
541    /// Block height when issued
542    pub issued_at_height: BlockHeight,
543    /// Supersedes another order (if any)
544    pub supersedes_order_id: Option<OrderId>,
545    /// Attachments
546    pub attachments: Vec<AttachmentRef>,
547}
548
549impl CourtOrder {
550    /// Generate order ID
551    pub fn generate_id(
552        case_id: &CaseId,
553        order_type: OrderType,
554        issuer: &Address,
555        nonce: &[u8; 32],
556    ) -> OrderId {
557        let mut hasher = blake3::Hasher::new();
558        hasher.update(ORDER_DOMAIN_SEP);
559        hasher.update(b":v1:");
560        hasher.update(case_id);
561        hasher.update(&[order_type as u8]);
562        hasher.update(issuer.as_ref());
563        hasher.update(nonce);
564        *hasher.finalize().as_bytes()
565    }
566
567    /// Generate order commitment
568    pub fn generate_commitment(
569        order_text_hash: &[u8; 32],
570        obligations_hash: Option<&[u8; 32]>,
571        parties_hash: &[u8; 32],
572    ) -> [u8; 32] {
573        let mut hasher = blake3::Hasher::new();
574        hasher.update(ORDER_COMMITMENT_SEP);
575        hasher.update(order_text_hash);
576        if let Some(oh) = obligations_hash {
577            hasher.update(oh);
578        }
579        hasher.update(parties_hash);
580        *hasher.finalize().as_bytes()
581    }
582
583    /// Check if order is currently in effect
584    pub fn is_in_effect(&self, current_time: Timestamp) -> bool {
585        if !matches!(self.status, OrderStatus::Active | OrderStatus::Affirmed) {
586            return false;
587        }
588        if current_time < self.effective_from {
589            return false;
590        }
591        if let Some(exp) = self.expiry {
592            if current_time >= exp {
593                return false;
594            }
595        }
596        true
597    }
598}
599
600// =============================================================================
601// SRC-854: Government Benefit Determination
602// =============================================================================
603
604/// Benefit type
605#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
606#[repr(u8)]
607pub enum BenefitType {
608    // Social Security (0-9)
609    SocialSecurityRetirement = 0,
610    SocialSecurityDisability = 1,
611    SupplementalSecurityIncome = 2,
612    SurvivorsInsurance = 3,
613
614    // Healthcare (10-19)
615    Medicare = 10,
616    Medicaid = 11,
617    ChildHealthInsurance = 12,
618    VeteranHealthcare = 13,
619
620    // Employment (20-29)
621    UnemploymentInsurance = 20,
622    WorkersCompensation = 21,
623    DisabilityInsurance = 22,
624    TrainingBenefit = 23,
625
626    // Food/Housing (30-39)
627    FoodAssistance = 30,
628    HousingAssistance = 31,
629    EnergyAssistance = 32,
630    ChildNutrition = 33,
631
632    // Family (40-49)
633    ChildTaxCredit = 40,
634    EarnedIncomeCredit = 41,
635    ChildcareAssistance = 42,
636    FamilyLeave = 43,
637
638    // Education (50-59)
639    EducationGrant = 50,
640    StudentLoanSubsidy = 51,
641    TuitionAssistance = 52,
642
643    // Veterans (60-69)
644    VeteranPension = 60,
645    VeteranDisability = 61,
646    GiBill = 62,
647    VeteranHousing = 63,
648
649    // Immigration (70-79)
650    RefugeeAssistance = 70,
651    AsylumSupport = 71,
652
653    /// Other benefit
654    Other = 255,
655}
656
657/// Benefit determination status
658#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
659#[repr(u8)]
660pub enum BenefitStatus {
661    /// Eligibility determination in progress
662    Pending = 0,
663    /// Determined eligible
664    Eligible = 1,
665    /// Benefit approved
666    Approved = 2,
667    /// Benefit denied
668    Denied = 3,
669    /// Benefit terminated
670    Terminated = 4,
671    /// Benefit suspended
672    Suspended = 5,
673    /// Under review/appeal
674    UnderReview = 6,
675    /// Benefit expired
676    Expired = 7,
677    /// Benefit reduced
678    Reduced = 8,
679    /// Benefit increased
680    Increased = 9,
681}
682
683/// SRC-854 Government Benefit Determination
684#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
685pub struct BenefitDetermination {
686    /// Unique benefit identifier
687    pub benefit_id: BenefitId,
688    /// Benefit type
689    pub benefit_type: BenefitType,
690    /// Jurisdiction code
691    pub jurisdiction_code: String,
692    /// Current status
693    pub status: BenefitStatus,
694    /// BLAKE3 commitment of determination details
695    pub determination_commitment: [u8; 32],
696    /// Subject nullifier (for privacy-preserving verification)
697    pub subject_nullifier: [u8; 32],
698    /// Issuer address (government agency)
699    pub issuer_address: Address,
700    /// Issuer class
701    pub issuer_class: LegalIssuerClass,
702    /// When determination becomes valid
703    pub valid_from: Timestamp,
704    /// When determination expires
705    pub expiry: Option<Timestamp>,
706    /// Policy ID
707    pub policy_id: PolicyId,
708    /// Revocation reference (SRC-805 compatible)
709    pub revocation_ref: Option<[u8; 32]>,
710    /// Creation timestamp
711    pub created_at: Timestamp,
712    /// Last update timestamp
713    pub updated_at: Timestamp,
714    /// Block height when recorded
715    pub recorded_at_height: BlockHeight,
716    /// Supersedes another determination (if any)
717    pub supersedes: Option<BenefitId>,
718}
719
720impl BenefitDetermination {
721    /// Generate benefit ID
722    pub fn generate_id(
723        subject_nullifier: &[u8; 32],
724        benefit_type: BenefitType,
725        jurisdiction: &str,
726        nonce: &[u8; 32],
727    ) -> BenefitId {
728        let mut hasher = blake3::Hasher::new();
729        hasher.update(BENEFIT_DOMAIN_SEP);
730        hasher.update(b":v1:");
731        hasher.update(subject_nullifier);
732        hasher.update(&[benefit_type as u8]);
733        hasher.update(jurisdiction.as_bytes());
734        hasher.update(nonce);
735        *hasher.finalize().as_bytes()
736    }
737
738    /// Generate determination commitment
739    pub fn generate_commitment(
740        eligibility_criteria_hash: &[u8; 32],
741        amount_commitment: Option<&[u8; 32]>,
742        conditions_hash: Option<&[u8; 32]>,
743    ) -> [u8; 32] {
744        let mut hasher = blake3::Hasher::new();
745        hasher.update(DETERMINATION_COMMITMENT_SEP);
746        hasher.update(eligibility_criteria_hash);
747        if let Some(ac) = amount_commitment {
748            hasher.update(ac);
749        }
750        if let Some(ch) = conditions_hash {
751            hasher.update(ch);
752        }
753        *hasher.finalize().as_bytes()
754    }
755
756    /// Check if benefit is currently valid
757    pub fn is_valid(&self, current_time: Timestamp) -> bool {
758        if !matches!(
759            self.status,
760            BenefitStatus::Eligible | BenefitStatus::Approved | BenefitStatus::Increased
761        ) {
762            return false;
763        }
764        if current_time < self.valid_from {
765            return false;
766        }
767        if let Some(exp) = self.expiry {
768            if current_time >= exp {
769                return false;
770            }
771        }
772        true
773    }
774}
775
776// =============================================================================
777// SRC-855: 85X Proof Profiles
778// =============================================================================
779
780/// Proof profile types for SRC-85X
781#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
782#[repr(u8)]
783pub enum LegalProofProfile {
784    /// Prove active order of specified type exists
785    ActiveOrderOfType = 0,
786    /// Prove benefit is approved
787    BenefitApproved = 1,
788    /// Prove case event exists (policy-gated)
789    CaseEventExists = 2,
790    /// Prove case status
791    CaseStatus = 3,
792    /// Prove order was issued by valid issuer
793    OrderIssuedByValid = 4,
794    /// Prove benefit eligibility without revealing details
795    BenefitEligible = 5,
796    /// Prove no active orders of type (for clearance checks)
797    NoActiveOrderOfType = 6,
798}
799
800/// Proof type (SRC-806 compatible)
801#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
802#[repr(u8)]
803pub enum LegalProofType {
804    /// Mock proof (for testing)
805    Mock = 0,
806    /// Groth16 ZK-SNARK
807    Groth16 = 1,
808    /// PLONK proof
809    Plonk = 2,
810    /// Threshold signature proof
811    ThresholdSignature = 3,
812    /// Merkle inclusion proof
813    MerkleInclusion = 4,
814}
815
816/// SRC-855 Legal Proof Envelope
817#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
818pub struct LegalProofEnvelope {
819    /// Proof identifier
820    pub proof_id: ProofId,
821    /// Proof profile being proven
822    pub profile: LegalProofProfile,
823    /// Profile version string (e.g., "legal.active_order.v1")
824    pub profile_id: String,
825    /// Policy IDs that were checked
826    pub policy_ids: Vec<PolicyId>,
827    /// Public inputs to the proof
828    pub public_inputs: Vec<u8>,
829    /// The proof data
830    pub proof_data: Vec<u8>,
831    /// Proof type
832    pub proof_type: LegalProofType,
833    /// Subject nullifier (for revocation checking)
834    pub subject_nullifier: [u8; 32],
835    /// When proof was generated
836    pub generated_at: Timestamp,
837    /// When proof expires
838    pub expires_at: Timestamp,
839}
840
841impl LegalProofEnvelope {
842    /// Generate proof ID
843    pub fn generate_id(
844        profile: LegalProofProfile,
845        subject_nullifier: &[u8; 32],
846        policy_ids: &[PolicyId],
847        nonce: &[u8; 32],
848    ) -> ProofId {
849        let mut hasher = blake3::Hasher::new();
850        hasher.update(LEGAL_PROOF_DOMAIN_SEP);
851        hasher.update(b":v1:");
852        hasher.update(&[profile as u8]);
853        hasher.update(subject_nullifier);
854        for policy_id in policy_ids {
855            hasher.update(policy_id);
856        }
857        hasher.update(nonce);
858        *hasher.finalize().as_bytes()
859    }
860}
861
862// =============================================================================
863// Operations
864// =============================================================================
865
866/// SRC-85X Operation codes
867#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
868#[repr(u8)]
869pub enum LegalOperation {
870    // SRC-851: Case Anchor (0-9)
871    AnchorCase = 0,
872    UpdateCase = 1,
873    CloseCase = 2,
874    SealCase = 3,
875    UnsealCase = 4,
876    ConsolidateCase = 5,
877    TransferCase = 6,
878
879    // SRC-852: Process Events (10-19)
880    RecordEvent = 10,
881    UpdateEvent = 11,
882    SupersedeEvent = 12,
883    RevokeEvent = 13,
884
885    // SRC-853: Orders (20-29)
886    IssueOrder = 20,
887    UpdateOrderStatus = 21,
888    StayOrder = 22,
889    VacateOrder = 23,
890    SupersedeOrder = 24,
891    ModifyOrder = 25,
892
893    // SRC-854: Benefits (30-39)
894    DetermineBenefit = 30,
895    UpdateBenefitStatus = 31,
896    TerminateBenefit = 32,
897    SuspendBenefit = 33,
898    ReinstateBenefit = 34,
899
900    // SRC-855: Proof Operations (40-49)
901    SubmitProof = 40,
902    VerifyProof = 41,
903}
904
905/// Transaction data for SRC-85X operations
906#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
907pub struct LegalTxData {
908    pub operation: LegalOperation,
909    pub data: Vec<u8>,
910    /// Token recipient address - the owner of the minted token
911    pub recipient: crate::Address,
912}
913
914// =============================================================================
915// Events
916// =============================================================================
917
918/// SRC-85X Events
919#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
920pub enum LegalEvent {
921    // SRC-851 Events
922    CaseAnchored {
923        case_id: CaseId,
924        jurisdiction: String,
925        case_commitment: [u8; 32],
926        timestamp: Timestamp,
927    },
928    CaseUpdated {
929        case_id: CaseId,
930        new_status: CaseStatus,
931        timestamp: Timestamp,
932    },
933    CaseSealed {
934        case_id: CaseId,
935        timestamp: Timestamp,
936    },
937    CaseUnsealed {
938        case_id: CaseId,
939        timestamp: Timestamp,
940    },
941
942    // SRC-852 Events
943    CaseEventRecorded {
944        case_id: CaseId,
945        event_type: ProcessEventType,
946        issuer: Address,
947        event_hash: [u8; 32],
948        timestamp: Timestamp,
949    },
950    CaseEventSuperseded {
951        old_event_id: ProcessEventId,
952        new_event_id: ProcessEventId,
953        timestamp: Timestamp,
954    },
955
956    // SRC-853 Events
957    OrderIssued {
958        order_id: OrderId,
959        case_id: CaseId,
960        order_type: OrderType,
961        status: OrderStatus,
962        timestamp: Timestamp,
963    },
964    OrderStatusUpdated {
965        order_id: OrderId,
966        new_status: OrderStatus,
967        timestamp: Timestamp,
968    },
969
970    // SRC-854 Events
971    BenefitDetermined {
972        benefit_id: BenefitId,
973        benefit_type: BenefitType,
974        status: BenefitStatus,
975        jurisdiction: String,
976        timestamp: Timestamp,
977    },
978    BenefitUpdated {
979        benefit_id: BenefitId,
980        new_status: BenefitStatus,
981        timestamp: Timestamp,
982    },
983
984    // SRC-855 Events
985    LegalProofSubmitted {
986        proof_id: ProofId,
987        profile: LegalProofProfile,
988        timestamp: Timestamp,
989    },
990    LegalProofVerified {
991        proof_id: ProofId,
992        valid: bool,
993        timestamp: Timestamp,
994    },
995}
996
997#[cfg(test)]
998mod tests {
999    use super::*;
1000
1001    #[test]
1002    fn test_case_id_generation() {
1003        let issuer = Address::new([1u8; 20]);
1004        let commitment = [2u8; 32];
1005        let nonce = [3u8; 32];
1006
1007        let id = CaseAnchor::generate_id(&issuer, &commitment, "US-NY", &nonce);
1008        assert_ne!(id, [0u8; 32]);
1009
1010        // Same inputs = same ID
1011        let id2 = CaseAnchor::generate_id(&issuer, &commitment, "US-NY", &nonce);
1012        assert_eq!(id, id2);
1013
1014        // Different jurisdiction = different ID
1015        let id3 = CaseAnchor::generate_id(&issuer, &commitment, "US-CA", &nonce);
1016        assert_ne!(id, id3);
1017    }
1018
1019    #[test]
1020    fn test_case_commitment() {
1021        let parties = [1u8; 32];
1022        let commitment = CaseAnchor::generate_commitment("2024-CV-12345", &parties, 1000, None);
1023        assert_ne!(commitment, [0u8; 32]);
1024    }
1025
1026    #[test]
1027    fn test_process_event_id() {
1028        let case_id = [1u8; 32];
1029        let issuer = Address::new([2u8; 20]);
1030        let nonce = [3u8; 32];
1031
1032        let id = ProcessEvent::generate_id(&case_id, ProcessEventType::Filed, &issuer, &nonce);
1033        assert_ne!(id, [0u8; 32]);
1034    }
1035
1036    #[test]
1037    fn test_order_id_generation() {
1038        let case_id = [1u8; 32];
1039        let issuer = Address::new([2u8; 20]);
1040        let nonce = [3u8; 32];
1041
1042        let id = CourtOrder::generate_id(&case_id, OrderType::FinalJudgment, &issuer, &nonce);
1043        assert_ne!(id, [0u8; 32]);
1044    }
1045
1046    #[test]
1047    fn test_order_in_effect() {
1048        let order = CourtOrder {
1049            order_id: [1u8; 32],
1050            case_id: [2u8; 32],
1051            order_type: OrderType::FinalJudgment,
1052            order_commitment: [3u8; 32],
1053            issuer_address: Address::new([4u8; 20]),
1054            issuer_class: LegalIssuerClass::CourtSystem,
1055            status: OrderStatus::Active,
1056            effective_from: 1000,
1057            expiry: Some(2000),
1058            policy_id: [5u8; 32],
1059            revocation_ref: None,
1060            created_at: 1000,
1061            updated_at: 1000,
1062            issued_at_height: 100,
1063            supersedes_order_id: None,
1064            attachments: vec![],
1065        };
1066
1067        assert!(!order.is_in_effect(500));  // Before effective
1068        assert!(order.is_in_effect(1500)); // During validity
1069        assert!(!order.is_in_effect(2500)); // After expiry
1070    }
1071
1072    #[test]
1073    fn test_benefit_id_generation() {
1074        let nullifier = [1u8; 32];
1075        let nonce = [2u8; 32];
1076
1077        let id = BenefitDetermination::generate_id(
1078            &nullifier,
1079            BenefitType::SocialSecurityRetirement,
1080            "US",
1081            &nonce,
1082        );
1083        assert_ne!(id, [0u8; 32]);
1084    }
1085
1086    #[test]
1087    fn test_benefit_validity() {
1088        let benefit = BenefitDetermination {
1089            benefit_id: [1u8; 32],
1090            benefit_type: BenefitType::Medicare,
1091            jurisdiction_code: "US".to_string(),
1092            status: BenefitStatus::Approved,
1093            determination_commitment: [2u8; 32],
1094            subject_nullifier: [3u8; 32],
1095            issuer_address: Address::new([4u8; 20]),
1096            issuer_class: LegalIssuerClass::GovernmentAgency,
1097            valid_from: 1000,
1098            expiry: None,
1099            policy_id: [5u8; 32],
1100            revocation_ref: None,
1101            created_at: 1000,
1102            updated_at: 1000,
1103            recorded_at_height: 100,
1104            supersedes: None,
1105        };
1106
1107        assert!(!benefit.is_valid(500));   // Before valid_from
1108        assert!(benefit.is_valid(1500));   // After valid_from, no expiry
1109    }
1110
1111    #[test]
1112    fn test_legal_issuer_class() {
1113        assert!(LegalIssuerClass::CourtSystem.is_official());
1114        assert!(LegalIssuerClass::GovernmentAgency.is_official());
1115        assert!(!LegalIssuerClass::LawFirm.is_official());
1116
1117        assert!(LegalIssuerClass::LawFirm.is_lowkey());
1118        assert!(LegalIssuerClass::Notary.is_lowkey());
1119        assert!(!LegalIssuerClass::CourtSystem.is_lowkey());
1120    }
1121
1122    #[test]
1123    fn test_legal_proof_id() {
1124        let nullifier = [1u8; 32];
1125        let policies = vec![[2u8; 32], [3u8; 32]];
1126        let nonce = [4u8; 32];
1127
1128        let id = LegalProofEnvelope::generate_id(
1129            LegalProofProfile::BenefitApproved,
1130            &nullifier,
1131            &policies,
1132            &nonce,
1133        );
1134        assert_ne!(id, [0u8; 32]);
1135    }
1136}