11import { expect , it , describe } from 'bun:test'
2- import { sha256 } from '../src/sha256 '
2+ import { sha512 , sha384 , sha512_256 , sha512_224 } from '../src/sha512 '
33import { ByteStringBuffer } from 'ts-security-utils'
44
5- describe ( 'SHA-256 ' , ( ) => {
5+ describe ( 'SHA-512 ' , ( ) => {
66 describe ( 'API structure' , ( ) => {
7- it ( 'should export a sha256 object with create method' , ( ) => {
8- expect ( sha256 ) . toBeDefined ( )
9- expect ( typeof sha256 . create ) . toBe ( 'function' )
7+ it ( 'should export a sha512 object with create method' , ( ) => {
8+ expect ( sha512 ) . toBeDefined ( )
9+ expect ( typeof sha512 . create ) . toBe ( 'function' )
1010 } )
1111
12- it ( 'should create a SHA-256 message digest object with correct interface' , ( ) => {
13- const md = sha256 . create ( )
12+ it ( 'should create a SHA-512 message digest object with correct interface' , ( ) => {
13+ const md = sha512 . create ( )
1414 expect ( md ) . toBeDefined ( )
15- expect ( md . algorithm ) . toBe ( 'sha256 ' )
16- expect ( md . blockLength ) . toBe ( 64 )
17- expect ( md . digestLength ) . toBe ( 32 ) // SHA-256 produces a 32 -byte (256 -bit) digest
15+ expect ( md . algorithm ) . toBe ( 'sha512 ' )
16+ expect ( md . blockLength ) . toBe ( 128 )
17+ expect ( md . digestLength ) . toBe ( 64 ) // SHA-512 produces a 64 -byte (512 -bit) digest
1818 expect ( typeof md . start ) . toBe ( 'function' )
1919 expect ( typeof md . update ) . toBe ( 'function' )
2020 expect ( typeof md . digest ) . toBe ( 'function' )
@@ -23,50 +23,50 @@ describe('SHA-256', () => {
2323
2424 describe ( 'hashing functionality' , ( ) => {
2525 it ( 'should hash empty string' , ( ) => {
26- const md = sha256 . create ( )
26+ const md = sha512 . create ( )
2727 const hash = md . update ( '' ) . digest ( )
2828 expect ( hash ) . toBeDefined ( )
2929 expect ( typeof hash . toHex ( ) ) . toBe ( 'string' )
30- expect ( hash . toHex ( ) . length ) . toBe ( 64 ) // SHA-256 produces a 256 -bit (64 hex chars) hash
30+ expect ( hash . toHex ( ) . length ) . toBe ( 128 ) // SHA-512 produces a 512 -bit (128 hex chars) hash
3131
32- expect ( hash . toHex ( ) ) . toBe ( 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 ' )
32+ expect ( hash . toHex ( ) ) . toBe ( 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e ' )
3333 } )
3434
3535 it ( 'should hash "abc"' , ( ) => {
36- const md = sha256 . create ( )
36+ const md = sha512 . create ( )
3737 const hash = md . update ( 'abc' ) . digest ( )
3838 expect ( hash ) . toBeDefined ( )
39- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
39+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
4040
41- expect ( hash . toHex ( ) ) . toBe ( 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ' )
41+ expect ( hash . toHex ( ) ) . toBe ( 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f ' )
4242 } )
4343
4444 it ( 'should hash longer text' , ( ) => {
45- const md = sha256 . create ( )
45+ const md = sha512 . create ( )
4646 const hash = md . update ( 'The quick brown fox jumps over the lazy dog' ) . digest ( )
4747 expect ( hash ) . toBeDefined ( )
48- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
48+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
4949
50- expect ( hash . toHex ( ) ) . toBe ( 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 ' )
50+ expect ( hash . toHex ( ) ) . toBe ( '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6 ' )
5151 } )
5252 } )
5353
5454 describe ( 'incremental hashing' , ( ) => {
5555 it ( 'should support incremental hashing' , ( ) => {
56- const md = sha256 . create ( )
56+ const md = sha512 . create ( )
5757 md . update ( 'The quick brown ' )
5858 md . update ( 'fox jumps over ' )
5959 md . update ( 'the lazy dog' )
6060 const hash = md . digest ( )
6161 expect ( hash ) . toBeDefined ( )
62- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
62+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
6363
6464 // Should match the hash of the complete string
65- expect ( hash . toHex ( ) ) . toBe ( 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 ' )
65+ expect ( hash . toHex ( ) ) . toBe ( '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6 ' )
6666 } )
6767
6868 it ( 'should allow multiple digests from the same instance' , ( ) => {
69- const md = sha256 . create ( )
69+ const md = sha512 . create ( )
7070 md . start ( )
7171 md . update ( 'abc' )
7272 const hash1 = md . digest ( )
@@ -84,7 +84,7 @@ describe('SHA-256', () => {
8484
8585 describe ( 'UTF-8 encoding' , ( ) => {
8686 it ( 'should handle UTF-8 encoding parameter' , ( ) => {
87- const md = sha256 . create ( )
87+ const md = sha512 . create ( )
8888 expect ( ( ) => md . update ( 'test string' , 'utf8' ) ) . not . toThrow ( )
8989 } )
9090 } )
@@ -94,55 +94,53 @@ describe('SHA-256', () => {
9494 const buffer = new ByteStringBuffer ( )
9595 buffer . putBytes ( 'abc' )
9696
97- const md = sha256 . create ( )
97+ const md = sha512 . create ( )
9898 const hash = md . update ( buffer as unknown as string ) . digest ( )
9999 expect ( hash ) . toBeDefined ( )
100- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
100+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
101101 } )
102102 } )
103103
104104 describe ( 'edge cases' , ( ) => {
105105 it ( 'should handle messages that require padding to a new block' , ( ) => {
106- // 64 bytes is exactly one block, so this will require padding in a new block
107- const md = sha256 . create ( )
108- const hash = md . update ( 'a' . repeat ( 64 ) ) . digest ( )
106+ const md = sha512 . create ( )
107+ const hash = md . update ( 'a' . repeat ( 128 ) ) . digest ( )
109108 expect ( hash ) . toBeDefined ( )
110- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
109+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
111110
112- // Current implementation produces: 'ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb'
113- expect ( hash . toHex ( ) ) . toBe ( 'ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb' )
111+ expect ( hash . toHex ( ) ) . toBe ( 'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a243667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321' )
114112 } )
115113
116114 it ( 'should handle messages that are exactly one byte less than a block' , ( ) => {
117- // 63 bytes is one byte less than a block
118- const md = sha256 . create ( )
119- const hash = md . update ( 'a' . repeat ( 63 ) ) . digest ( )
115+ // 127 bytes is one byte less than a block
116+ const md = sha512 . create ( )
117+ const hash = md . update ( 'a' . repeat ( 127 ) ) . digest ( )
120118 expect ( hash ) . toBeDefined ( )
121- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
119+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
122120 } )
123121
124122 it ( 'should handle longer messages' , ( ) => {
125123 // Test with a longer message (multiple blocks)
126- const md = sha256 . create ( )
124+ const md = sha512 . create ( )
127125 const hash = md . update ( 'a' . repeat ( 200 ) ) . digest ( )
128126 expect ( hash ) . toBeDefined ( )
129- expect ( hash . toHex ( ) . length ) . toBe ( 64 )
127+ expect ( hash . toHex ( ) . length ) . toBe ( 128 )
130128 } )
131129 } )
132130
133131 describe ( 'state management' , ( ) => {
134132 it ( 'should reset state when start() is called' , ( ) => {
135- const md = sha256 . create ( )
133+ const md = sha512 . create ( )
136134 md . update ( 'test' )
137135 md . start ( )
138136 expect ( md . messageLength ) . toBe ( 0 )
139137 } )
140138
141139 it ( 'should maintain state between updates' , ( ) => {
142- const md1 = sha256 . create ( )
140+ const md1 = sha512 . create ( )
143141 const singleHash = md1 . update ( 'abcdef' ) . digest ( ) . toHex ( )
144142
145- const md2 = sha256 . create ( )
143+ const md2 = sha512 . create ( )
146144 md2 . update ( 'abc' )
147145 md2 . update ( 'def' )
148146 const incrementalHash = md2 . digest ( ) . toHex ( )
@@ -151,10 +149,10 @@ describe('SHA-256', () => {
151149 } )
152150 } )
153151
154- describe ( 'SHA-256 specific features' , ( ) => {
152+ describe ( 'SHA-512 specific features' , ( ) => {
155153 it ( 'should use the correct initial hash values' , ( ) => {
156- // SHA-256 has specific initial hash values defined in the standard
157- const md = sha256 . create ( )
154+ // SHA-512 has specific initial hash values defined in the standard
155+ const md = sha512 . create ( )
158156
159157 // We'll test this indirectly by checking the hash of an empty string
160158 // which should only depend on the initial values and padding
@@ -163,65 +161,178 @@ describe('SHA-256', () => {
163161 } )
164162
165163 it ( 'should handle the K constants correctly' , ( ) => {
166- // SHA-256 uses 64 constants in its compression function
164+ // SHA-512 uses 80 constants in its compression function
167165 // We'll test this indirectly by hashing data that would exercise these constants
168- const md = sha256 . create ( )
169- const hash = md . update ( 'a' . repeat ( 64 ) ) . digest ( ) // One full block
166+ const md = sha512 . create ( )
167+ const hash = md . update ( 'a' . repeat ( 80 ) ) . digest ( ) // One full block
170168 expect ( hash ) . toBeDefined ( )
171169 } )
172170 } )
173171
174172 describe ( 'NIST test vectors' , ( ) => {
175173 it ( 'should match NIST test vector 1' , ( ) => {
176- const md = sha256 . create ( )
174+ const md = sha512 . create ( )
177175 const hash = md . update ( 'abc' ) . digest ( )
178- expect ( hash . toHex ( ) ) . toBe ( 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ' )
176+ expect ( hash . toHex ( ) ) . toBe ( 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f ' )
179177 } )
180178
181179 it ( 'should match NIST test vector 2' , ( ) => {
182- const md = sha256 . create ( )
180+ const md = sha512 . create ( )
183181 const hash = md . update ( 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq' ) . digest ( )
184- expect ( hash . toHex ( ) ) . toBe ( '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 ' )
182+ expect ( hash . toHex ( ) ) . toBe ( '204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 ' )
185183 } )
186184
187185 it ( 'should produce consistent results for "a" repeated 1000 times' , ( ) => {
188- const md = sha256 . create ( )
186+ const md = sha512 . create ( )
189187 const hash = md . update ( 'a' . repeat ( 1000 ) ) . digest ( )
190188
191- expect ( hash . toHex ( ) ) . toBe ( '41edece42d63e8d9bf515a9ba6932e1c20cbc9f5a5d134645adb5db1b9737ea3 ' )
189+ expect ( hash . toHex ( ) ) . toBe ( '67ba5535a46e3f86dbfbed8cbbaf0125c76ed549ff8b0b9e03e0c88cf90fa634fa7b12b47d77b694de488ace8d9a65967dc96df599727d3292a8d9d447709c97 ' )
192190 } )
193191 } )
194192
195193 describe ( 'edge cases with consistent outputs' , ( ) => {
196194 it ( 'should consistently hash a message that is exactly one block' , ( ) => {
197- const md = sha256 . create ( )
198- // SHA-256 block size is 64 bytes
199- const hash = md . update ( 'a' . repeat ( 64 ) ) . digest ( )
200- expect ( hash . toHex ( ) ) . toBe ( 'ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb ' )
195+ const md = sha512 . create ( )
196+ // SHA-512 block size is 128 bytes
197+ const hash = md . update ( 'a' . repeat ( 128 ) ) . digest ( )
198+ expect ( hash . toHex ( ) ) . toBe ( 'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a243667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321 ' )
201199 } )
202200
203201 it ( 'should consistently hash a message that spans multiple blocks' , ( ) => {
204- const md = sha256 . create ( )
202+ const md = sha512 . create ( )
205203 // 120 bytes (spans 2 blocks)
206204 const hash = md . update ( 'a' . repeat ( 120 ) ) . digest ( )
207205
208- expect ( hash . toHex ( ) ) . toBe ( '2f3d335432c70b580af0e8e1b3674a7c020d683aa5f73aaaedfdc55af904c21c ' )
206+ expect ( hash . toHex ( ) ) . toBe ( 'f241de612b01aa2fa3cf01531d2a8e5e17fc761dfd48a704a834a47f57d6eade7804ecc39be42fdef16ec6adeaf7c01c2fd0c4cc97d3860907cfa4a3b36d0c05 ' )
209207 } )
210208 } )
211209
212210 describe ( 'special test cases' , ( ) => {
213211 it ( 'should consistently hash a message with a period' , ( ) => {
214- const md = sha256 . create ( )
212+ const md = sha512 . create ( )
215213 const hash = md . update ( 'abc.' ) . digest ( )
216214
217- expect ( hash . toHex ( ) ) . toBe ( '5ac9481b887da55cdb508bbb7d91e7896c418c1ad3badb6f4f6d2a524f5cdcaf ' )
215+ expect ( hash . toHex ( ) ) . toBe ( '5fffad2405028218042feee8f1e7e8af4b8e119e5cd7172091b7d6a09068f1ee04cf2f83e8f4342397c65cb553215e31d6d370b48e1d87f880253a281a44b4a6 ' )
218216 } )
219217
220218 it ( 'should consistently hash a message with special characters' , ( ) => {
221- const md = sha256 . create ( )
219+ const md = sha512 . create ( )
222220 const hash = md . update ( 'abc!@#$%^&*()' ) . digest ( )
223221
224- expect ( hash . toHex ( ) ) . toBe ( '12467d627114bfff999bc2570676736fbdc19ece55d83be7ebfb6603576e9972 ' )
222+ expect ( hash . toHex ( ) ) . toBe ( 'ad7333f992837ac94ec3c236a9fe2e3916b53fd28e9b5ab9f176f616e0da3d765e5fead6ab2c42e06dfb3df90dd7867c49b9692d6a18817a6b7456b64ab5351d ' )
225223 } )
226224 } )
227225} )
226+
227+ describe ( 'sha384' , ( ) => {
228+ it ( 'should have correct digest length' , ( ) => {
229+ expect ( sha384 . digestLength ) . toBe ( 48 )
230+ } )
231+
232+ it ( 'should digest the empty string' , ( ) => {
233+ const md = sha384
234+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
235+ '38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'
236+ )
237+ } )
238+
239+ it ( 'should digest "abc"' , ( ) => {
240+ const md = sha384
241+ md . update ( 'abc' )
242+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
243+ 'cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7'
244+ )
245+ } )
246+
247+ it ( 'should digest "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"' , ( ) => {
248+ const md = sha384
249+ md . update ( 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu' )
250+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
251+ 'ef8b20e8c90839628529dc71a9a9f571e9c4efbd2c2e7ef45da5be177f009965f49be0f62c2e3c9a8759fbdeff45d367'
252+ )
253+ } )
254+
255+ it ( 'should digest "The quick brown fox jumps over the lazy dog"' , ( ) => {
256+ const md = sha384
257+ md . update ( 'The quick brown fox jumps over the lazy dog' )
258+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
259+ '3b2e7c68c0ddde61fb92bb00aa8e36ada3164322a393b2075f95edee93c7cd48bc5577c3ec6bf9a7392c33c58e26e916'
260+ )
261+ } )
262+
263+ it ( 'should digest "c\'\u00E8"' , ( ) => {
264+ const md = sha384
265+ md . update ( 'c\'\u00E8' , 'utf8' )
266+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
267+ '351b6fea9efe4eb10d7a95d438f2135183c8df0e358df967dd32c3563183cfd58133fc4639f1e18ca4e5cd6b1fbc5fe5'
268+ )
269+ } )
270+
271+ it ( 'should digest "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"' , ( ) => {
272+ const md = sha384
273+ md . start ( )
274+ md . update ( 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq' )
275+ // do twice to check continuing digest
276+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
277+ '3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b'
278+ )
279+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
280+ '3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b'
281+ )
282+ } )
283+
284+ it ( 'should digest multiple long messages' , ( ) => {
285+ for ( let loop = 0 ; loop < 3 ; ++ loop ) {
286+ const md = sha384
287+ for ( let i = 0 ; i < 10000 ; ++ i ) {
288+ md . update ( 'abc' )
289+ }
290+ const hash = md . digest ( ) . toHex ( )
291+ expect ( hash . length ) . toBe ( 96 ) // SHA-384 produces a 48-byte (96 hex character) hash
292+ }
293+ } )
294+ } )
295+
296+ describe ( 'sha512/256' , ( ) => {
297+ it ( 'should have correct digest length' , ( ) => {
298+ const md = sha512_256
299+ expect ( md . digestLength ) . toBe ( 32 )
300+ } )
301+
302+ it ( 'should digest the empty string' , ( ) => {
303+ const md = sha512_256
304+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
305+ 'c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a'
306+ )
307+ } )
308+
309+ it ( 'should digest "The quick brown fox jumps over the lazy dog"' , ( ) => {
310+ const md = sha512_256
311+ md . update ( 'The quick brown fox jumps over the lazy dog' )
312+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
313+ 'dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d'
314+ )
315+ } )
316+ } )
317+
318+ describe ( 'sha512/224' , ( ) => {
319+ it ( 'should have correct digest length' , ( ) => {
320+ const md = sha512_224
321+ expect ( md . digestLength ) . toBe ( 28 )
322+ } )
323+
324+ it ( 'should digest the empty string' , ( ) => {
325+ const md = sha512_224
326+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
327+ '6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4'
328+ )
329+ } )
330+
331+ it ( 'should digest "The quick brown fox jumps over the lazy dog"' , ( ) => {
332+ const md = sha512_224
333+ md . update ( 'The quick brown fox jumps over the lazy dog' )
334+ expect ( md . digest ( ) . toHex ( ) ) . toBe (
335+ '944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37'
336+ )
337+ } )
338+ } )
0 commit comments