@@ -1043,57 +1043,78 @@ def test_gil(self):
10431043
10441044 def test_sha256_gil (self ):
10451045 gil_minsize = hashlib_helper .find_gil_minsize (['_sha2' , '_hashlib' ])
1046+ data = b'1' + b'#' * gil_minsize + b'1'
1047+ expected = hashlib .sha256 (data ).hexdigest ()
1048+
10461049 m = hashlib .sha256 ()
10471050 m .update (b'1' )
10481051 m .update (b'#' * gil_minsize )
10491052 m .update (b'1' )
1050- self .assertEqual (
1051- m .hexdigest (),
1052- '1cfceca95989f51f658e3f3ffe7f1cd43726c9e088c13ee10b46f57cef135b94'
1053- )
1053+ self .assertEqual (m .hexdigest (), expected )
10541054
1055- m = hashlib .sha256 (b'1' + b'#' * gil_minsize + b'1' )
1056- self .assertEqual (
1057- m .hexdigest (),
1058- '1cfceca95989f51f658e3f3ffe7f1cd43726c9e088c13ee10b46f57cef135b94'
1059- )
1055+ @threading_helper .reap_threads
1056+ @threading_helper .requires_working_threading ()
1057+ def test_threaded_hashing_fast (self ):
1058+ # Same as test_threaded_hashing_slow() but only tests some functions
1059+ # since otherwise test_hashlib.py becomes too slow during development.
1060+ for name in ['md5' , 'sha1' , 'sha256' , 'sha3_256' , 'blake2s' ]:
1061+ if constructor := getattr (hashlib , name , None ):
1062+ with self .subTest (name ):
1063+ self .do_test_threaded_hashing (constructor , is_shake = False )
1064+ if shake_128 := getattr (hashlib , 'shake_128' , None ):
1065+ self .do_test_threaded_hashing (shake_128 , is_shake = True )
10601066
1067+ @requires_resource ('cpu' )
10611068 @threading_helper .reap_threads
10621069 @threading_helper .requires_working_threading ()
1063- def test_threaded_hashing (self ):
1070+ def test_threaded_hashing_slow (self ):
1071+ for algorithm , constructors in self .constructors_to_test .items ():
1072+ is_shake = algorithm in self .shakes
1073+ for constructor in constructors :
1074+ with self .subTest (constructor .__name__ , is_shake = is_shake ):
1075+ self .do_test_threaded_hashing (constructor , is_shake )
1076+
1077+ def do_test_threaded_hashing (self , constructor , is_shake ):
10641078 # Updating the same hash object from several threads at once
10651079 # using data chunk sizes containing the same byte sequences.
10661080 #
10671081 # If the internal locks are working to prevent multiple
10681082 # updates on the same object from running at once, the resulting
10691083 # hash will be the same as doing it single threaded upfront.
1070- hasher = hashlib .sha1 ()
1071- num_threads = 5
1072- smallest_data = b'swineflu'
1073- data = smallest_data * 200000
1074- expected_hash = hashlib .sha1 (data * num_threads ).hexdigest ()
1075-
1076- def hash_in_chunks (chunk_size ):
1077- index = 0
1078- while index < len (data ):
1079- hasher .update (data [index :index + chunk_size ])
1080- index += chunk_size
1084+
1085+ # The data to hash has length s|M|q^N and the chunk size for the i-th
1086+ # thread is s|M|q^(N-i), where N is the number of threads, M is a fixed
1087+ # message of small length, and s >= 1 and q >= 2 are small integers.
1088+ smallest_size , num_threads , s , q = 8 , 5 , 2 , 10
1089+
1090+ smallest_data = os .urandom (smallest_size )
1091+ data = s * smallest_data * (q ** num_threads )
1092+
1093+ h1 = constructor (usedforsecurity = False )
1094+ h2 = constructor (data * num_threads , usedforsecurity = False )
1095+
1096+ def update (chunk_size ):
1097+ for index in range (0 , len (data ), chunk_size ):
1098+ h1 .update (data [index :index + chunk_size ])
10811099
10821100 threads = []
1083- for threadnum in range (num_threads ):
1084- chunk_size = len (data ) // (10 ** threadnum )
1101+ for thread_num in range (num_threads ):
1102+ # chunk_size = len(data) // (q ** thread_num)
1103+ chunk_size = s * smallest_size * q ** (num_threads - thread_num )
10851104 self .assertGreater (chunk_size , 0 )
1086- self .assertEqual (chunk_size % len (smallest_data ), 0 )
1087- thread = threading .Thread (target = hash_in_chunks ,
1088- args = (chunk_size ,))
1105+ self .assertEqual (chunk_size % smallest_size , 0 )
1106+ thread = threading .Thread (target = update , args = (chunk_size ,))
10891107 threads .append (thread )
10901108
10911109 for thread in threads :
10921110 thread .start ()
10931111 for thread in threads :
10941112 thread .join ()
10951113
1096- self .assertEqual (expected_hash , hasher .hexdigest ())
1114+ if is_shake :
1115+ self .assertEqual (h1 .hexdigest (16 ), h2 .hexdigest (16 ))
1116+ else :
1117+ self .assertEqual (h1 .hexdigest (), h2 .hexdigest ())
10971118
10981119 def test_get_fips_mode (self ):
10991120 fips_mode = self .is_fips_mode
0 commit comments