hypercall_state_commitment/
keys.rs1use jmt::KeyHash;
2use sha3::{Digest, Keccak256};
3
4pub struct StateKey;
12
13impl StateKey {
14 pub fn account(address: &[u8; 20]) -> KeyHash {
16 let mut h = Keccak256::new();
17 h.update(address);
18 h.update(b"account");
19 KeyHash(h.finalize().into())
20 }
21
22 pub fn option_position(address: &[u8; 20], symbol: &str) -> KeyHash {
24 let mut h = Keccak256::new();
25 h.update(address);
26 h.update(b"pos");
27 h.update(symbol.as_bytes());
28 KeyHash(h.finalize().into())
29 }
30
31 pub fn perp_position(address: &[u8; 20], coin: &str) -> KeyHash {
33 let mut h = Keccak256::new();
34 h.update(address);
35 h.update(b"perp");
36 h.update(coin.as_bytes());
37 KeyHash(h.finalize().into())
38 }
39
40 pub fn order(address: &[u8; 20], order_id: u64) -> KeyHash {
42 let mut h = Keccak256::new();
43 h.update(address);
44 h.update(b"order");
45 h.update(order_id.to_be_bytes());
46 KeyHash(h.finalize().into())
47 }
48
49 pub fn mmp_config(address: &[u8; 20], currency: &str) -> KeyHash {
51 let mut h = Keccak256::new();
52 h.update(address);
53 h.update(b"mmp");
54 h.update(currency.as_bytes());
55 KeyHash(h.finalize().into())
56 }
57
58 pub fn instrument(symbol: &str) -> KeyHash {
60 let mut h = Keccak256::new();
61 h.update(b"instrument");
62 h.update(symbol.as_bytes());
63 KeyHash(h.finalize().into())
64 }
65
66 pub fn oracle(underlying: &str) -> KeyHash {
68 let mut h = Keccak256::new();
69 h.update(b"oracle");
70 h.update(underlying.as_bytes());
71 KeyHash(h.finalize().into())
72 }
73
74 pub fn global() -> KeyHash {
76 let mut h = Keccak256::new();
77 h.update(b"global");
78 KeyHash(h.finalize().into())
79 }
80
81 pub fn risk(address: &[u8; 20]) -> KeyHash {
83 let mut h = Keccak256::new();
84 h.update(address);
85 KeyHash(h.finalize().into())
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn different_namespaces_produce_different_keys() {
95 let addr = [0xABu8; 20];
96 let account = StateKey::account(&addr);
97 let pos = StateKey::option_position(&addr, "BTC-20261231-100000-C");
98 let perp = StateKey::perp_position(&addr, "BTC");
99 let mmp = StateKey::mmp_config(&addr, "BTC");
100
101 assert_ne!(account, pos);
102 assert_ne!(account, perp);
103 assert_ne!(account, mmp);
104 assert_ne!(pos, perp);
105 assert_ne!(pos, mmp);
106 assert_ne!(perp, mmp);
107 }
108
109 #[test]
110 fn same_inputs_produce_same_key() {
111 let addr = [0x42u8; 20];
112 let a = StateKey::option_position(&addr, "ETH-20261231-5000-P");
113 let b = StateKey::option_position(&addr, "ETH-20261231-5000-P");
114 assert_eq!(a, b);
115 }
116
117 #[test]
118 fn different_addresses_produce_different_keys() {
119 let addr_a = [0x01u8; 20];
120 let addr_b = [0x02u8; 20];
121 assert_ne!(StateKey::account(&addr_a), StateKey::account(&addr_b));
122 }
123
124 #[test]
125 fn global_key_is_deterministic() {
126 assert_eq!(StateKey::global(), StateKey::global());
127 }
128
129 #[test]
130 fn namespace_prefix_prevents_cross_type_collision() {
131 let addr = [0x00; 20];
132 let pos_btc = StateKey::option_position(&addr, "BTC");
134 let perp_tc = StateKey::perp_position(&addr, "TC");
135 assert_ne!(pos_btc, perp_tc);
136 }
137
138 #[test]
139 fn empty_symbol_produces_valid_key() {
140 let addr = [0x01; 20];
141 let key = StateKey::option_position(&addr, "");
142 assert_ne!(key.0, [0u8; 32]);
143 }
144
145 #[test]
146 fn long_symbol_produces_valid_key() {
147 let addr = [0x01; 20];
148 let long_symbol = "A".repeat(1000);
149 let key = StateKey::option_position(&addr, &long_symbol);
150 assert_ne!(key.0, [0u8; 32]);
151 }
152
153 #[test]
154 fn fast_risk_key_differs_from_account_key() {
155 let addr = [0x42; 20];
156 assert_ne!(StateKey::account(&addr), StateKey::risk(&addr));
157 }
158
159 #[test]
160 fn all_zero_address_works() {
161 let addr = [0x00; 20];
162 let key = StateKey::account(&addr);
163 assert_ne!(key.0, [0u8; 32]);
164 }
165}
166
167#[cfg(kani)]
168mod kani_proofs {
169 use super::*;
170
171 #[kani::proof]
173 fn bounded_account_key_deterministic() {
174 let addr: [u8; 20] = kani::any();
175 let a = StateKey::account(&addr);
176 let b = StateKey::account(&addr);
177 assert_eq!(a.0, b.0);
178 }
179
180 #[kani::proof]
183 #[kani::unwind(1)]
184 fn bounded_account_key_no_panic() {
185 let addr: [u8; 20] = kani::any();
186 let _ = StateKey::account(&addr);
187 }
188
189 #[kani::proof]
191 fn bounded_order_key_deterministic() {
192 let addr: [u8; 20] = kani::any();
193 let order_id: u64 = kani::any();
194 let a = StateKey::order(&addr, order_id);
195 let b = StateKey::order(&addr, order_id);
196 assert_eq!(a.0, b.0);
197 }
198
199 #[kani::proof]
202 fn bounded_risk_key_differs_from_account_key() {
203 let addr: [u8; 20] = kani::any();
204 let account = StateKey::account(&addr);
205 let risk = StateKey::risk(&addr);
206 assert_ne!(account.0, risk.0);
209 }
210
211 #[kani::proof]
213 fn bounded_global_key_no_panic() {
214 let key = StateKey::global();
215 let _ = key.0;
217 }
218}