Skip to content

Commit

Permalink
Add SHA224 and SHA512/224
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Dec 5, 2022
1 parent 2c7ee19 commit ad91f35
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 11 deletions.
3 changes: 2 additions & 1 deletion src/_sha2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ export abstract class SHA2<T extends SHA2<T>> extends Hash<T> {
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');
const state = this.get();
const outLen = len / 4;
const state = this.get();
if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');
for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);
}
Expand Down
32 changes: 24 additions & 8 deletions src/sha256.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ const SHA256_W = new Uint32Array(64);
class SHA256 extends SHA2<SHA256> {
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
private A = IV[0] | 0;
private B = IV[1] | 0;
private C = IV[2] | 0;
private D = IV[3] | 0;
private E = IV[4] | 0;
private F = IV[5] | 0;
private G = IV[6] | 0;
private H = IV[7] | 0;
A = IV[0] | 0;
B = IV[1] | 0;
C = IV[2] | 0;
D = IV[3] | 0;
E = IV[4] | 0;
F = IV[5] | 0;
G = IV[6] | 0;
H = IV[7] | 0;

constructor() {
super(64, 32, 8, false);
Expand Down Expand Up @@ -106,9 +106,25 @@ class SHA256 extends SHA2<SHA256> {
this.buffer.fill(0);
}
}
// Constants from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
class SHA224 extends SHA256 {
A = 0xc1059ed8 | 0;
B = 0x367cd507 | 0;
C = 0x3070dd17 | 0;
D = 0xf70e5939 | 0;
E = 0xffc00b31 | 0;
F = 0x68581511 | 0;
G = 0x64f98fa7 | 0;
H = 0xbefa4fa4 | 0;
constructor() {
super();
this.outputLen = 28;
}
}

/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
export const sha256 = wrapConstructor(() => new SHA256());
export const sha224 = wrapConstructor(() => new SHA224());
26 changes: 26 additions & 0 deletions src/sha512.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,31 @@ export class SHA512 extends SHA2<SHA512> {
}
}

class SHA512_224 extends SHA512 {
// h -- high 32 bits, l -- low 32 bits
Ah = 0x8c3d37c8 | 0;
Al = 0x19544da2 | 0;
Bh = 0x73e19966 | 0;
Bl = 0x89dcd4d6 | 0;
Ch = 0x1dfab7ae | 0;
Cl = 0x32ff9c82 | 0;
Dh = 0x679dd514 | 0;
Dl = 0x582f9fcf | 0;
Eh = 0x0f6d2b69 | 0;
El = 0x7bd44da8 | 0;
Fh = 0x77e36f73 | 0;
Fl = 0x04c48942 | 0;
Gh = 0x3f9d85a8 | 0;
Gl = 0x6a1d36c8 | 0;
Hh = 0x1112e6ad | 0;
Hl = 0x91d692a1 | 0;

constructor() {
super();
this.outputLen = 28;
}
}

class SHA512_256 extends SHA512 {
// h -- high 32 bits, l -- low 32 bits
Ah = 0x22312194 | 0;
Expand Down Expand Up @@ -217,5 +242,6 @@ class SHA384 extends SHA512 {
}

export const sha512 = wrapConstructor(() => new SHA512());
export const sha512_224 = wrapConstructor(() => new SHA512_224());
export const sha512_256 = wrapConstructor(() => new SHA512_256());
export const sha384 = wrapConstructor(() => new SHA384());
33 changes: 31 additions & 2 deletions test/hashes.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const assert = require('assert');
const { should } = require('micro-should');
const crypto = require('crypto');
const { sha256 } = require('../sha256');
const { sha384, sha512, sha512_256 } = require('../sha512');
const { sha224, sha256 } = require('../sha256');
const { sha384, sha512, sha512_224, sha512_256 } = require('../sha512');
const {
sha3_224,
sha3_256,
Expand Down Expand Up @@ -64,6 +64,20 @@ const HASHES = {
'7789f0c9 ef7bfc40 d9331114 3dfbe69e 2017f592',
],
},
SHA224: {
fn: sha224,
obj: sha224.create,
node: (buf) => Uint8Array.from(crypto.createHash('sha224').update(buf).digest()),
node_obj: () => crypto.createHash('sha224'),
nist: [
'23097d22 3405d822 8642a477 bda255b3 2aadbce4 bda0b3f7 e36c9da7',
'd14a028c 2a3a2bc9 476102bb 288234c4 15a2b01f 828ea62a c5b3e42f',
'75388b16 512776cc 5dba5da1 fd890150 b0c6455c b4f58b19 52522525',
'c97ca9a5 59850ce9 7a04a96d ef6d99a9 e0e0e2ab 14e6b8df 265fc0b3',
'20794655 980c91d8 bbb4c1ea 97618a4b f03f4258 1948b2ee 4ee7ad67',
'b5989713 ca4fe47a 009f8621 980b34e6 d63ed306 3b2a0a2c 867d8a85',
],
},
SHA256: {
fn: sha256,
obj: sha256.create,
Expand Down Expand Up @@ -120,6 +134,21 @@ const HASHES = {
'5441235cc0235341 ed806a64fb354742 b5e5c02a3c5cb71b 5f63fb793458d8fd ae599c8cd8884943 c04f11b31b89f023',
],
},
SHA512_224: {
fn: sha512_224,
obj: sha512_224.create,
node: (buf) => Uint8Array.from(crypto.createHash('sha512-224').update(buf).digest()),
node_obj: () => crypto.createHash('sha512-224'),
// There is no official vectors, so we created them via:
// > NIST_VECTORS.map((i) => crypto.createHash('sha512-256').update(i[2]).digest('hex'))
nist: [
'4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa',
'6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4',
'e5302d6d54bb242275d1e7622d68df6eb02dedd13f564c13dbda2174',
'23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9',
'37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287',
],
},
SHA512_256: {
fn: sha512_256,
obj: sha512_256.create,
Expand Down

0 comments on commit ad91f35

Please sign in to comment.