@@ -2,10 +2,14 @@ use fhevm_engine_common::chain_id::ChainId;
22use fhevm_engine_common:: crs:: CrsCache ;
33use fhevm_engine_common:: db_keys:: DbKeyCache ;
44use fhevm_engine_common:: pg_pool:: PostgresPoolManager ;
5- use fhevm_engine_common:: utils:: safe_serialize;
5+ use fhevm_engine_common:: tfhe_ops:: { current_ciphertext_version, extract_ct_list} ;
6+ use fhevm_engine_common:: types:: SupportedFheCiphertexts ;
7+ use fhevm_engine_common:: utils:: { safe_deserialize_conformant, safe_serialize} ;
8+ use sqlx:: Row ;
69use std:: sync:: Arc ;
710use std:: time:: { Duration , SystemTime } ;
811use test_harness:: instance:: { DBInstance , ImportMode } ;
12+ use tfhe:: integer:: ciphertext:: IntegerProvenCompactCiphertextListConformanceParams ;
913use tokio:: sync:: RwLock ;
1014use tokio:: time:: sleep;
1115
@@ -84,6 +88,147 @@ pub(crate) async fn is_valid(
8488 Ok ( false )
8589}
8690
91+ #[ derive( Debug ) ]
92+ pub ( crate ) struct StoredCiphertext {
93+ pub ( crate ) handle : Vec < u8 > ,
94+ pub ( crate ) ciphertext : Vec < u8 > ,
95+ pub ( crate ) ciphertext_type : i16 ,
96+ pub ( crate ) input_blob_index : i32 ,
97+ }
98+
99+ #[ derive( Debug , PartialEq , Eq ) ]
100+ pub ( crate ) struct DecryptionResult {
101+ pub ( crate ) output_type : i16 ,
102+ pub ( crate ) value : String ,
103+ }
104+
105+ pub ( crate ) async fn wait_for_handles (
106+ pool : & sqlx:: PgPool ,
107+ zk_proof_id : i64 ,
108+ max_retries : usize ,
109+ ) -> Result < Vec < Vec < u8 > > , sqlx:: Error > {
110+ for _ in 0 ..max_retries {
111+ sleep ( Duration :: from_millis ( 100 ) ) . await ;
112+ let row = sqlx:: query ( "SELECT verified, handles FROM verify_proofs WHERE zk_proof_id = $1" )
113+ . bind ( zk_proof_id)
114+ . fetch_one ( pool)
115+ . await ?;
116+
117+ let verified: Option < bool > = row. try_get ( "verified" ) ?;
118+ if !matches ! ( verified, Some ( true ) ) {
119+ continue ;
120+ }
121+
122+ let handles: Option < Vec < u8 > > = row. try_get ( "handles" ) ?;
123+ let handles = handles. unwrap_or_default ( ) ;
124+ assert_eq ! ( handles. len( ) % 32 , 0 ) ;
125+
126+ return Ok ( handles. chunks ( 32 ) . map ( |chunk| chunk. to_vec ( ) ) . collect ( ) ) ;
127+ }
128+
129+ Ok ( vec ! [ ] )
130+ }
131+
132+ pub ( crate ) async fn fetch_stored_ciphertexts (
133+ pool : & sqlx:: PgPool ,
134+ handles : & [ Vec < u8 > ] ,
135+ ) -> Result < Vec < StoredCiphertext > , sqlx:: Error > {
136+ if handles. is_empty ( ) {
137+ return Ok ( vec ! [ ] ) ;
138+ }
139+
140+ let rows = sqlx:: query (
141+ "
142+ SELECT handle, ciphertext, ciphertext_type, input_blob_index
143+ FROM ciphertexts
144+ WHERE handle = ANY($1::BYTEA[])
145+ AND ciphertext_version = $2
146+ ORDER BY input_blob_index ASC
147+ " ,
148+ )
149+ . bind ( handles)
150+ . bind ( current_ciphertext_version ( ) )
151+ . fetch_all ( pool)
152+ . await ?;
153+
154+ rows. into_iter ( )
155+ . map ( |row| {
156+ Ok ( StoredCiphertext {
157+ handle : row. try_get ( "handle" ) ?,
158+ ciphertext : row. try_get ( "ciphertext" ) ?,
159+ ciphertext_type : row. try_get ( "ciphertext_type" ) ?,
160+ input_blob_index : row. try_get ( "input_blob_index" ) ?,
161+ } )
162+ } )
163+ . collect ( )
164+ }
165+
166+ pub ( crate ) async fn decrypt_ciphertexts (
167+ pool : & sqlx:: PgPool ,
168+ handles : & [ Vec < u8 > ] ,
169+ ) -> anyhow:: Result < Vec < DecryptionResult > > {
170+ let stored = fetch_stored_ciphertexts ( pool, handles) . await ?;
171+ let db_key_cache = DbKeyCache :: new ( MAX_CACHED_KEYS ) . expect ( "create db key cache" ) ;
172+ let key = db_key_cache. fetch_latest ( pool) . await ?;
173+
174+ tokio:: task:: spawn_blocking ( move || {
175+ let client_key = key. cks . expect ( "client key available in tests" ) ;
176+ tfhe:: set_server_key ( key. sks ) ;
177+
178+ stored
179+ . into_iter ( )
180+ . map ( |ct| {
181+ let deserialized = SupportedFheCiphertexts :: decompress_no_memcheck (
182+ ct. ciphertext_type ,
183+ & ct. ciphertext ,
184+ )
185+ . expect ( "valid compressed ciphertext" ) ;
186+ DecryptionResult {
187+ output_type : ct. ciphertext_type ,
188+ value : deserialized. decrypt ( & client_key) ,
189+ }
190+ } )
191+ . collect :: < Vec < _ > > ( )
192+ } )
193+ . await
194+ . map_err ( anyhow:: Error :: from)
195+ }
196+
197+ pub ( crate ) async fn compress_inputs_without_rerandomization (
198+ pool : & sqlx:: PgPool ,
199+ raw_ct : & [ u8 ] ,
200+ ) -> anyhow:: Result < Vec < Vec < u8 > > > {
201+ let db_key_cache = DbKeyCache :: new ( MAX_CACHED_KEYS ) . expect ( "create db key cache" ) ;
202+ let latest_key = db_key_cache. fetch_latest ( pool) . await ?;
203+ let latest_crs = CrsCache :: load ( pool)
204+ . await ?
205+ . get_latest ( )
206+ . cloned ( )
207+ . expect ( "latest CRS" ) ;
208+
209+ let verified_list: tfhe:: ProvenCompactCiphertextList = safe_deserialize_conformant (
210+ raw_ct,
211+ & IntegerProvenCompactCiphertextListConformanceParams :: from_public_key_encryption_parameters_and_crs_parameters (
212+ latest_key. pks . parameters ( ) ,
213+ & latest_crs. crs ,
214+ ) ,
215+ ) ?;
216+
217+ if verified_list. is_empty ( ) {
218+ return Ok ( vec ! [ ] ) ;
219+ }
220+
221+ tokio:: task:: spawn_blocking ( move || {
222+ tfhe:: set_server_key ( latest_key. sks ) ;
223+ let expanded = verified_list. expand_without_verification ( ) ?;
224+ let cts = extract_ct_list ( & expanded) ?;
225+ cts. into_iter ( )
226+ . map ( |ct| ct. compress ( ) . map_err ( anyhow:: Error :: from) )
227+ . collect ( )
228+ } )
229+ . await ?
230+ }
231+
87232#[ derive( Debug , Clone ) ]
88233pub ( crate ) enum ZkInput {
89234 Bool ( bool ) ,
@@ -93,6 +238,18 @@ pub(crate) enum ZkInput {
93238 U64 ( u64 ) ,
94239}
95240
241+ impl ZkInput {
242+ pub ( crate ) fn cleartext ( & self ) -> String {
243+ match self {
244+ Self :: Bool ( value) => value. to_string ( ) ,
245+ Self :: U8 ( value) => value. to_string ( ) ,
246+ Self :: U16 ( value) => value. to_string ( ) ,
247+ Self :: U32 ( value) => value. to_string ( ) ,
248+ Self :: U64 ( value) => value. to_string ( ) ,
249+ }
250+ }
251+ }
252+
96253pub ( crate ) async fn generate_zk_pok_with_inputs (
97254 pool : & sqlx:: PgPool ,
98255 aux_data : & [ u8 ] ,
0 commit comments