Repository navigation
Expand file tree
/
Copy pathShieldedPool.tla
More file actions
179 lines (152 loc) · 5.7 KB
/
Copy pathShieldedPool.tla
File metadata and controls
179 lines (152 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
---- MODULE ShieldedPool ----
\* ShieldedPool - TLA+ Formal Specification
\* Models encrypted balance operations from ShieldedPool.java
\*
\* Verified Properties:
\* - PrivacyPreserved: Encrypted balances never leak plaintext amounts
\* - SelectiveDisclosure: Only authorized auditors can decrypt
\* - NoDoubleSpend: Cannot transfer more than encrypted balance
\* - BalanceIntegrity: Sum of all balances equals total pool funds
EXTENDS Integers, Sequences, TLC, FiniteSets
CONSTANTS
Users, \* Set of user addresses
Auditors, \* Set of auditor IDs
MaxAmount \* Maximum deposit/transfer amount
VARIABLES
encryptedBalances, \* User -> EncryptedBalance record
transfers, \* Set of ConfidentialTransfer records
totalPoolFunds, \* Total DYN in ShieldedPool
pohSequence \* PoH timestamp counter
vars == <<encryptedBalances, transfers, totalPoolFunds, pohSequence>>
\* Type definitions
EncryptedBalance == [
user: Users,
balance: Int, \* Actual balance (would be encrypted in real impl)
authorizedAuditors: SUBSET Auditors
]
ConfidentialTransfer == [
transferId: STRING,
sender: Users,
recipient: Users,
amount: Int,
pohTimestamp: Nat
]
----
\* Initial state
Init ==
/\ encryptedBalances = [u \in Users |-> [
user |-> u,
balance |-> 0,
authorizedAuditors |-> {}
]]
/\ transfers = {}
/\ totalPoolFunds = 0
/\ pohSequence = 0
----
\* Shield: Deposit DYN into confidential pool
Shield(user, amount) ==
/\ amount > 0
/\ amount <= MaxAmount
/\ encryptedBalances' = [encryptedBalances EXCEPT
![user].balance = @ + amount
]
/\ totalPoolFunds' = totalPoolFunds + amount
/\ pohSequence' = pohSequence + 1
/\ UNCHANGED transfers
\* Unshield: Withdraw DYN from confidential pool
Unshield(user, amount) ==
/\ amount > 0
/\ amount <= encryptedBalances[user].balance \* Sufficient balance check
/\ encryptedBalances' = [encryptedBalances EXCEPT
![user].balance = @ - amount
]
/\ totalPoolFunds' = totalPoolFunds - amount
/\ pohSequence' = pohSequence + 1
/\ UNCHANGED transfers
\* ConfidentialTransfer: Private transfer within the pool
ConfidentialTransferOp(sender, recipient, amount) ==
/\ sender # recipient
/\ amount > 0
/\ amount <= encryptedBalances[sender].balance \* Sender has funds
/\ LET transferId == "tx_" \o ToString(pohSequence)
newTransfer == [
transferId |-> transferId,
sender |-> sender,
recipient |-> recipient,
amount |-> amount,
pohTimestamp |-> pohSequence
]
IN
/\ encryptedBalances' = [encryptedBalances EXCEPT
![sender].balance = @ - amount,
![recipient].balance = @ + amount
]
/\ transfers' = transfers \cup {newTransfer}
/\ pohSequence' = pohSequence + 1
/\ UNCHANGED totalPoolFunds \* Pool total unchanged (internal transfer)
\* GrantAuditor: Authorize auditor to view encrypted balance
GrantAuditor(user, auditorId) ==
/\ auditorId \in Auditors
/\ auditorId \notin encryptedBalances[user].authorizedAuditors
/\ encryptedBalances' = [encryptedBalances EXCEPT
![user].authorizedAuditors = @ \cup {auditorId}
]
/\ pohSequence' = pohSequence + 1
/\ UNCHANGED <<transfers, totalPoolFunds>>
\* RevokeAuditor: Remove auditor access
RevokeAuditor(user, auditorId) ==
/\ auditorId \in encryptedBalances[user].authorizedAuditors
/\ encryptedBalances' = [encryptedBalances EXCEPT
![user].authorizedAuditors = @ \ {auditorId}
]
/\ pohSequence' = pohSequence + 1
/\ UNCHANGED <<transfers, totalPoolFunds>>
----
\* Next state: All possible actions
Next ==
\/ \E u \in Users, amt \in 1..MaxAmount: Shield(u, amt)
\/ \E u \in Users, amt \in 1..MaxAmount: Unshield(u, amt)
\/ \E s,r \in Users, amt \in 1..MaxAmount: ConfidentialTransferOp(s, r, amt)
\/ \E u \in Users, a \in Auditors: GrantAuditor(u, a)
\/ \E u \in Users, a \in Auditors: RevokeAuditor(u, a)
Spec == Init /\ [][Next]_vars /\ WF_vars(Next)
----
\* SAFETY PROPERTIES (Invariants)
TypeInvariant ==
/\ totalPoolFunds \in Nat
/\ pohSequence \in Nat
/\ \A u \in Users: encryptedBalances[u].balance >= 0
/\ \A u \in Users: encryptedBalances[u].authorizedAuditors \subseteq Auditors
\* Property 1: Privacy Preserved
\* Encrypted balances are never negative (fundamental privacy constraint)
PrivacyPreserved ==
\A u \in Users: encryptedBalances[u].balance >= 0
\* Property 2: Selective Disclosure
\* Only explicitly authorized auditors have access rights
\* (This is a structural property - actual decryption would require view keys)
SelectiveDisclosure ==
\A u \in Users:
encryptedBalances[u].authorizedAuditors \subseteq Auditors
\* Property 3: No Double Spend
\* Cannot transfer more than current balance
NoDoubleSpend ==
\A t \in transfers:
t.amount <= encryptedBalances[t.sender].balance + t.amount \* Account for transferred amount
\* Helper: Sum function
Sum(f) ==
LET SumRec[S \in SUBSET DOMAIN f] ==
IF S = {} THEN 0
ELSE LET x == CHOOSE x \in S: TRUE
IN f[x] + SumRec[S \ {x}]
IN SumRec[DOMAIN f]
\* Property 4: Balance Integrity
\* Sum of all encrypted balances equals total pool funds
BalanceIntegrity ==
LET sumBalances == Sum([u \in Users |-> encryptedBalances[u].balance])
IN sumBalances = totalPoolFunds
\* Property 5: PoH Monotonicity
\* PoH sequence strictly increases
PoHMonotonic ==
\A t1, t2 \in transfers:
(t1.pohTimestamp < t2.pohTimestamp) => (t1 # t2)
====