Skip to content

Commit 84f1dd6

Browse files
committed
chore: wip
1 parent 9d74eea commit 84f1dd6

4 files changed

Lines changed: 388 additions & 286 deletions

File tree

packages/sha/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * from './sha1'
22
export * from './sha256'
33
export * from './sha384'
4-
// export * from './sha512'
4+
export * from './sha512'

packages/sha/test/sha512.test.ts

Lines changed: 174 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import { expect, it, describe } from 'bun:test'
2-
import { sha256 } from '../src/sha256'
2+
import { sha512, sha384, sha512_256, sha512_224 } from '../src/sha512'
33
import { 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

Comments
 (0)