@@ -201,21 +201,42 @@ pub(crate) const UNSAFE_SRS_SEED: u64 = 42;
201201#[ cfg( any( test, feature = "benchmark-internals" ) ) ]
202202impl TrustedSetupProvider {
203203 /// Builds a `TrustedSetupProvider` backed by a freshly generated unsafe SRS of degree `k`, written
204- /// to `base_dir/srs/srs-parameters` with a matching SHA256 hash so the provider's hash check passes.
204+ /// to `base_dir/{k}/ srs/srs-parameters` with a matching SHA256 hash so the provider's hash check passes.
205205 /// For tests and benchmarks only.
206206 pub ( crate ) fn with_unsafe_srs ( base_dir : & std:: path:: Path , k : u32 ) -> Self {
207+ let base_dir = base_dir. join ( k. to_string ( ) ) ;
208+ let srs_file = base_dir
209+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
210+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
211+
212+ if srs_file. exists ( ) {
213+ return Self :: new ( base_dir, "" , "" , Duration :: from_secs ( 600 ) ) ;
214+ }
215+
207216 let srs = ParamsKZG :: < Bls12 > :: unsafe_setup ( k, ChaCha20Rng :: seed_from_u64 ( UNSAFE_SRS_SEED ) ) ;
208217 let mut srs_bytes = Vec :: new ( ) ;
209- srs. write_custom ( & mut srs_bytes, SerdeFormat :: RawBytes ) . unwrap ( ) ;
218+ srs. write_custom ( & mut srs_bytes, SerdeFormat :: RawBytesUnchecked )
219+ . unwrap ( ) ;
210220
211221 let srs_dir = base_dir. join ( MITHRIL_CIRCUIT_SRS_FOLDER ) ;
212222 create_dir_all ( & srs_dir) . unwrap ( ) ;
213- File :: create ( srs_dir. join ( MITHRIL_CIRCUIT_SRS_FILENAME ) )
214- . unwrap ( )
215- . write_all ( & srs_bytes)
223+
224+ let temp_path = srs_dir. join ( MITHRIL_CIRCUIT_SRS_FILENAME ) . with_extension ( "temp" ) ;
225+ let final_path = srs_dir. join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
226+ let mut temporary_file = File :: create ( & temp_path)
227+ . with_context ( || format ! ( "Failed to create temporary SRS file at {temp_path:?}." ) )
216228 . unwrap ( ) ;
229+ temporary_file. write_all ( & srs_bytes) . unwrap ( ) ;
230+ temporary_file
231+ . sync_all ( )
232+ . with_context ( || "Failed to fsync temporary SRS file before rename." )
233+ . unwrap ( ) ;
234+ drop ( temporary_file) ;
235+
236+ std:: fs:: rename ( temp_path, final_path) . unwrap ( ) ;
217237
218238 let expected_hash = hex:: encode ( Sha256 :: digest ( & srs_bytes) ) ;
239+
219240 Self :: new ( base_dir, expected_hash, "" , Duration :: from_secs ( 600 ) )
220241 }
221242}
@@ -466,6 +487,102 @@ mod tests {
466487 assert ! ( result. is_err( ) ) ;
467488 }
468489
490+ mod with_unsafe_srs {
491+ use super :: * ;
492+
493+ #[ test]
494+ fn creates_srs_file_nested_under_degree_subdirectory_and_loads_successfully ( ) {
495+ let temp_dir = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
496+ let k = 1 ;
497+
498+ let provider = TrustedSetupProvider :: with_unsafe_srs ( temp_dir. path ( ) , k) ;
499+
500+ let expected_srs_path = temp_dir
501+ . path ( )
502+ . join ( k. to_string ( ) )
503+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
504+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
505+ assert ! ( expected_srs_path. exists( ) ) ;
506+ assert ! ( provider. get_trusted_setup_parameters( ) . is_ok( ) ) ;
507+ }
508+
509+ #[ test]
510+ fn uses_separate_subdirectory_and_produces_distinct_files_per_degree ( ) {
511+ let temp_dir = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
512+
513+ TrustedSetupProvider :: with_unsafe_srs ( temp_dir. path ( ) , 1 ) ;
514+ TrustedSetupProvider :: with_unsafe_srs ( temp_dir. path ( ) , 2 ) ;
515+
516+ let srs_path_k1 = temp_dir
517+ . path ( )
518+ . join ( "1" )
519+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
520+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
521+ let srs_path_k2 = temp_dir
522+ . path ( )
523+ . join ( "2" )
524+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
525+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
526+
527+ assert ! ( srs_path_k1. exists( ) ) ;
528+ assert ! ( srs_path_k2. exists( ) ) ;
529+ assert_ne ! (
530+ std:: fs:: read( srs_path_k1) . unwrap( ) ,
531+ std:: fs:: read( srs_path_k2) . unwrap( )
532+ ) ;
533+ }
534+
535+ #[ test]
536+ fn is_deterministic_for_the_same_degree_across_different_base_dirs ( ) {
537+ let temp_dir_a = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
538+ let temp_dir_b = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
539+ let k = 1 ;
540+
541+ let provider_a = TrustedSetupProvider :: with_unsafe_srs ( temp_dir_a. path ( ) , k) ;
542+ let provider_b = TrustedSetupProvider :: with_unsafe_srs ( temp_dir_b. path ( ) , k) ;
543+
544+ let srs_subpath = std:: path:: Path :: new ( & k. to_string ( ) )
545+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
546+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
547+ let bytes_a = std:: fs:: read ( temp_dir_a. path ( ) . join ( & srs_subpath) ) . unwrap ( ) ;
548+ let bytes_b = std:: fs:: read ( temp_dir_b. path ( ) . join ( & srs_subpath) ) . unwrap ( ) ;
549+
550+ assert_eq ! ( bytes_a, bytes_b) ;
551+ assert ! ( provider_a. get_trusted_setup_parameters( ) . is_ok( ) ) ;
552+ assert ! ( provider_b. get_trusted_setup_parameters( ) . is_ok( ) ) ;
553+ }
554+
555+ #[ test]
556+ fn does_not_regenerate_or_overwrite_an_existing_srs_file ( ) {
557+ let temp_dir = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
558+ let k = 1 ;
559+ let srs_dir = temp_dir. path ( ) . join ( k. to_string ( ) ) . join ( MITHRIL_CIRCUIT_SRS_FOLDER ) ;
560+ std:: fs:: create_dir_all ( & srs_dir) . unwrap ( ) ;
561+ let srs_path = srs_dir. join ( MITHRIL_CIRCUIT_SRS_FILENAME ) ;
562+ std:: fs:: write ( & srs_path, b"sentinel-content-not-a-real-srs" ) . unwrap ( ) ;
563+
564+ TrustedSetupProvider :: with_unsafe_srs ( temp_dir. path ( ) , k) ;
565+
566+ let bytes_after = std:: fs:: read ( & srs_path) . unwrap ( ) ;
567+ assert_eq ! ( bytes_after, b"sentinel-content-not-a-real-srs" ) ;
568+ }
569+
570+ #[ test]
571+ fn leaves_no_temporary_file_behind_after_generation ( ) {
572+ let temp_dir = tempfile:: tempdir_in ( "/tmp" ) . unwrap ( ) ;
573+ let k = 1 ;
574+
575+ TrustedSetupProvider :: with_unsafe_srs ( temp_dir. path ( ) , k) ;
576+
577+ let temp_path = temp_dir
578+ . path ( )
579+ . join ( k. to_string ( ) )
580+ . join ( MITHRIL_CIRCUIT_SRS_FOLDER )
581+ . join ( MITHRIL_CIRCUIT_SRS_FILENAME )
582+ . with_extension ( "temp" ) ;
583+ assert ! ( !temp_path. exists( ) ) ;
584+ }
585+ }
469586 mod golden {
470587 use super :: * ;
471588
0 commit comments