11use std:: {
22 fs:: File ,
3- io:: { BufReader , BufWriter , Read , Write } ,
3+ io:: { BufReader , BufWriter , Write } ,
44 path:: PathBuf ,
5+ time:: Duration ,
56} ;
67
78use anyhow:: { Context , anyhow} ;
89use midnight_curves:: Bls12 ;
910use midnight_proofs:: { poly:: kzg:: params:: ParamsKZG , utils:: SerdeFormat } ;
1011use sha2:: { Digest , Sha256 } ;
11- use tempfile:: NamedTempFile ;
1212
13- use crate :: StmResult ;
13+ use crate :: { StmResult , circuits :: MITHRIL_CIRCUIT_CACHE_FOLDER } ;
1414
1515/// TODO: remove allow(dead_code) when the constants are used or remove the constatnts
1616#[ allow( dead_code) ]
@@ -22,35 +22,36 @@ use crate::StmResult;
2222/// the proper value available here: https://github.com/midnightntwrk/midnight-trusted-setup/blob/main/MIDNIGHT_SRS_CATALOG.md
2323const SRS_HASH_K22 : & str = "e8ad5eed936d657a0fb59d2a55ba19f81a3083bb3554ef88f464f5377e9b2c2f" ;
2424#[ allow( dead_code) ]
25- /// Constant storing local path of the SRS of degree 22 used to create proof in production
26- const SRS_PATH_K22 : & str = ".local/local_trusted_setup/" ;
27- #[ allow( dead_code) ]
2825/// Constant storing URL to download the SRS of degree 22 used to create proof in production
2926const SRS_URL_K22 : & str = "https://srs.midnight.network/midnight-srs-2p22" ;
3027
31- /// An handle to manage the trusted setup srs . It stores the local path of the srs file
28+ /// A structure to manage the trusted setup SRS . It stores the local path of the SRS file
3229/// and information to download the file and verify integrity if it is missing.
33- pub struct TrustedSetupHandle {
34- /// Path of the local srs file
30+ pub struct TrustedSetupProvider {
31+ /// Path of the local SRS file
3532 local_srs_path : PathBuf ,
36- /// Expected hash of the downloaded srs file
33+ /// Expected hash of the downloaded SRS file
3734 srs_expected_hash : String ,
38- /// URL where to download the srs file if it is not present locally
35+ /// URL where to download the SRS file if it is not present locally
3936 url_to_download_srs : String ,
37+ /// The timeout limit when trying to download the SRS file
38+ download_timeout_limit : Duration ,
4039}
4140
4241/// TODO: remove allow(dead_code) when used
4342#[ allow( dead_code) ]
44- impl TrustedSetupHandle {
45- fn new < P , S > ( local_srs_path : P , srs_expected_hash : S , url_to_download_srs : S ) -> Self
46- where
47- P : Into < PathBuf > ,
48- S : Into < String > ,
49- {
43+ impl TrustedSetupProvider {
44+ fn new < P : Into < PathBuf > , S : Into < String > > (
45+ local_srs_path : P ,
46+ srs_expected_hash : S ,
47+ url_to_download_srs : S ,
48+ download_timeout_limit : Duration ,
49+ ) -> Self {
5050 Self {
5151 local_srs_path : local_srs_path. into ( ) ,
5252 srs_expected_hash : srs_expected_hash. into ( ) ,
5353 url_to_download_srs : url_to_download_srs. into ( ) ,
54+ download_timeout_limit,
5455 }
5556 }
5657
@@ -62,18 +63,6 @@ impl TrustedSetupHandle {
6263 hex:: encode ( hasher. finalize ( ) )
6364 }
6465
65- /// Reads the local SRS file at the stored path and checks its SHA256 hash against the expected value.
66- // This function can be removed if it is not used.
67- fn verify_file_sha256_hash ( & self ) -> StmResult < bool > {
68- let mut file = File :: open ( & self . local_srs_path )
69- . with_context ( || "Loading of the SRS file should have succeeded!" ) ?;
70- let mut srs_buffer = vec ! [ ] ;
71- file. read_to_end ( & mut srs_buffer)
72- . with_context ( || "Reading the SRS file should have succeeded!" ) ?;
73-
74- Ok ( self . verify_bytes_sha256_hash ( & srs_buffer) )
75- }
76-
7766 /// Checks SHA256 hash of the given bytes against the stored expected value.
7867 fn verify_bytes_sha256_hash ( & self , srs_bytes : & [ u8 ] ) -> bool {
7968 let recomputed_hash = Self :: compute_hash ( srs_bytes) ;
@@ -85,7 +74,7 @@ impl TrustedSetupHandle {
8574 fn download_srs_file ( & self ) -> StmResult < Vec < u8 > > {
8675 let response = reqwest:: blocking:: Client :: builder ( )
8776 // TODO: For now a timeout but this should be updated depending on the behavior we want
88- . timeout ( std :: time :: Duration :: from_secs ( 600 ) )
77+ . timeout ( self . download_timeout_limit )
8978 . build ( ) ?
9079 . get ( & self . url_to_download_srs )
9180 . header ( "User-Agent" , "mithril-stm" )
@@ -96,8 +85,9 @@ impl TrustedSetupHandle {
9685 Ok ( bytes. to_vec ( ) )
9786 }
9887
99- /// Saves the given bytes in a file at the stored path while creating
100- /// the directories of the path if needed.
88+ /// Saves the given bytes in a temporary file then atomically moves it to the stored path
89+ /// while creating the directories of the path if needed.
90+ /// If the writing is interu
10191 fn store_srs_bytes_to_file ( & self , srs_bytes : & [ u8 ] ) -> StmResult < ( ) > {
10292 let parent = self
10393 . local_srs_path
@@ -106,12 +96,14 @@ impl TrustedSetupHandle {
10696 std:: fs:: create_dir_all ( parent)
10797 . with_context ( || "Subdirectory creation should have succeeded!" ) ?;
10898
109- let mut temporary_file = NamedTempFile :: new_in ( parent)
110- . with_context ( || "Failed to generate temporary file to store the SRS" ) ?;
99+ let temp_path = self . local_srs_path . with_extension ( ".temp" ) ;
100+ // Create/clean the file
101+ let mut temporary_file = File :: create ( & temp_path) ?;
111102 BufWriter :: new ( & mut temporary_file) . write_all ( srs_bytes) ?;
112- temporary_file
113- . persist ( & self . local_srs_path )
114- . with_context ( || "Failed to atomically rename SRS temp file." ) ?;
103+
104+ // atomic renaming
105+ std:: fs:: rename ( temp_path, & self . local_srs_path ) ?;
106+
115107 Ok ( ( ) )
116108 }
117109
@@ -143,19 +135,18 @@ impl TrustedSetupHandle {
143135 . with_context ( || format ! ( "Failed to open SRS file at {:?}" , self . local_srs_path) ) ?;
144136 let mut reader = BufReader :: new ( file) ;
145137
146- ParamsKZG :: read_custom ( & mut reader, SerdeFormat :: RawBytes )
138+ ParamsKZG :: read_custom ( & mut reader, SerdeFormat :: RawBytesUnchecked )
147139 . with_context ( || "Failed to deserialize SRS from file" )
148140 }
149141}
150142
151- impl Default for TrustedSetupHandle {
143+ impl Default for TrustedSetupProvider {
152144 fn default ( ) -> Self {
153145 Self :: new (
154- PathBuf :: from ( std:: env:: var ( "HOME" ) . unwrap_or_else ( |_| "." . to_string ( ) ) )
155- . join ( SRS_PATH_K22 )
156- . join ( "midnight-srs-2p22" ) ,
146+ std:: env:: temp_dir ( ) . join ( MITHRIL_CIRCUIT_CACHE_FOLDER ) . join ( "srs" ) ,
157147 SRS_HASH_K22 ,
158148 SRS_URL_K22 ,
149+ Duration :: from_secs ( 600 ) ,
159150 )
160151 }
161152}
@@ -215,7 +206,8 @@ mod tests {
215206 fn both_bytes_encoding_work_to_load_srs_from_file ( ) {
216207 let mut tmp_file = NamedTempFile :: new ( ) . unwrap ( ) ;
217208 std:: fs:: write ( & mut tmp_file, SRS_K1 . as_slice ( ) ) . unwrap ( ) ;
218- let srs_manager = TrustedSetupHandle :: new ( tmp_file. path ( ) , "" , "" ) ;
209+ let srs_manager =
210+ TrustedSetupProvider :: new ( tmp_file. path ( ) , "" , "" , Duration :: from_secs ( 600 ) ) ;
219211 let loaded_srs = srs_manager. check_available_file_then_load_srs ( ) . unwrap ( ) ;
220212 let srs_rawbytes: ParamsKZG < Bls12 > =
221213 ParamsKZG :: read_custom ( & mut SRS_K1 . as_slice ( ) , SerdeFormat :: RawBytes ) . unwrap ( ) ;
@@ -243,57 +235,44 @@ mod tests {
243235 assert_eq ! ( raw_bytes_unchecked_buffer, raw_bytes_buffer) ;
244236 }
245237
246- #[ test]
247- fn hash_of_correct_srs_file_verifies ( ) {
248- let srs_file = NamedTempFile :: new_in ( "/tmp" ) . unwrap ( ) ;
249- std:: fs:: write ( & srs_file, SRS_K1 ) . unwrap ( ) ;
250-
251- let result = TrustedSetupHandle :: new ( srs_file. path ( ) , SRS_HASH_K1 , "" )
252- . verify_file_sha256_hash ( )
253- . unwrap ( ) ;
254-
255- assert ! ( result) ;
256- }
257-
258238 #[ test]
259239 fn verification_of_hash_of_invalid_srs_file_fails ( ) {
260240 let mut tampered_bytes = SRS_K1 . to_vec ( ) ;
261241 tampered_bytes[ 0 ] = tampered_bytes[ 0 ] . wrapping_add ( 1 ) ;
262242
263- let result =
264- TrustedSetupHandle :: new ( "" , SRS_HASH_K1 , "" ) . verify_bytes_sha256_hash ( & tampered_bytes) ;
243+ let result = TrustedSetupProvider :: new ( "" , SRS_HASH_K1 , "" , Duration :: from_secs ( 600 ) )
244+ . verify_bytes_sha256_hash ( & tampered_bytes) ;
265245
266246 assert ! ( !result) ;
267247 }
268248
269249 #[ test]
270250 fn hash_of_correct_bytes_verifies ( ) {
271- let result = TrustedSetupHandle :: new ( "" , SRS_HASH_K1 , "" ) . verify_bytes_sha256_hash ( SRS_K1 ) ;
251+ let result = TrustedSetupProvider :: new ( "" , SRS_HASH_K1 , "" , Duration :: from_secs ( 600 ) )
252+ . verify_bytes_sha256_hash ( SRS_K1 ) ;
272253
273254 assert ! ( result) ;
274255 }
275256
276257 #[ test]
277- fn verification_of_hash_of_invalid_bytes_fails ( ) {
258+ fn existing_file_on_disk_skips_download_and_verification ( ) {
278259 let srs_file = NamedTempFile :: new_in ( "/tmp" ) . unwrap ( ) ;
279- let mut tampered = SRS_K1 . to_vec ( ) ;
280- tampered[ 0 ] = tampered[ 0 ] . wrapping_add ( 1 ) ;
281- std:: fs:: write ( & srs_file, & tampered) . unwrap ( ) ;
260+ std:: fs:: write ( & srs_file, [ 0 , 1 , 2 , 3 , 4 ] ) . unwrap ( ) ;
282261
283- let result = TrustedSetupHandle :: new ( srs_file. path ( ) , SRS_HASH_K1 , "" )
284- . verify_file_sha256_hash ( )
285- . unwrap ( ) ;
262+ let result = TrustedSetupProvider :: new ( srs_file. path ( ) , "" , "" , Duration :: from_secs ( 600 ) )
263+ . ensure_srs_file_is_available ( ) ;
286264
287- assert ! ( ! result) ;
265+ assert ! ( result. is_ok ( ) ) ;
288266 }
289267
290268 #[ test]
291- fn existing_file_on_disk_skips_download_and_verification ( ) {
269+ fn interrupted_writing_of_srs_resumes_properly_at_next_try ( ) {
292270 let srs_file = NamedTempFile :: new_in ( "/tmp" ) . unwrap ( ) ;
293- std:: fs:: write ( & srs_file, [ 0 , 1 , 2 , 3 , 4 ] ) . unwrap ( ) ;
271+ let temp_srs_file = srs_file. path ( ) . with_extension ( "temp" ) ;
272+ std:: fs:: write ( & temp_srs_file, [ 0 , 1 , 2 , 3 , 4 ] ) . unwrap ( ) ;
294273
295- let result =
296- TrustedSetupHandle :: new ( srs_file . path ( ) , "" , "" ) . ensure_srs_file_is_available ( ) ;
274+ let result = TrustedSetupProvider :: new ( srs_file . path ( ) , "" , "" , Duration :: from_secs ( 600 ) )
275+ . ensure_srs_file_is_available ( ) ;
297276
298277 assert ! ( result. is_ok( ) ) ;
299278 }
@@ -302,7 +281,7 @@ mod tests {
302281 use super :: * ;
303282
304283 #[ test]
305- fn missing_srs_file_triggers_download_verifiation_and_storage ( ) {
284+ fn missing_srs_file_triggers_download_verification_and_storage ( ) {
306285 let server = MockServer :: start ( ) ;
307286 let mock = server. mock ( |when, then| {
308287 when. method ( httpmock:: Method :: GET ) . path ( "/srs" ) ;
@@ -312,9 +291,14 @@ mod tests {
312291 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
313292 let srs_path = temp_dir. path ( ) . join ( "missing_file_trigger_dl" ) ;
314293
315- TrustedSetupHandle :: new ( & srs_path, SRS_HASH_K1 , & server. url ( "/srs" ) )
316- . ensure_srs_file_is_available ( )
317- . unwrap ( ) ;
294+ TrustedSetupProvider :: new (
295+ & srs_path,
296+ SRS_HASH_K1 ,
297+ & server. url ( "/srs" ) ,
298+ Duration :: from_secs ( 600 ) ,
299+ )
300+ . ensure_srs_file_is_available ( )
301+ . unwrap ( ) ;
318302
319303 mock. assert ( ) ;
320304 assert ! ( srs_path. exists( ) ) ;
@@ -331,8 +315,13 @@ mod tests {
331315 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
332316 let srs_path = temp_dir. path ( ) . join ( "dl_wrong_hash" ) ;
333317
334- let result = TrustedSetupHandle :: new ( & srs_path, SRS_HASH_K1 , & server. url ( "/srs" ) )
335- . ensure_srs_file_is_available ( ) ;
318+ let result = TrustedSetupProvider :: new (
319+ & srs_path,
320+ SRS_HASH_K1 ,
321+ & server. url ( "/srs" ) ,
322+ Duration :: from_secs ( 600 ) ,
323+ )
324+ . ensure_srs_file_is_available ( ) ;
336325
337326 assert ! ( result. is_err( ) ) ;
338327 assert ! ( !srs_path. exists( ) ) ;
@@ -349,8 +338,13 @@ mod tests {
349338 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
350339 let srs_path = temp_dir. path ( ) . join ( "server_error_fails" ) ;
351340
352- let result = TrustedSetupHandle :: new ( & srs_path, SRS_HASH_K1 , & server. url ( "/srs" ) )
353- . ensure_srs_file_is_available ( ) ;
341+ let result = TrustedSetupProvider :: new (
342+ & srs_path,
343+ SRS_HASH_K1 ,
344+ & server. url ( "/srs" ) ,
345+ Duration :: from_secs ( 600 ) ,
346+ )
347+ . ensure_srs_file_is_available ( ) ;
354348
355349 assert ! ( result. is_err( ) ) ;
356350 }
0 commit comments