Skip to content

Commit da2c37d

Browse files
authored
fix: hash/hmac string passing (#856)
1 parent 90f8af7 commit da2c37d

18 files changed

Lines changed: 395 additions & 29 deletions

File tree

docs/implementation-coverage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ These algorithms provide quantum-resistant cryptography.
253253
*`subtle.decapsulateKey(decapsulationAlgorithm, decapsulationKey, ciphertext, sharedKeyAlgorithm, extractable, usages)`
254254
*`subtle.decrypt(algorithm, key, data)`
255255
* 🚧 `subtle.deriveBits(algorithm, baseKey, length)`
256-
* `subtle.deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)`
256+
* 🚧 `subtle.deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)`
257257
* 🚧 `subtle.digest(algorithm, data)`
258258
*`subtle.encapsulateBits(encapsulationAlgorithm, encapsulationKey)`
259259
*`subtle.encapsulateKey(encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable, usages)`

example/src/benchmarks/benchmarks.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ export class BenchmarkSuite {
2828

2929
async run() {
3030
this.results = [];
31-
const promises = this.benchmarks.map(async benchFn => {
31+
// Run benchmarks sequentially to avoid timing interference
32+
for (const benchFn of this.benchmarks) {
3233
const b = await benchFn();
3334
await b.run();
3435
this.processResults(b);
35-
this.state = 'done';
36-
});
37-
await Promise.all(promises);
36+
}
37+
this.state = 'done';
3838
}
3939

4040
processResults = (b: Bench): void => {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import rnqc from 'react-native-quick-crypto';
2+
// @ts-expect-error - crypto-browserify is not typed
3+
import browserify from 'crypto-browserify';
4+
import { gcm } from '@noble/ciphers/aes.js';
5+
import type { BenchFn } from '../../types/benchmarks';
6+
import { Bench } from 'tinybench';
7+
import { buffer1MB } from '../testData';
8+
9+
// Generate a key for AES-256-GCM
10+
const key = rnqc.randomBytes(32);
11+
const iv = rnqc.randomBytes(12);
12+
13+
// @noble requires Uint8Array
14+
const nobleKey = new Uint8Array(key);
15+
const nobleIv = new Uint8Array(iv);
16+
17+
const cipher_aes256gcm_1mb_buffer: BenchFn = () => {
18+
const bench = new Bench({
19+
name: 'cipher aes256gcm 1MB Buffer',
20+
iterations: 1,
21+
warmupIterations: 0,
22+
});
23+
24+
const nobleData = new Uint8Array(buffer1MB);
25+
26+
bench
27+
.add('rnqc', () => {
28+
const cipher = rnqc.createCipheriv('aes-256-gcm', key, iv);
29+
cipher.update(buffer1MB);
30+
cipher.final();
31+
})
32+
.add('@noble/ciphers/aes', () => {
33+
const cipher = gcm(nobleKey, nobleIv);
34+
cipher.encrypt(nobleData);
35+
})
36+
.add('browserify', () => {
37+
const cipher = browserify.createCipheriv('aes-256-gcm', key, iv);
38+
cipher.update(buffer1MB);
39+
cipher.final();
40+
});
41+
42+
return bench;
43+
};
44+
45+
export default [cipher_aes256gcm_1mb_buffer];
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import rnqc from 'react-native-quick-crypto';
2+
import { sha256 } from '@noble/hashes/sha2';
3+
// @ts-expect-error - crypto-browserify is not typed
4+
import browserify from 'crypto-browserify';
5+
import type { BenchFn } from '../../types/benchmarks';
6+
import { Bench } from 'tinybench';
7+
import { text1MB, text8MB, buffer1MB, buffer8MB } from '../testData';
8+
9+
const hash_sha256_8mb_string: BenchFn = () => {
10+
const bench = new Bench({
11+
name: 'hash sha256 8MB string',
12+
iterations: 3,
13+
warmupIterations: 1,
14+
time: 0,
15+
});
16+
17+
bench
18+
.add('rnqc', () => {
19+
const hash = rnqc.createHash('sha256');
20+
hash.update(text8MB);
21+
hash.digest('hex');
22+
})
23+
.add('@noble/hashes/sha256', () => {
24+
sha256(text8MB);
25+
})
26+
.add('browserify', () => {
27+
const hash = browserify.createHash('sha256');
28+
hash.update(text8MB);
29+
hash.digest('hex');
30+
});
31+
32+
return bench;
33+
};
34+
35+
const hash_sha256_1mb_string: BenchFn = () => {
36+
const bench = new Bench({
37+
name: 'hash sha256 1MB string',
38+
iterations: 5,
39+
warmupIterations: 2,
40+
time: 0,
41+
});
42+
43+
bench
44+
.add('rnqc', () => {
45+
const hash = rnqc.createHash('sha256');
46+
hash.update(text1MB);
47+
hash.digest('hex');
48+
})
49+
.add('@noble/hashes/sha256', () => {
50+
sha256(text1MB);
51+
})
52+
.add('browserify', () => {
53+
const hash = browserify.createHash('sha256');
54+
hash.update(text1MB);
55+
hash.digest('hex');
56+
});
57+
58+
return bench;
59+
};
60+
61+
const hash_sha256_8mb_buffer: BenchFn = () => {
62+
const bench = new Bench({
63+
name: 'hash sha256 8MB Buffer',
64+
iterations: 3,
65+
warmupIterations: 1,
66+
time: 0,
67+
});
68+
69+
bench
70+
.add('rnqc', () => {
71+
const hash = rnqc.createHash('sha256');
72+
hash.update(buffer8MB);
73+
hash.digest('hex');
74+
})
75+
.add('@noble/hashes/sha256', () => {
76+
sha256(buffer8MB);
77+
})
78+
.add('browserify', () => {
79+
const hash = browserify.createHash('sha256');
80+
hash.update(buffer8MB);
81+
hash.digest('hex');
82+
});
83+
84+
return bench;
85+
};
86+
87+
const hash_sha256_1mb_buffer: BenchFn = () => {
88+
const bench = new Bench({
89+
name: 'hash sha256 1MB Buffer',
90+
iterations: 5,
91+
warmupIterations: 2,
92+
time: 0,
93+
});
94+
95+
bench
96+
.add('rnqc', () => {
97+
const hash = rnqc.createHash('sha256');
98+
hash.update(buffer1MB);
99+
hash.digest('hex');
100+
})
101+
.add('@noble/hashes/sha256', () => {
102+
sha256(buffer1MB);
103+
})
104+
.add('browserify', () => {
105+
const hash = browserify.createHash('sha256');
106+
hash.update(buffer1MB);
107+
hash.digest('hex');
108+
});
109+
110+
return bench;
111+
};
112+
113+
export default [
114+
hash_sha256_1mb_string,
115+
hash_sha256_1mb_buffer,
116+
hash_sha256_8mb_string,
117+
hash_sha256_8mb_buffer,
118+
];
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import rnqc from 'react-native-quick-crypto';
2+
// @ts-expect-error - crypto-browserify is not typed
3+
import browserify from 'crypto-browserify';
4+
import { hmac } from '@noble/hashes/hmac';
5+
import { sha256 } from '@noble/hashes/sha2';
6+
import type { BenchFn } from '../../types/benchmarks';
7+
import { Bench } from 'tinybench';
8+
import { text1MB, text8MB, buffer1MB, buffer8MB } from '../testData';
9+
10+
const hmacKey = 'test-key-for-hmac-benchmarks';
11+
12+
const hmac_sha256_8mb_string: BenchFn = () => {
13+
const bench = new Bench({
14+
name: 'hmac sha256 8MB string',
15+
iterations: 3,
16+
warmupIterations: 1,
17+
time: 0,
18+
});
19+
20+
bench
21+
.add('rnqc', () => {
22+
const h = rnqc.createHmac('sha256', hmacKey);
23+
h.update(text8MB);
24+
h.digest('hex');
25+
})
26+
.add('@noble/hashes/hmac', () => {
27+
hmac(sha256, hmacKey, text8MB);
28+
})
29+
.add('browserify', () => {
30+
const h = browserify.createHmac('sha256', hmacKey);
31+
h.update(text8MB);
32+
h.digest('hex');
33+
});
34+
35+
return bench;
36+
};
37+
38+
const hmac_sha256_1mb_string: BenchFn = () => {
39+
const bench = new Bench({
40+
name: 'hmac sha256 1MB string',
41+
iterations: 5,
42+
warmupIterations: 2,
43+
time: 0,
44+
});
45+
46+
bench
47+
.add('rnqc', () => {
48+
const h = rnqc.createHmac('sha256', hmacKey);
49+
h.update(text1MB);
50+
h.digest('hex');
51+
})
52+
.add('@noble/hashes/hmac', () => {
53+
hmac(sha256, hmacKey, text1MB);
54+
})
55+
.add('browserify', () => {
56+
const h = browserify.createHmac('sha256', hmacKey);
57+
h.update(text1MB);
58+
h.digest('hex');
59+
});
60+
61+
return bench;
62+
};
63+
64+
const hmac_sha256_8mb_buffer: BenchFn = () => {
65+
const bench = new Bench({
66+
name: 'hmac sha256 8MB Buffer',
67+
iterations: 3,
68+
warmupIterations: 1,
69+
time: 0,
70+
});
71+
72+
bench
73+
.add('rnqc', () => {
74+
const h = rnqc.createHmac('sha256', hmacKey);
75+
h.update(buffer8MB);
76+
h.digest('hex');
77+
})
78+
.add('@noble/hashes/hmac', () => {
79+
hmac(sha256, hmacKey, buffer8MB);
80+
})
81+
.add('browserify', () => {
82+
const h = browserify.createHmac('sha256', hmacKey);
83+
h.update(buffer8MB);
84+
h.digest('hex');
85+
});
86+
87+
return bench;
88+
};
89+
90+
const hmac_sha256_1mb_buffer: BenchFn = () => {
91+
const bench = new Bench({
92+
name: 'hmac sha256 1MB Buffer',
93+
iterations: 5,
94+
warmupIterations: 2,
95+
time: 0,
96+
});
97+
98+
bench
99+
.add('rnqc', () => {
100+
const h = rnqc.createHmac('sha256', hmacKey);
101+
h.update(buffer1MB);
102+
h.digest('hex');
103+
})
104+
.add('@noble/hashes/hmac', () => {
105+
hmac(sha256, hmacKey, buffer1MB);
106+
})
107+
.add('browserify', () => {
108+
const h = browserify.createHmac('sha256', hmacKey);
109+
h.update(buffer1MB);
110+
h.digest('hex');
111+
});
112+
113+
return bench;
114+
};
115+
116+
export default [
117+
hmac_sha256_1mb_string,
118+
hmac_sha256_1mb_buffer,
119+
hmac_sha256_8mb_string,
120+
hmac_sha256_8mb_buffer,
121+
];

example/src/benchmarks/testData.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Shared test data for benchmarks
2+
// Generate test data of different sizes using repeating pattern
3+
const generateString = (sizeInMB: number): string => {
4+
const chunk =
5+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
6+
const bytesPerMB = 1024 * 1024;
7+
const totalBytes = Math.floor(sizeInMB * bytesPerMB);
8+
const repeatCount = Math.ceil(totalBytes / chunk.length);
9+
return chunk.repeat(repeatCount).substring(0, totalBytes);
10+
};
11+
12+
// Pre-generate test data once for all benchmarks
13+
export const text100KB = generateString(0.1);
14+
export const text1MB = generateString(1);
15+
export const text8MB = generateString(8);
16+
17+
// Pre-generate Buffer versions for comparison
18+
export const buffer100KB = Buffer.from(text100KB);
19+
export const buffer1MB = Buffer.from(text1MB);
20+
export const buffer8MB = Buffer.from(text8MB);

example/src/components/BenchmarkResultItem.tsx

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,36 @@ export const BenchmarkResultItemHeader: React.FC = () => {
2424
export const BenchmarkResultItem: React.FC<BenchmarkResultItemProps> = ({
2525
result,
2626
}: BenchmarkResultItemProps) => {
27+
// Check if benchmark errored out
28+
const usHasError = result.us?.error !== undefined;
29+
const themHasError = result.them?.error !== undefined;
30+
31+
if (usHasError || themHasError) {
32+
return (
33+
<View>
34+
<View style={styles.subContainer}>
35+
<Text style={[styles.sub, styles.benchName]}>{result.benchName}</Text>
36+
</View>
37+
<View style={styles.subContainer}>
38+
<Text style={[styles.sub, styles.subLabel]}>error</Text>
39+
<Text style={[styles.sub, styles.subValue, styles.slower]}>
40+
{usHasError ? 'rnqc failed' : ''}
41+
{usHasError && themHasError ? ' / ' : ''}
42+
{themHasError ? `${result.challenger} failed` : ''}
43+
</Text>
44+
</View>
45+
</View>
46+
);
47+
}
48+
49+
const hasComparison = result.them !== undefined;
50+
2751
const rows = ['throughput', 'latency'].map((key, i) => {
2852
const us = result.us![key as Key].mean;
29-
const them = result.them![key as Key].mean;
53+
const them = hasComparison ? result.them![key as Key].mean : 0;
3054
const comparison = key === 'throughput' ? us > them : us < them;
3155
const places = key === 'throughput' ? 2 : 3;
32-
const times = calculateTimes(us, them);
56+
const times = hasComparison ? calculateTimes(us, them) : 0;
3357
const emoji = comparison ? '🐇' : '🐢';
3458
const timesType = comparison ? 'faster' : 'slower';
3559
const timesStyle = timesType === 'faster' ? styles.faster : styles.slower;
@@ -41,11 +65,15 @@ export const BenchmarkResultItem: React.FC<BenchmarkResultItemProps> = ({
4165
<Text style={[styles.text, styles.description]}>
4266
{key} {key === 'throughput' ? '(ops/s)' : '(ms)'}
4367
</Text>
44-
<Text style={[styles.value, timesStyle]}>
45-
{formatNumber(times, 2, 'x')}
46-
</Text>
68+
{hasComparison && (
69+
<Text style={[styles.value, timesStyle]}>
70+
{formatNumber(times, 2, 'x')}
71+
</Text>
72+
)}
4773
<Text style={styles.value}>{formatNumber(us, places, '')}</Text>
48-
<Text style={styles.value}>{formatNumber(them, places, '')}</Text>
74+
{hasComparison && (
75+
<Text style={styles.value}>{formatNumber(them, places, '')}</Text>
76+
)}
4977
</View>
5078
</View>
5179
);

0 commit comments

Comments
 (0)