3434
3535requires_blake2 = unittest .skipUnless (_blake2 , 'requires _blake2' )
3636
37+ try :
38+ import _sha3
39+ except ImportError :
40+ _sha3 = None
41+
42+ requires_sha3 = unittest .skipUnless (_sha3 , 'requires _sha3' )
43+
3744
3845def hexstr (s ):
3946 assert isinstance (s , bytes ), repr (s )
@@ -61,7 +68,11 @@ class HashLibTestCase(unittest.TestCase):
6168 supported_hash_names = ( 'md5' , 'MD5' , 'sha1' , 'SHA1' ,
6269 'sha224' , 'SHA224' , 'sha256' , 'SHA256' ,
6370 'sha384' , 'SHA384' , 'sha512' , 'SHA512' ,
64- 'blake2b' , 'blake2s' )
71+ 'blake2b' , 'blake2s' ,
72+ 'sha3_224' , 'sha3_256' , 'sha3_384' , 'sha3_512' ,
73+ 'shake_128' , 'shake_256' )
74+
75+ shakes = {'shake_128' , 'shake_256' }
6576
6677 # Issue #14693: fallback modules are always compiled under POSIX
6778 _warn_on_extension_import = os .name == 'posix' or COMPILED_WITH_PYDEBUG
@@ -131,6 +142,15 @@ def add_builtin_constructor(name):
131142 add_builtin_constructor ('blake2s' )
132143 add_builtin_constructor ('blake2b' )
133144
145+ _sha3 = self ._conditional_import_module ('_sha3' )
146+ if _sha3 :
147+ add_builtin_constructor ('sha3_224' )
148+ add_builtin_constructor ('sha3_256' )
149+ add_builtin_constructor ('sha3_384' )
150+ add_builtin_constructor ('sha3_512' )
151+ add_builtin_constructor ('shake_128' )
152+ add_builtin_constructor ('shake_256' )
153+
134154 super (HashLibTestCase , self ).__init__ (* args , ** kwargs )
135155
136156 @property
@@ -142,7 +162,10 @@ def test_hash_array(self):
142162 a = array .array ("b" , range (10 ))
143163 for cons in self .hash_constructors :
144164 c = cons (a )
145- c .hexdigest ()
165+ if c .name in self .shakes :
166+ c .hexdigest (16 )
167+ else :
168+ c .hexdigest ()
146169
147170 def test_algorithms_guaranteed (self ):
148171 self .assertEqual (hashlib .algorithms_guaranteed ,
@@ -186,14 +209,21 @@ def test_get_builtin_constructor(self):
186209 def test_hexdigest (self ):
187210 for cons in self .hash_constructors :
188211 h = cons ()
189- self .assertIsInstance (h .digest (), bytes )
190- self .assertEqual (hexstr (h .digest ()), h .hexdigest ())
212+ if h .name in self .shakes :
213+ self .assertIsInstance (h .digest (16 ), bytes )
214+ self .assertEqual (hexstr (h .digest (16 )), h .hexdigest (16 ))
215+ else :
216+ self .assertIsInstance (h .digest (), bytes )
217+ self .assertEqual (hexstr (h .digest ()), h .hexdigest ())
191218
192219 def test_name_attribute (self ):
193220 for cons in self .hash_constructors :
194221 h = cons ()
195222 self .assertIsInstance (h .name , str )
196- self .assertIn (h .name , self .supported_hash_names )
223+ if h .name in self .supported_hash_names :
224+ self .assertIn (h .name , self .supported_hash_names )
225+ else :
226+ self .assertNotIn (h .name , self .supported_hash_names )
197227 self .assertEqual (h .name , hashlib .new (h .name ).name )
198228
199229 def test_large_update (self ):
@@ -208,40 +238,46 @@ def test_large_update(self):
208238 m1 .update (bees )
209239 m1 .update (cees )
210240 m1 .update (dees )
241+ if m1 .name in self .shakes :
242+ args = (16 ,)
243+ else :
244+ args = ()
211245
212246 m2 = cons ()
213247 m2 .update (aas + bees + cees + dees )
214- self .assertEqual (m1 .digest (), m2 .digest ())
248+ self .assertEqual (m1 .digest (* args ), m2 .digest (* args ))
215249
216250 m3 = cons (aas + bees + cees + dees )
217- self .assertEqual (m1 .digest (), m3 .digest ())
251+ self .assertEqual (m1 .digest (* args ), m3 .digest (* args ))
218252
219253 # verify copy() doesn't touch original
220254 m4 = cons (aas + bees + cees )
221- m4_digest = m4 .digest ()
255+ m4_digest = m4 .digest (* args )
222256 m4_copy = m4 .copy ()
223257 m4_copy .update (dees )
224- self .assertEqual (m1 .digest (), m4_copy .digest ())
225- self .assertEqual (m4 .digest (), m4_digest )
258+ self .assertEqual (m1 .digest (* args ), m4_copy .digest (* args ))
259+ self .assertEqual (m4 .digest (* args ), m4_digest )
226260
227- def check (self , name , data , hexdigest , ** kwargs ):
261+ def check (self , name , data , hexdigest , shake = False , ** kwargs ):
262+ length = len (hexdigest )// 2
228263 hexdigest = hexdigest .lower ()
229264 constructors = self .constructors_to_test [name ]
230265 # 2 is for hashlib.name(...) and hashlib.new(name, ...)
231266 self .assertGreaterEqual (len (constructors ), 2 )
232267 for hash_object_constructor in constructors :
233268 m = hash_object_constructor (data , ** kwargs )
234- computed = m .hexdigest ()
269+ computed = m .hexdigest () if not shake else m . hexdigest ( length )
235270 self .assertEqual (
236271 computed , hexdigest ,
237272 "Hash algorithm %s constructed using %s returned hexdigest"
238273 " %r for %d byte input data that should have hashed to %r."
239274 % (name , hash_object_constructor ,
240275 computed , len (data ), hexdigest ))
241- computed = m .digest ()
276+ computed = m .digest () if not shake else m . digest ( length )
242277 digest = bytes .fromhex (hexdigest )
243278 self .assertEqual (computed , digest )
244- self .assertEqual (len (digest ), m .digest_size )
279+ if not shake :
280+ self .assertEqual (len (digest ), m .digest_size )
245281
246282 def check_no_unicode (self , algorithm_name ):
247283 # Unicode objects are not allowed as input.
@@ -262,13 +298,30 @@ def test_no_unicode_blake2(self):
262298 self .check_no_unicode ('blake2b' )
263299 self .check_no_unicode ('blake2s' )
264300
265- def check_blocksize_name (self , name , block_size = 0 , digest_size = 0 ):
301+ @requires_sha3
302+ def test_no_unicode_sha3 (self ):
303+ self .check_no_unicode ('sha3_224' )
304+ self .check_no_unicode ('sha3_256' )
305+ self .check_no_unicode ('sha3_384' )
306+ self .check_no_unicode ('sha3_512' )
307+ self .check_no_unicode ('shake_128' )
308+ self .check_no_unicode ('shake_256' )
309+
310+ def check_blocksize_name (self , name , block_size = 0 , digest_size = 0 ,
311+ digest_length = None ):
266312 constructors = self .constructors_to_test [name ]
267313 for hash_object_constructor in constructors :
268314 m = hash_object_constructor ()
269315 self .assertEqual (m .block_size , block_size )
270316 self .assertEqual (m .digest_size , digest_size )
271- self .assertEqual (len (m .digest ()), digest_size )
317+ if digest_length :
318+ self .assertEqual (len (m .digest (digest_length )),
319+ digest_length )
320+ self .assertEqual (len (m .hexdigest (digest_length )),
321+ 2 * digest_length )
322+ else :
323+ self .assertEqual (len (m .digest ()), digest_size )
324+ self .assertEqual (len (m .hexdigest ()), 2 * digest_size )
272325 self .assertEqual (m .name , name )
273326 # split for sha3_512 / _sha3.sha3 object
274327 self .assertIn (name .split ("_" )[0 ], repr (m ))
@@ -280,6 +333,12 @@ def test_blocksize_name(self):
280333 self .check_blocksize_name ('sha256' , 64 , 32 )
281334 self .check_blocksize_name ('sha384' , 128 , 48 )
282335 self .check_blocksize_name ('sha512' , 128 , 64 )
336+ self .check_blocksize_name ('sha3_224' , 144 , 28 )
337+ self .check_blocksize_name ('sha3_256' , 136 , 32 )
338+ self .check_blocksize_name ('sha3_384' , 104 , 48 )
339+ self .check_blocksize_name ('sha3_512' , 72 , 64 )
340+ self .check_blocksize_name ('shake_128' , 168 , 0 , 32 )
341+ self .check_blocksize_name ('shake_256' , 136 , 0 , 64 )
283342
284343 @requires_blake2
285344 def test_blocksize_name_blake2 (self ):
@@ -563,6 +622,72 @@ def test_blake2s_vectors(self):
563622 key = bytes .fromhex (key )
564623 self .check ('blake2s' , msg , md , key = key )
565624
625+ @requires_sha3
626+ def test_case_sha3_224_0 (self ):
627+ self .check ('sha3_224' , b"" ,
628+ "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7" )
629+
630+ @requires_sha3
631+ def test_case_sha3_224_vector (self ):
632+ for msg , md in read_vectors ('sha3_224' ):
633+ self .check ('sha3_224' , msg , md )
634+
635+ @requires_sha3
636+ def test_case_sha3_256_0 (self ):
637+ self .check ('sha3_256' , b"" ,
638+ "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" )
639+
640+ @requires_sha3
641+ def test_case_sha3_256_vector (self ):
642+ for msg , md in read_vectors ('sha3_256' ):
643+ self .check ('sha3_256' , msg , md )
644+
645+ @requires_sha3
646+ def test_case_sha3_384_0 (self ):
647+ self .check ('sha3_384' , b"" ,
648+ "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a" +
649+ "c3713831264adb47fb6bd1e058d5f004" )
650+
651+ @requires_sha3
652+ def test_case_sha3_384_vector (self ):
653+ for msg , md in read_vectors ('sha3_384' ):
654+ self .check ('sha3_384' , msg , md )
655+
656+ @requires_sha3
657+ def test_case_sha3_512_0 (self ):
658+ self .check ('sha3_512' , b"" ,
659+ "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6" +
660+ "15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26" )
661+
662+ @requires_sha3
663+ def test_case_sha3_512_vector (self ):
664+ for msg , md in read_vectors ('sha3_512' ):
665+ self .check ('sha3_512' , msg , md )
666+
667+ @requires_sha3
668+ def test_case_shake_128_0 (self ):
669+ self .check ('shake_128' , b"" ,
670+ "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26" ,
671+ True )
672+ self .check ('shake_128' , b"" , "7f9c" , True )
673+
674+ @requires_sha3
675+ def test_case_shake128_vector (self ):
676+ for msg , md in read_vectors ('shake_128' ):
677+ self .check ('shake_128' , msg , md , True )
678+
679+ @requires_sha3
680+ def test_case_shake_256_0 (self ):
681+ self .check ('shake_256' , b"" ,
682+ "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f" ,
683+ True )
684+ self .check ('shake_256' , b"" , "46b9" , True )
685+
686+ @requires_sha3
687+ def test_case_shake256_vector (self ):
688+ for msg , md in read_vectors ('shake_256' ):
689+ self .check ('shake_256' , msg , md , True )
690+
566691 def test_gil (self ):
567692 # Check things work fine with an input larger than the size required
568693 # for multithreaded operation (which is hardwired to 2048).
0 commit comments