@amritk/nish-x86_64-linux 0.27.2 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +16 -8
- package/bin/nish +0 -0
- package/docs/AI.md +118 -26
- package/package.json +1 -1
- package/runtime/core/host.d.ts +2 -1
- package/runtime/core/host.mjs +4 -0
- package/runtime/core.d.ts +47 -0
- package/runtime/core.mjs +67 -0
- package/runtime/nish.d.ts +176 -0
- package/runtime/nish.h +120 -6
- package/runtime/nish.mjs +24 -4
- package/runtime/runtime-checksum.c +270 -0
- package/runtime/runtime-net.c +386 -5
- package/runtime/runtime-os.c +59 -8
- package/runtime/runtime-parallel.c +81 -5
- package/runtime/runtime-sandbox.c +479 -0
- package/runtime/runtime-sha256.c +239 -0
- package/runtime/runtime-shm.c +541 -0
- package/runtime/runtime.c +827 -791
- package/scripts/build.sh +79 -28
- package/std/README.md +25 -13
- package/std/collections.ts +5 -5
- package/std/compress/checksum.ts +88 -75
- package/std/compress/deflate.ts +224 -0
- package/std/compress/gzip.ts +52 -0
- package/std/crypto/bcrypt.ts +816 -280
- package/std/crypto/hmac.ts +305 -2
- package/std/crypto/jwt.ts +1661 -0
- package/std/json-equal.ts +335 -0
- package/std/json-format.ts +1070 -0
- package/std/json-number.ts +428 -0
- package/std/json-pointer.ts +245 -0
- package/std/json-typed.ts +34 -0
- package/std/json-value.ts +510 -17
- package/std/json.ts +35 -6
- package/std/net/handler.ts +1348 -0
- package/std/net/http-client.ts +97 -16
- package/std/net/http-compress.ts +301 -16
- package/std/net/http1-client.ts +104 -19
- package/std/net/http1-server.ts +127 -24
- package/std/net/http1.ts +24 -4
- package/std/net/outbound.ts +409 -0
- package/std/net/postgres.ts +405 -0
- package/std/net/prefork.ts +344 -20
- package/std/net/websocket.ts +295 -14
- package/std/regex.ts +613 -52
- package/std/secret.ts +1 -1
- package/std/sync/ring.ts +587 -0
- package/std/sync/shm.ts +284 -0
- package/std/term-io.ts +35 -8
- package/std/term-rate.ts +13 -1
- package/std/threads.ts +35 -3
- package/std/yaml-json.ts +841 -0
- /package/runtime/{LICENSE-ryu → LICENSE-zmij} +0 -0
package/std/crypto/bcrypt.ts
CHANGED
|
@@ -14,13 +14,17 @@
|
|
|
14
14
|
* // "$2b$12$" + 22 salt characters + 31 digest characters
|
|
15
15
|
* const ok: Result<boolean, string> = bcryptVerify(pw, storedHash)
|
|
16
16
|
*
|
|
17
|
-
* **
|
|
17
|
+
* **Several at once.** `bcryptHashN` and `bcryptVerifyN` take one to six
|
|
18
18
|
* passwords (lane 0 always, a null lane skipped) and run their Blowfish
|
|
19
|
-
* encryptions interleaved in one loop, so one core does the work of
|
|
20
|
-
* hashes in well under the time of
|
|
21
|
-
* byte for byte. `
|
|
19
|
+
* encryptions interleaved in one loop, so one core does the work of several
|
|
20
|
+
* hashes in well under the time of as many; each result is the single path's,
|
|
21
|
+
* byte for byte. `bcryptVerifyN` groups lanes by the cost their hash names,
|
|
22
22
|
* and a malformed hash in any lane is an `Err` for the whole call, naming the
|
|
23
|
-
* lane, before anything is hashed.
|
|
23
|
+
* lane, before anything is hashed. `bcryptHash4` and `bcryptVerify4` are the
|
|
24
|
+
* same for up to four. Which width is fastest depends on the core (how many
|
|
25
|
+
* loads it issues a cycle, how much L1 the states fill), so `bcryptCalibrate`
|
|
26
|
+
* measures it: it times widths one to six at cost 4 on throwaway passwords
|
|
27
|
+
* and answers the one with the least time per hash. Call it once, at startup.
|
|
24
28
|
*
|
|
25
29
|
* **The password is a `Secret<u8[]>`** (`nish:secret`). The key schedule and
|
|
26
30
|
* the 2^cost rounds run inside `exposeWith`; the Blowfish state (the P-array
|
|
@@ -28,8 +32,8 @@
|
|
|
28
32
|
* are wiped before it returns. `bcryptVerify` rebuilds the whole 60-character
|
|
29
33
|
* hash and compares it with `timingSafeEqual` inside the same `exposeWith`,
|
|
30
34
|
* then wipes the rebuilt hash and the given hash's bytes; the batch wipes its
|
|
31
|
-
* digests and, in `
|
|
32
|
-
* hash strings `bcryptHash` and `
|
|
35
|
+
* state and digests and, in `bcryptVerifyN`, each lane's rebuilt and given
|
|
36
|
+
* hash. The hash strings `bcryptHash` and `bcryptHashN` return are public and are not
|
|
33
37
|
* wiped, nor are the bytes they are made from.
|
|
34
38
|
*
|
|
35
39
|
* **The key is the reference's.** The bytes up to the first NUL, then one NUL,
|
|
@@ -56,7 +60,9 @@
|
|
|
56
60
|
* cost the hash names, so a `$2b$31$` hash someone hands you takes 2^31
|
|
57
61
|
* rounds, hours of one core. Verify only hashes you stored.
|
|
58
62
|
*
|
|
59
|
-
* **Pure.** No I/O and no C, so it builds for wasm32
|
|
63
|
+
* **Pure.** No I/O and no C, so it builds for wasm32; `bcryptCalibrate`
|
|
64
|
+
* alone reads the monotonic clock (`clock` in `--emit-capabilities`), and the
|
|
65
|
+
* hashes never do. A `std/threads` task
|
|
60
66
|
* may call `bcryptHash`, `bcryptVerify` and the batch: everything they wipe
|
|
61
67
|
* is an array they made, never the caller's `hashes`, and the batch's state is
|
|
62
68
|
* a `Secret` of a fresh array
|
|
@@ -117,6 +123,7 @@
|
|
|
117
123
|
|
|
118
124
|
import { timingSafeEqual } from "nish/crypto/ct"
|
|
119
125
|
import { Secret, exposeWith, secret, wipe } from "nish:secret"
|
|
126
|
+
import { monotonicNanos } from "nish:process"
|
|
120
127
|
|
|
121
128
|
/** The length of a bcrypt hash string: `$2b$`, two cost digits, `$`, 22 salt and 31 digest characters. */
|
|
122
129
|
export const BCRYPT_HASH_LENGTH: i32 = 60
|
|
@@ -380,12 +387,13 @@ const bcryptEncrypt = (st: u32[], lr: u32[]): void => {
|
|
|
380
387
|
const lb: i32 = toI32(l >>> 16) & 0xff
|
|
381
388
|
const lc: i32 = toI32(l >>> 8) & 0xff
|
|
382
389
|
const ld: i32 = toI32(l) & 0xff
|
|
383
|
-
r
|
|
390
|
+
r = ctSelect(0xffffffff, r ^ st[n], 0) ^ (((st[18 + la] + st[274 + lb]) ^ st[530 + lc]) + st[786 + ld])
|
|
384
391
|
const ra: i32 = toI32(r >>> 24) & 0xff
|
|
385
392
|
const rb: i32 = toI32(r >>> 16) & 0xff
|
|
386
393
|
const rc: i32 = toI32(r >>> 8) & 0xff
|
|
387
394
|
const rd: i32 = toI32(r) & 0xff
|
|
388
|
-
l
|
|
395
|
+
l =
|
|
396
|
+
ctSelect(0xffffffff, l ^ st[n + 1], 0) ^ (((st[18 + ra] + st[274 + rb]) ^ st[530 + rc]) + st[786 + rd])
|
|
389
397
|
}
|
|
390
398
|
lr[0] = r ^ st[17]
|
|
391
399
|
lr[1] = l
|
|
@@ -395,6 +403,15 @@ const bcryptEncrypt = (st: u32[], lr: u32[]): void => {
|
|
|
395
403
|
* `BF_body`: encrypt the zero block, then each result in turn, writing the
|
|
396
404
|
* pairs over the whole state, P first and then the S-boxes. The hot loop:
|
|
397
405
|
* 2^(cost+1) calls of 521 blocks each.
|
|
406
|
+
*
|
|
407
|
+
* Each half-round is `x ^ P[n] ^ F(y)`, and only `F(y)` waits on the previous
|
|
408
|
+
* one, so `x ^ P[n]` belongs off the critical path with one XOR after the last
|
|
409
|
+
* S-box add. Written plainly, LLVM's Reassociate and InstCombine put `P[n]`
|
|
410
|
+
* after `F(y)` in 15 of 16 half-rounds, two dependent XORs instead of one
|
|
411
|
+
* (docs/security/crypto-bcrypt.md, "Speed"). `ctSelect` with an all-ones mask
|
|
412
|
+
* is `x ^ P[n]` itself, but behind the value barrier the mask is opaque, so the
|
|
413
|
+
* `and` it leaves cannot be reassociated into the XOR chain: the half-round
|
|
414
|
+
* keeps the order written, for one hoisted barrier and an `and` off the path.
|
|
398
415
|
*/
|
|
399
416
|
const bcryptBody = (st: u32[]): void => {
|
|
400
417
|
if (st.length < 1042) {
|
|
@@ -409,12 +426,14 @@ const bcryptBody = (st: u32[]): void => {
|
|
|
409
426
|
const lb: i32 = toI32(l >>> 16) & 0xff
|
|
410
427
|
const lc: i32 = toI32(l >>> 8) & 0xff
|
|
411
428
|
const ld: i32 = toI32(l) & 0xff
|
|
412
|
-
r
|
|
429
|
+
r = ctSelect(0xffffffff, r ^ st[n], 0) ^ (((st[18 + la] + st[274 + lb]) ^ st[530 + lc]) + st[786 + ld])
|
|
413
430
|
const ra: i32 = toI32(r >>> 24) & 0xff
|
|
414
431
|
const rb: i32 = toI32(r >>> 16) & 0xff
|
|
415
432
|
const rc: i32 = toI32(r >>> 8) & 0xff
|
|
416
433
|
const rd: i32 = toI32(r) & 0xff
|
|
417
|
-
l
|
|
434
|
+
l =
|
|
435
|
+
ctSelect(0xffffffff, l ^ st[n + 1], 0) ^
|
|
436
|
+
(((st[18 + ra] + st[274 + rb]) ^ st[530 + rc]) + st[786 + rd])
|
|
418
437
|
}
|
|
419
438
|
const t: u32 = r
|
|
420
439
|
r = l
|
|
@@ -876,44 +895,50 @@ const bcryptBytesOf = (given: u8[], hash: string): void => {
|
|
|
876
895
|
}
|
|
877
896
|
|
|
878
897
|
// ---------------------------------------------------------------------------
|
|
879
|
-
// The
|
|
880
|
-
//
|
|
881
|
-
//
|
|
882
|
-
//
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
-
//
|
|
898
|
+
// The batch, two to six lanes on one thread. Up to six independent hashes
|
|
899
|
+
// share one `Secret<u32[]>`: the lane in slot s has its Blowfish state at
|
|
900
|
+
// 1042s (0–6251), its expanded key at 6252 + 18s and its `$2a$` safety word at
|
|
901
|
+
// 6360 + s. The lanes a caller gives are packed into slots 0 to w - 1, so a
|
|
902
|
+
// batch of w passwords runs the w-lane kernel whatever positions they came in.
|
|
903
|
+
// One exposeWith per password XORs that lane's key in, and one more runs the
|
|
904
|
+
// expansion, the 2^cost rounds and the magic string. The cost rounds, all but
|
|
905
|
+
// 713 of a hash's 2^(cost+1) × 521 + 713 blocks, run on all w lanes at once
|
|
906
|
+
// with their encryption chains interleaved round by round, so the S-box loads
|
|
907
|
+
// of one lane overlap the others' and the core is not left waiting on one
|
|
908
|
+
// chain's latency; the expansion and the magic string run lane by lane.
|
|
886
909
|
// ---------------------------------------------------------------------------
|
|
887
910
|
|
|
888
|
-
/**
|
|
889
|
-
const
|
|
890
|
-
/** Where the
|
|
891
|
-
const
|
|
892
|
-
/**
|
|
893
|
-
const
|
|
911
|
+
/** The most lanes a batch runs. */
|
|
912
|
+
const BCRYPT_BATCH_LANES: i32 = 6
|
|
913
|
+
/** Where the six expanded keys of 18 start in the batch state, after the six Blowfish states. */
|
|
914
|
+
const BCRYPT_BATCH_KEYS: i32 = 6252
|
|
915
|
+
/** Where the six safety words start, after the keys. */
|
|
916
|
+
const BCRYPT_BATCH_SAFETY: i32 = 6360
|
|
917
|
+
/** Words in the batch state: six Blowfish states, six expanded keys of 18 and six safety words. */
|
|
918
|
+
const BCRYPT_BATCH_WORDS: i32 = 6366
|
|
894
919
|
|
|
895
920
|
/**
|
|
896
|
-
* What the batch kernel reads besides the state: each
|
|
897
|
-
* (
|
|
898
|
-
*
|
|
899
|
-
* verifying, each
|
|
921
|
+
* What the batch kernel reads besides the state, slot by slot: each slot's
|
|
922
|
+
* four salt words (slot s at 4s), each slot's `$2a$` safety word, the shared
|
|
923
|
+
* cost, the number of slots that run, each slot's 29-character setting and,
|
|
924
|
+
* for verifying, each slot's hash to compare with.
|
|
900
925
|
*/
|
|
901
926
|
interface BcryptBatch {
|
|
902
927
|
salts: u32[]
|
|
903
928
|
safety: u32[]
|
|
904
929
|
cost: i32
|
|
905
|
-
|
|
930
|
+
width: i32
|
|
906
931
|
prefixes: u8[][]
|
|
907
932
|
hashes: string[]
|
|
908
933
|
}
|
|
909
934
|
|
|
910
|
-
/** The
|
|
911
|
-
const
|
|
912
|
-
if (st.length <
|
|
935
|
+
/** The six states set to π and each slot's safety word stored, for `exposeWith` on the fresh batch state. */
|
|
936
|
+
const bcryptInitN = (st: u32[], batch: BcryptBatch): i32 => {
|
|
937
|
+
if (toI32(st.length) < BCRYPT_BATCH_WORDS) {
|
|
913
938
|
return 0
|
|
914
939
|
}
|
|
915
940
|
const safety: u32[] = batch.safety
|
|
916
|
-
for (let k: i32 = 0; k <
|
|
941
|
+
for (let k: i32 = 0; k < BCRYPT_BATCH_LANES; k++) {
|
|
917
942
|
bcryptInitState(st, k * BCRYPT_STATE_WORDS)
|
|
918
943
|
st[BCRYPT_BATCH_SAFETY + k] = k < toI32(safety.length) ? safety[k] : 0
|
|
919
944
|
}
|
|
@@ -936,21 +961,21 @@ const bcryptKeyWord = (password: u8[], arg: i32): u32 => {
|
|
|
936
961
|
}
|
|
937
962
|
|
|
938
963
|
/**
|
|
939
|
-
*
|
|
940
|
-
* XORs it, and the 18 words kept for the cost rounds. Each
|
|
941
|
-
* `exposeWith` on the password, since the state is what this
|
|
942
|
-
* exposing and a `Secret` cannot be handed into it otherwise.
|
|
964
|
+
* The key of the lane in slot `slot` into the batch state: P XORed with it
|
|
965
|
+
* as `bcryptSetKey` XORs it, and the 18 words kept for the cost rounds. Each
|
|
966
|
+
* word is one `exposeWith` on the password, since the state is what this
|
|
967
|
+
* function is exposing and a `Secret` cannot be handed into it otherwise.
|
|
943
968
|
*/
|
|
944
|
-
const bcryptLoadLane = (st: u32[], password: Secret<u8[]>,
|
|
945
|
-
if (st.length <
|
|
969
|
+
const bcryptLoadLane = (st: u32[], password: Secret<u8[]>, slot: i32): i32 => {
|
|
970
|
+
if (toI32(st.length) < BCRYPT_BATCH_WORDS) {
|
|
946
971
|
return 0
|
|
947
972
|
}
|
|
948
|
-
if (
|
|
973
|
+
if (slot < 0 || slot >= BCRYPT_BATCH_LANES) {
|
|
949
974
|
return 0
|
|
950
975
|
}
|
|
951
|
-
const at: i32 =
|
|
952
|
-
const kept: i32 =
|
|
953
|
-
const flag: i32 = st[BCRYPT_BATCH_SAFETY +
|
|
976
|
+
const at: i32 = slot * BCRYPT_STATE_WORDS
|
|
977
|
+
const kept: i32 = slot * 18 + BCRYPT_BATCH_KEYS
|
|
978
|
+
const flag: i32 = st[BCRYPT_BATCH_SAFETY + slot] !== 0 ? 32 : 0
|
|
954
979
|
for (let k: i32 = 0; k < 18; k++) {
|
|
955
980
|
const word: u32 = exposeWith(password, k | flag, bcryptKeyWord)
|
|
956
981
|
st[at + k] ^= word
|
|
@@ -960,18 +985,159 @@ const bcryptLoadLane = (st: u32[], password: Secret<u8[]>, lane: i32): i32 => {
|
|
|
960
985
|
return 0
|
|
961
986
|
}
|
|
962
987
|
|
|
963
|
-
/** `bcryptLoadLane` for
|
|
988
|
+
/** `bcryptLoadLane` for slot 0, in the shape `exposeWith` calls. */
|
|
964
989
|
const bcryptLoadLane0 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 0)
|
|
965
990
|
|
|
966
|
-
/** `bcryptLoadLane` for
|
|
991
|
+
/** `bcryptLoadLane` for slot 1. */
|
|
967
992
|
const bcryptLoadLane1 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 1)
|
|
968
993
|
|
|
969
|
-
/** `bcryptLoadLane` for
|
|
994
|
+
/** `bcryptLoadLane` for slot 2. */
|
|
970
995
|
const bcryptLoadLane2 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 2)
|
|
971
996
|
|
|
972
|
-
/** `bcryptLoadLane` for
|
|
997
|
+
/** `bcryptLoadLane` for slot 3. */
|
|
973
998
|
const bcryptLoadLane3 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 3)
|
|
974
999
|
|
|
1000
|
+
/** `bcryptLoadLane` for slot 4. */
|
|
1001
|
+
const bcryptLoadLane4 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 4)
|
|
1002
|
+
|
|
1003
|
+
/** `bcryptLoadLane` for slot 5. */
|
|
1004
|
+
const bcryptLoadLane5 = (st: u32[], password: Secret<u8[]>): i32 => bcryptLoadLane(st, password, 5)
|
|
1005
|
+
|
|
1006
|
+
/** `password` into slot `slot` of the batch `state`. */
|
|
1007
|
+
const bcryptLoadSlot = (state: Secret<u32[]>, password: Secret<u8[]>, slot: i32): void => {
|
|
1008
|
+
if (slot === 0) {
|
|
1009
|
+
exposeWith(state, password, bcryptLoadLane0)
|
|
1010
|
+
} else if (slot === 1) {
|
|
1011
|
+
exposeWith(state, password, bcryptLoadLane1)
|
|
1012
|
+
} else if (slot === 2) {
|
|
1013
|
+
exposeWith(state, password, bcryptLoadLane2)
|
|
1014
|
+
} else if (slot === 3) {
|
|
1015
|
+
exposeWith(state, password, bcryptLoadLane3)
|
|
1016
|
+
} else if (slot === 4) {
|
|
1017
|
+
exposeWith(state, password, bcryptLoadLane4)
|
|
1018
|
+
} else if (slot === 5) {
|
|
1019
|
+
exposeWith(state, password, bcryptLoadLane5)
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// The cost-round kernels, one per width. Each is `bcryptBody4`'s text with
|
|
1024
|
+
// the lane count changed (bench/crypto/bcrypt/gen-body.mjs writes them), not
|
|
1025
|
+
// one loop over a lane count: the lanes' l and r must live in registers and
|
|
1026
|
+
// their loads be scheduled together, which a loop over an array of lanes
|
|
1027
|
+
// does not give.
|
|
1028
|
+
|
|
1029
|
+
/** `bcryptBody4`'s interleave on two lanes. */
|
|
1030
|
+
const bcryptBody2 = (st: u32[]): void => {
|
|
1031
|
+
if (st.length < 2084) {
|
|
1032
|
+
return
|
|
1033
|
+
}
|
|
1034
|
+
let l0: u32 = 0
|
|
1035
|
+
let r0: u32 = 0
|
|
1036
|
+
let l1: u32 = 0
|
|
1037
|
+
let r1: u32 = 0
|
|
1038
|
+
for (let i: i32 = 0; i + 1 < 1042; i += 2) {
|
|
1039
|
+
l0 ^= st[0]
|
|
1040
|
+
l1 ^= st[1042]
|
|
1041
|
+
for (let n: i32 = 1; n < 17; n += 2) {
|
|
1042
|
+
const l0a: i32 = toI32(l0 >>> 24) & 0xff
|
|
1043
|
+
const l0b: i32 = toI32(l0 >>> 16) & 0xff
|
|
1044
|
+
const l0c: i32 = toI32(l0 >>> 8) & 0xff
|
|
1045
|
+
const l0d: i32 = toI32(l0) & 0xff
|
|
1046
|
+
const l1a: i32 = toI32(l1 >>> 24) & 0xff
|
|
1047
|
+
const l1b: i32 = toI32(l1 >>> 16) & 0xff
|
|
1048
|
+
const l1c: i32 = toI32(l1 >>> 8) & 0xff
|
|
1049
|
+
const l1d: i32 = toI32(l1) & 0xff
|
|
1050
|
+
r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
|
|
1051
|
+
r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
|
|
1052
|
+
const r0a: i32 = toI32(r0 >>> 24) & 0xff
|
|
1053
|
+
const r0b: i32 = toI32(r0 >>> 16) & 0xff
|
|
1054
|
+
const r0c: i32 = toI32(r0 >>> 8) & 0xff
|
|
1055
|
+
const r0d: i32 = toI32(r0) & 0xff
|
|
1056
|
+
const r1a: i32 = toI32(r1 >>> 24) & 0xff
|
|
1057
|
+
const r1b: i32 = toI32(r1 >>> 16) & 0xff
|
|
1058
|
+
const r1c: i32 = toI32(r1 >>> 8) & 0xff
|
|
1059
|
+
const r1d: i32 = toI32(r1) & 0xff
|
|
1060
|
+
l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
|
|
1061
|
+
l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
|
|
1062
|
+
}
|
|
1063
|
+
const t0: u32 = r0
|
|
1064
|
+
r0 = l0
|
|
1065
|
+
l0 = t0 ^ st[17]
|
|
1066
|
+
st[i] = l0
|
|
1067
|
+
st[i + 1] = r0
|
|
1068
|
+
const t1: u32 = r1
|
|
1069
|
+
r1 = l1
|
|
1070
|
+
l1 = t1 ^ st[1059]
|
|
1071
|
+
st[1042 + i] = l1
|
|
1072
|
+
st[1042 + i + 1] = r1
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/** `bcryptBody4`'s interleave on three lanes. */
|
|
1077
|
+
const bcryptBody3 = (st: u32[]): void => {
|
|
1078
|
+
if (st.length < 3126) {
|
|
1079
|
+
return
|
|
1080
|
+
}
|
|
1081
|
+
let l0: u32 = 0
|
|
1082
|
+
let r0: u32 = 0
|
|
1083
|
+
let l1: u32 = 0
|
|
1084
|
+
let r1: u32 = 0
|
|
1085
|
+
let l2: u32 = 0
|
|
1086
|
+
let r2: u32 = 0
|
|
1087
|
+
for (let i: i32 = 0; i + 1 < 1042; i += 2) {
|
|
1088
|
+
l0 ^= st[0]
|
|
1089
|
+
l1 ^= st[1042]
|
|
1090
|
+
l2 ^= st[2084]
|
|
1091
|
+
for (let n: i32 = 1; n < 17; n += 2) {
|
|
1092
|
+
const l0a: i32 = toI32(l0 >>> 24) & 0xff
|
|
1093
|
+
const l0b: i32 = toI32(l0 >>> 16) & 0xff
|
|
1094
|
+
const l0c: i32 = toI32(l0 >>> 8) & 0xff
|
|
1095
|
+
const l0d: i32 = toI32(l0) & 0xff
|
|
1096
|
+
const l1a: i32 = toI32(l1 >>> 24) & 0xff
|
|
1097
|
+
const l1b: i32 = toI32(l1 >>> 16) & 0xff
|
|
1098
|
+
const l1c: i32 = toI32(l1 >>> 8) & 0xff
|
|
1099
|
+
const l1d: i32 = toI32(l1) & 0xff
|
|
1100
|
+
const l2a: i32 = toI32(l2 >>> 24) & 0xff
|
|
1101
|
+
const l2b: i32 = toI32(l2 >>> 16) & 0xff
|
|
1102
|
+
const l2c: i32 = toI32(l2 >>> 8) & 0xff
|
|
1103
|
+
const l2d: i32 = toI32(l2) & 0xff
|
|
1104
|
+
r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
|
|
1105
|
+
r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
|
|
1106
|
+
r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
|
|
1107
|
+
const r0a: i32 = toI32(r0 >>> 24) & 0xff
|
|
1108
|
+
const r0b: i32 = toI32(r0 >>> 16) & 0xff
|
|
1109
|
+
const r0c: i32 = toI32(r0 >>> 8) & 0xff
|
|
1110
|
+
const r0d: i32 = toI32(r0) & 0xff
|
|
1111
|
+
const r1a: i32 = toI32(r1 >>> 24) & 0xff
|
|
1112
|
+
const r1b: i32 = toI32(r1 >>> 16) & 0xff
|
|
1113
|
+
const r1c: i32 = toI32(r1 >>> 8) & 0xff
|
|
1114
|
+
const r1d: i32 = toI32(r1) & 0xff
|
|
1115
|
+
const r2a: i32 = toI32(r2 >>> 24) & 0xff
|
|
1116
|
+
const r2b: i32 = toI32(r2 >>> 16) & 0xff
|
|
1117
|
+
const r2c: i32 = toI32(r2 >>> 8) & 0xff
|
|
1118
|
+
const r2d: i32 = toI32(r2) & 0xff
|
|
1119
|
+
l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
|
|
1120
|
+
l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
|
|
1121
|
+
l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
|
|
1122
|
+
}
|
|
1123
|
+
const t0: u32 = r0
|
|
1124
|
+
r0 = l0
|
|
1125
|
+
l0 = t0 ^ st[17]
|
|
1126
|
+
st[i] = l0
|
|
1127
|
+
st[i + 1] = r0
|
|
1128
|
+
const t1: u32 = r1
|
|
1129
|
+
r1 = l1
|
|
1130
|
+
l1 = t1 ^ st[1059]
|
|
1131
|
+
st[1042 + i] = l1
|
|
1132
|
+
st[1042 + i + 1] = r1
|
|
1133
|
+
const t2: u32 = r2
|
|
1134
|
+
r2 = l2
|
|
1135
|
+
l2 = t2 ^ st[2101]
|
|
1136
|
+
st[2084 + i] = l2
|
|
1137
|
+
st[2084 + i + 1] = r2
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
975
1141
|
/**
|
|
976
1142
|
* `bcryptBody` on all four lanes at once: each lane's state re-encrypted in
|
|
977
1143
|
* place, the four encryption chains interleaved round by round so that one
|
|
@@ -1060,93 +1226,287 @@ const bcryptBody4 = (st: u32[]): void => {
|
|
|
1060
1226
|
}
|
|
1061
1227
|
}
|
|
1062
1228
|
|
|
1063
|
-
/** `
|
|
1064
|
-
const
|
|
1065
|
-
if (st.length <
|
|
1229
|
+
/** `bcryptBody4`'s interleave on five lanes. */
|
|
1230
|
+
const bcryptBody5 = (st: u32[]): void => {
|
|
1231
|
+
if (st.length < 5210) {
|
|
1232
|
+
return
|
|
1233
|
+
}
|
|
1234
|
+
let l0: u32 = 0
|
|
1235
|
+
let r0: u32 = 0
|
|
1236
|
+
let l1: u32 = 0
|
|
1237
|
+
let r1: u32 = 0
|
|
1238
|
+
let l2: u32 = 0
|
|
1239
|
+
let r2: u32 = 0
|
|
1240
|
+
let l3: u32 = 0
|
|
1241
|
+
let r3: u32 = 0
|
|
1242
|
+
let l4: u32 = 0
|
|
1243
|
+
let r4: u32 = 0
|
|
1244
|
+
for (let i: i32 = 0; i + 1 < 1042; i += 2) {
|
|
1245
|
+
l0 ^= st[0]
|
|
1246
|
+
l1 ^= st[1042]
|
|
1247
|
+
l2 ^= st[2084]
|
|
1248
|
+
l3 ^= st[3126]
|
|
1249
|
+
l4 ^= st[4168]
|
|
1250
|
+
for (let n: i32 = 1; n < 17; n += 2) {
|
|
1251
|
+
const l0a: i32 = toI32(l0 >>> 24) & 0xff
|
|
1252
|
+
const l0b: i32 = toI32(l0 >>> 16) & 0xff
|
|
1253
|
+
const l0c: i32 = toI32(l0 >>> 8) & 0xff
|
|
1254
|
+
const l0d: i32 = toI32(l0) & 0xff
|
|
1255
|
+
const l1a: i32 = toI32(l1 >>> 24) & 0xff
|
|
1256
|
+
const l1b: i32 = toI32(l1 >>> 16) & 0xff
|
|
1257
|
+
const l1c: i32 = toI32(l1 >>> 8) & 0xff
|
|
1258
|
+
const l1d: i32 = toI32(l1) & 0xff
|
|
1259
|
+
const l2a: i32 = toI32(l2 >>> 24) & 0xff
|
|
1260
|
+
const l2b: i32 = toI32(l2 >>> 16) & 0xff
|
|
1261
|
+
const l2c: i32 = toI32(l2 >>> 8) & 0xff
|
|
1262
|
+
const l2d: i32 = toI32(l2) & 0xff
|
|
1263
|
+
const l3a: i32 = toI32(l3 >>> 24) & 0xff
|
|
1264
|
+
const l3b: i32 = toI32(l3 >>> 16) & 0xff
|
|
1265
|
+
const l3c: i32 = toI32(l3 >>> 8) & 0xff
|
|
1266
|
+
const l3d: i32 = toI32(l3) & 0xff
|
|
1267
|
+
const l4a: i32 = toI32(l4 >>> 24) & 0xff
|
|
1268
|
+
const l4b: i32 = toI32(l4 >>> 16) & 0xff
|
|
1269
|
+
const l4c: i32 = toI32(l4 >>> 8) & 0xff
|
|
1270
|
+
const l4d: i32 = toI32(l4) & 0xff
|
|
1271
|
+
r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
|
|
1272
|
+
r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
|
|
1273
|
+
r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
|
|
1274
|
+
r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
|
|
1275
|
+
r4 ^= st[4168 + n] ^ (((st[4186 + l4a] + st[4442 + l4b]) ^ st[4698 + l4c]) + st[4954 + l4d])
|
|
1276
|
+
const r0a: i32 = toI32(r0 >>> 24) & 0xff
|
|
1277
|
+
const r0b: i32 = toI32(r0 >>> 16) & 0xff
|
|
1278
|
+
const r0c: i32 = toI32(r0 >>> 8) & 0xff
|
|
1279
|
+
const r0d: i32 = toI32(r0) & 0xff
|
|
1280
|
+
const r1a: i32 = toI32(r1 >>> 24) & 0xff
|
|
1281
|
+
const r1b: i32 = toI32(r1 >>> 16) & 0xff
|
|
1282
|
+
const r1c: i32 = toI32(r1 >>> 8) & 0xff
|
|
1283
|
+
const r1d: i32 = toI32(r1) & 0xff
|
|
1284
|
+
const r2a: i32 = toI32(r2 >>> 24) & 0xff
|
|
1285
|
+
const r2b: i32 = toI32(r2 >>> 16) & 0xff
|
|
1286
|
+
const r2c: i32 = toI32(r2 >>> 8) & 0xff
|
|
1287
|
+
const r2d: i32 = toI32(r2) & 0xff
|
|
1288
|
+
const r3a: i32 = toI32(r3 >>> 24) & 0xff
|
|
1289
|
+
const r3b: i32 = toI32(r3 >>> 16) & 0xff
|
|
1290
|
+
const r3c: i32 = toI32(r3 >>> 8) & 0xff
|
|
1291
|
+
const r3d: i32 = toI32(r3) & 0xff
|
|
1292
|
+
const r4a: i32 = toI32(r4 >>> 24) & 0xff
|
|
1293
|
+
const r4b: i32 = toI32(r4 >>> 16) & 0xff
|
|
1294
|
+
const r4c: i32 = toI32(r4 >>> 8) & 0xff
|
|
1295
|
+
const r4d: i32 = toI32(r4) & 0xff
|
|
1296
|
+
l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
|
|
1297
|
+
l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
|
|
1298
|
+
l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
|
|
1299
|
+
l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
|
|
1300
|
+
l4 ^= st[4168 + n + 1] ^ (((st[4186 + r4a] + st[4442 + r4b]) ^ st[4698 + r4c]) + st[4954 + r4d])
|
|
1301
|
+
}
|
|
1302
|
+
const t0: u32 = r0
|
|
1303
|
+
r0 = l0
|
|
1304
|
+
l0 = t0 ^ st[17]
|
|
1305
|
+
st[i] = l0
|
|
1306
|
+
st[i + 1] = r0
|
|
1307
|
+
const t1: u32 = r1
|
|
1308
|
+
r1 = l1
|
|
1309
|
+
l1 = t1 ^ st[1059]
|
|
1310
|
+
st[1042 + i] = l1
|
|
1311
|
+
st[1042 + i + 1] = r1
|
|
1312
|
+
const t2: u32 = r2
|
|
1313
|
+
r2 = l2
|
|
1314
|
+
l2 = t2 ^ st[2101]
|
|
1315
|
+
st[2084 + i] = l2
|
|
1316
|
+
st[2084 + i + 1] = r2
|
|
1317
|
+
const t3: u32 = r3
|
|
1318
|
+
r3 = l3
|
|
1319
|
+
l3 = t3 ^ st[3143]
|
|
1320
|
+
st[3126 + i] = l3
|
|
1321
|
+
st[3126 + i + 1] = r3
|
|
1322
|
+
const t4: u32 = r4
|
|
1323
|
+
r4 = l4
|
|
1324
|
+
l4 = t4 ^ st[4185]
|
|
1325
|
+
st[4168 + i] = l4
|
|
1326
|
+
st[4168 + i + 1] = r4
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
/** `bcryptBody4`'s interleave on six lanes. */
|
|
1331
|
+
const bcryptBody6 = (st: u32[]): void => {
|
|
1332
|
+
if (st.length < 6252) {
|
|
1333
|
+
return
|
|
1334
|
+
}
|
|
1335
|
+
let l0: u32 = 0
|
|
1336
|
+
let r0: u32 = 0
|
|
1337
|
+
let l1: u32 = 0
|
|
1338
|
+
let r1: u32 = 0
|
|
1339
|
+
let l2: u32 = 0
|
|
1340
|
+
let r2: u32 = 0
|
|
1341
|
+
let l3: u32 = 0
|
|
1342
|
+
let r3: u32 = 0
|
|
1343
|
+
let l4: u32 = 0
|
|
1344
|
+
let r4: u32 = 0
|
|
1345
|
+
let l5: u32 = 0
|
|
1346
|
+
let r5: u32 = 0
|
|
1347
|
+
for (let i: i32 = 0; i + 1 < 1042; i += 2) {
|
|
1348
|
+
l0 ^= st[0]
|
|
1349
|
+
l1 ^= st[1042]
|
|
1350
|
+
l2 ^= st[2084]
|
|
1351
|
+
l3 ^= st[3126]
|
|
1352
|
+
l4 ^= st[4168]
|
|
1353
|
+
l5 ^= st[5210]
|
|
1354
|
+
for (let n: i32 = 1; n < 17; n += 2) {
|
|
1355
|
+
const l0a: i32 = toI32(l0 >>> 24) & 0xff
|
|
1356
|
+
const l0b: i32 = toI32(l0 >>> 16) & 0xff
|
|
1357
|
+
const l0c: i32 = toI32(l0 >>> 8) & 0xff
|
|
1358
|
+
const l0d: i32 = toI32(l0) & 0xff
|
|
1359
|
+
const l1a: i32 = toI32(l1 >>> 24) & 0xff
|
|
1360
|
+
const l1b: i32 = toI32(l1 >>> 16) & 0xff
|
|
1361
|
+
const l1c: i32 = toI32(l1 >>> 8) & 0xff
|
|
1362
|
+
const l1d: i32 = toI32(l1) & 0xff
|
|
1363
|
+
const l2a: i32 = toI32(l2 >>> 24) & 0xff
|
|
1364
|
+
const l2b: i32 = toI32(l2 >>> 16) & 0xff
|
|
1365
|
+
const l2c: i32 = toI32(l2 >>> 8) & 0xff
|
|
1366
|
+
const l2d: i32 = toI32(l2) & 0xff
|
|
1367
|
+
const l3a: i32 = toI32(l3 >>> 24) & 0xff
|
|
1368
|
+
const l3b: i32 = toI32(l3 >>> 16) & 0xff
|
|
1369
|
+
const l3c: i32 = toI32(l3 >>> 8) & 0xff
|
|
1370
|
+
const l3d: i32 = toI32(l3) & 0xff
|
|
1371
|
+
const l4a: i32 = toI32(l4 >>> 24) & 0xff
|
|
1372
|
+
const l4b: i32 = toI32(l4 >>> 16) & 0xff
|
|
1373
|
+
const l4c: i32 = toI32(l4 >>> 8) & 0xff
|
|
1374
|
+
const l4d: i32 = toI32(l4) & 0xff
|
|
1375
|
+
const l5a: i32 = toI32(l5 >>> 24) & 0xff
|
|
1376
|
+
const l5b: i32 = toI32(l5 >>> 16) & 0xff
|
|
1377
|
+
const l5c: i32 = toI32(l5 >>> 8) & 0xff
|
|
1378
|
+
const l5d: i32 = toI32(l5) & 0xff
|
|
1379
|
+
r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
|
|
1380
|
+
r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
|
|
1381
|
+
r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
|
|
1382
|
+
r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
|
|
1383
|
+
r4 ^= st[4168 + n] ^ (((st[4186 + l4a] + st[4442 + l4b]) ^ st[4698 + l4c]) + st[4954 + l4d])
|
|
1384
|
+
r5 ^= st[5210 + n] ^ (((st[5228 + l5a] + st[5484 + l5b]) ^ st[5740 + l5c]) + st[5996 + l5d])
|
|
1385
|
+
const r0a: i32 = toI32(r0 >>> 24) & 0xff
|
|
1386
|
+
const r0b: i32 = toI32(r0 >>> 16) & 0xff
|
|
1387
|
+
const r0c: i32 = toI32(r0 >>> 8) & 0xff
|
|
1388
|
+
const r0d: i32 = toI32(r0) & 0xff
|
|
1389
|
+
const r1a: i32 = toI32(r1 >>> 24) & 0xff
|
|
1390
|
+
const r1b: i32 = toI32(r1 >>> 16) & 0xff
|
|
1391
|
+
const r1c: i32 = toI32(r1 >>> 8) & 0xff
|
|
1392
|
+
const r1d: i32 = toI32(r1) & 0xff
|
|
1393
|
+
const r2a: i32 = toI32(r2 >>> 24) & 0xff
|
|
1394
|
+
const r2b: i32 = toI32(r2 >>> 16) & 0xff
|
|
1395
|
+
const r2c: i32 = toI32(r2 >>> 8) & 0xff
|
|
1396
|
+
const r2d: i32 = toI32(r2) & 0xff
|
|
1397
|
+
const r3a: i32 = toI32(r3 >>> 24) & 0xff
|
|
1398
|
+
const r3b: i32 = toI32(r3 >>> 16) & 0xff
|
|
1399
|
+
const r3c: i32 = toI32(r3 >>> 8) & 0xff
|
|
1400
|
+
const r3d: i32 = toI32(r3) & 0xff
|
|
1401
|
+
const r4a: i32 = toI32(r4 >>> 24) & 0xff
|
|
1402
|
+
const r4b: i32 = toI32(r4 >>> 16) & 0xff
|
|
1403
|
+
const r4c: i32 = toI32(r4 >>> 8) & 0xff
|
|
1404
|
+
const r4d: i32 = toI32(r4) & 0xff
|
|
1405
|
+
const r5a: i32 = toI32(r5 >>> 24) & 0xff
|
|
1406
|
+
const r5b: i32 = toI32(r5 >>> 16) & 0xff
|
|
1407
|
+
const r5c: i32 = toI32(r5 >>> 8) & 0xff
|
|
1408
|
+
const r5d: i32 = toI32(r5) & 0xff
|
|
1409
|
+
l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
|
|
1410
|
+
l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
|
|
1411
|
+
l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
|
|
1412
|
+
l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
|
|
1413
|
+
l4 ^= st[4168 + n + 1] ^ (((st[4186 + r4a] + st[4442 + r4b]) ^ st[4698 + r4c]) + st[4954 + r4d])
|
|
1414
|
+
l5 ^= st[5210 + n + 1] ^ (((st[5228 + r5a] + st[5484 + r5b]) ^ st[5740 + r5c]) + st[5996 + r5d])
|
|
1415
|
+
}
|
|
1416
|
+
const t0: u32 = r0
|
|
1417
|
+
r0 = l0
|
|
1418
|
+
l0 = t0 ^ st[17]
|
|
1419
|
+
st[i] = l0
|
|
1420
|
+
st[i + 1] = r0
|
|
1421
|
+
const t1: u32 = r1
|
|
1422
|
+
r1 = l1
|
|
1423
|
+
l1 = t1 ^ st[1059]
|
|
1424
|
+
st[1042 + i] = l1
|
|
1425
|
+
st[1042 + i + 1] = r1
|
|
1426
|
+
const t2: u32 = r2
|
|
1427
|
+
r2 = l2
|
|
1428
|
+
l2 = t2 ^ st[2101]
|
|
1429
|
+
st[2084 + i] = l2
|
|
1430
|
+
st[2084 + i + 1] = r2
|
|
1431
|
+
const t3: u32 = r3
|
|
1432
|
+
r3 = l3
|
|
1433
|
+
l3 = t3 ^ st[3143]
|
|
1434
|
+
st[3126 + i] = l3
|
|
1435
|
+
st[3126 + i + 1] = r3
|
|
1436
|
+
const t4: u32 = r4
|
|
1437
|
+
r4 = l4
|
|
1438
|
+
l4 = t4 ^ st[4185]
|
|
1439
|
+
st[4168 + i] = l4
|
|
1440
|
+
st[4168 + i + 1] = r4
|
|
1441
|
+
const t5: u32 = r5
|
|
1442
|
+
r5 = l5
|
|
1443
|
+
l5 = t5 ^ st[5227]
|
|
1444
|
+
st[5210 + i] = l5
|
|
1445
|
+
st[5210 + i + 1] = r5
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
/** The cost-round kernel for `width` lanes, slots 0 to `width` - 1. */
|
|
1450
|
+
const bcryptBodyN = (st: u32[], width: i32): void => {
|
|
1451
|
+
if (width === 2) {
|
|
1452
|
+
bcryptBody2(st)
|
|
1453
|
+
} else if (width === 3) {
|
|
1454
|
+
bcryptBody3(st)
|
|
1455
|
+
} else if (width === 4) {
|
|
1456
|
+
bcryptBody4(st)
|
|
1457
|
+
} else if (width === 5) {
|
|
1458
|
+
bcryptBody5(st)
|
|
1459
|
+
} else if (width === 6) {
|
|
1460
|
+
bcryptBody6(st)
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/** `bcryptEncrypt` under the state at `at`: one block, `lr[0]` and `lr[1]` in place. */
|
|
1465
|
+
const bcryptEncryptAt = (st: u32[], at: i32, lr: u32[]): void => {
|
|
1466
|
+
if (at < 0 || at + BCRYPT_STATE_WORDS > toI32(st.length)) {
|
|
1066
1467
|
return
|
|
1067
1468
|
}
|
|
1068
|
-
if (lr.length <
|
|
1469
|
+
if (lr.length < 2) {
|
|
1069
1470
|
return
|
|
1070
1471
|
}
|
|
1071
|
-
let
|
|
1072
|
-
let
|
|
1073
|
-
let l1: u32 = lr[2] ^ st[1042]
|
|
1074
|
-
let r1: u32 = lr[3]
|
|
1075
|
-
let l2: u32 = lr[4] ^ st[2084]
|
|
1076
|
-
let r2: u32 = lr[5]
|
|
1077
|
-
let l3: u32 = lr[6] ^ st[3126]
|
|
1078
|
-
let r3: u32 = lr[7]
|
|
1472
|
+
let l: u32 = lr[0] ^ st[at]
|
|
1473
|
+
let r: u32 = lr[1]
|
|
1079
1474
|
for (let n: i32 = 1; n < 17; n += 2) {
|
|
1080
|
-
const
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
const
|
|
1086
|
-
const
|
|
1087
|
-
const
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
|
|
1099
|
-
r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
|
|
1100
|
-
const r0a: i32 = toI32(r0 >>> 24) & 0xff
|
|
1101
|
-
const r0b: i32 = toI32(r0 >>> 16) & 0xff
|
|
1102
|
-
const r0c: i32 = toI32(r0 >>> 8) & 0xff
|
|
1103
|
-
const r0d: i32 = toI32(r0) & 0xff
|
|
1104
|
-
const r1a: i32 = toI32(r1 >>> 24) & 0xff
|
|
1105
|
-
const r1b: i32 = toI32(r1 >>> 16) & 0xff
|
|
1106
|
-
const r1c: i32 = toI32(r1 >>> 8) & 0xff
|
|
1107
|
-
const r1d: i32 = toI32(r1) & 0xff
|
|
1108
|
-
const r2a: i32 = toI32(r2 >>> 24) & 0xff
|
|
1109
|
-
const r2b: i32 = toI32(r2 >>> 16) & 0xff
|
|
1110
|
-
const r2c: i32 = toI32(r2 >>> 8) & 0xff
|
|
1111
|
-
const r2d: i32 = toI32(r2) & 0xff
|
|
1112
|
-
const r3a: i32 = toI32(r3 >>> 24) & 0xff
|
|
1113
|
-
const r3b: i32 = toI32(r3 >>> 16) & 0xff
|
|
1114
|
-
const r3c: i32 = toI32(r3 >>> 8) & 0xff
|
|
1115
|
-
const r3d: i32 = toI32(r3) & 0xff
|
|
1116
|
-
l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
|
|
1117
|
-
l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
|
|
1118
|
-
l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
|
|
1119
|
-
l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
|
|
1120
|
-
}
|
|
1121
|
-
lr[0] = r0 ^ st[17]
|
|
1122
|
-
lr[1] = l0
|
|
1123
|
-
lr[2] = r1 ^ st[1059]
|
|
1124
|
-
lr[3] = l1
|
|
1125
|
-
lr[4] = r2 ^ st[2101]
|
|
1126
|
-
lr[5] = l2
|
|
1127
|
-
lr[6] = r3 ^ st[3143]
|
|
1128
|
-
lr[7] = l3
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
/** Each lane's P XORed with its kept expanded key, as `bcryptXorKey`. */
|
|
1132
|
-
const bcryptXorKey4 = (st: u32[]): void => {
|
|
1133
|
-
if (st.length < 4244) {
|
|
1475
|
+
const la: i32 = toI32(l >>> 24) & 0xff
|
|
1476
|
+
const lb: i32 = toI32(l >>> 16) & 0xff
|
|
1477
|
+
const lc: i32 = toI32(l >>> 8) & 0xff
|
|
1478
|
+
const ld: i32 = toI32(l) & 0xff
|
|
1479
|
+
r ^= st[at + n] ^ (((st[at + 18 + la] + st[at + 274 + lb]) ^ st[at + 530 + lc]) + st[at + 786 + ld])
|
|
1480
|
+
const ra: i32 = toI32(r >>> 24) & 0xff
|
|
1481
|
+
const rb: i32 = toI32(r >>> 16) & 0xff
|
|
1482
|
+
const rc: i32 = toI32(r >>> 8) & 0xff
|
|
1483
|
+
const rd: i32 = toI32(r) & 0xff
|
|
1484
|
+
l ^= st[at + n + 1] ^ (((st[at + 18 + ra] + st[at + 274 + rb]) ^ st[at + 530 + rc]) + st[at + 786 + rd])
|
|
1485
|
+
}
|
|
1486
|
+
lr[0] = r ^ st[at + 17]
|
|
1487
|
+
lr[1] = l
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
/** Each running slot's P XORed with its kept expanded key, as `bcryptXorKey`. */
|
|
1491
|
+
const bcryptXorKeyN = (st: u32[], width: i32): void => {
|
|
1492
|
+
if (toI32(st.length) < BCRYPT_BATCH_WORDS) {
|
|
1134
1493
|
return
|
|
1135
1494
|
}
|
|
1136
|
-
for (let
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1495
|
+
for (let k: i32 = 0; k < width && k < BCRYPT_BATCH_LANES; k++) {
|
|
1496
|
+
const at: i32 = k * BCRYPT_STATE_WORDS
|
|
1497
|
+
const kept: i32 = k * 18 + BCRYPT_BATCH_KEYS
|
|
1498
|
+
for (let i: i32 = 0; i < 18; i++) {
|
|
1499
|
+
st[at + i] ^= st[kept + i]
|
|
1500
|
+
}
|
|
1141
1501
|
}
|
|
1142
1502
|
}
|
|
1143
1503
|
|
|
1144
|
-
/** Each
|
|
1145
|
-
const
|
|
1146
|
-
if (salts.length <
|
|
1504
|
+
/** Each running slot's P XORed with its salt words, as `bcryptXorSalt`. */
|
|
1505
|
+
const bcryptXorSaltN = (st: u32[], salts: u32[], width: i32): void => {
|
|
1506
|
+
if (salts.length < 24) {
|
|
1147
1507
|
return
|
|
1148
1508
|
}
|
|
1149
|
-
for (let k: i32 = 0; k <
|
|
1509
|
+
for (let k: i32 = 0; k < width && k < BCRYPT_BATCH_LANES; k++) {
|
|
1150
1510
|
bcryptXorSalt(
|
|
1151
1511
|
st,
|
|
1152
1512
|
k * BCRYPT_STATE_WORDS,
|
|
@@ -1159,87 +1519,109 @@ const bcryptXorSalt4 = (st: u32[], salts: u32[]): void => {
|
|
|
1159
1519
|
}
|
|
1160
1520
|
|
|
1161
1521
|
/**
|
|
1162
|
-
* The
|
|
1163
|
-
*
|
|
1164
|
-
*
|
|
1165
|
-
* wipes. The block and digest copies are wiped here.
|
|
1522
|
+
* The salted expansion of the state at `at`, `BF_crypt`'s first pass: each
|
|
1523
|
+
* block XORed with the salt words `salts[4k..]` in turn, encrypted, and
|
|
1524
|
+
* written over P and the S-boxes.
|
|
1166
1525
|
*/
|
|
1167
|
-
const
|
|
1168
|
-
if (
|
|
1526
|
+
const bcryptExpandAt = (st: u32[], at: i32, salts: u32[], k: i32, lr: u32[]): void => {
|
|
1527
|
+
if (lr.length < 2 || 4 * k + 3 >= toI32(salts.length)) {
|
|
1169
1528
|
return
|
|
1170
1529
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1530
|
+
lr[0] = 0
|
|
1531
|
+
lr[1] = 0
|
|
1532
|
+
for (let i: i32 = 0; i < BCRYPT_STATE_WORDS; i += 2) {
|
|
1173
1533
|
const half: i32 = (i & 2) !== 0 ? 2 : 0
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
const at: i32 = k * 1042 + i
|
|
1181
|
-
if (at + 1 < toI32(st.length)) {
|
|
1182
|
-
st[at] = lr[2 * k]
|
|
1183
|
-
st[at + 1] = lr[2 * k + 1]
|
|
1184
|
-
}
|
|
1534
|
+
lr[0] ^= salts[4 * k + half]
|
|
1535
|
+
lr[1] ^= salts[4 * k + half + 1]
|
|
1536
|
+
bcryptEncryptAt(st, at, lr)
|
|
1537
|
+
if (at + i + 1 < toI32(st.length)) {
|
|
1538
|
+
st[at + i] = lr[0]
|
|
1539
|
+
st[at + i + 1] = lr[1]
|
|
1185
1540
|
}
|
|
1186
1541
|
}
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
/** `bcryptMagic` under the state at `at`: one pair of the magic string, into `dst` at `to`. */
|
|
1545
|
+
const bcryptMagicAt = (st: u32[], at: i32, lr: u32[], dst: u8[], to: i32, l: u32, r: u32): void => {
|
|
1546
|
+
if (lr.length < 2) {
|
|
1547
|
+
return
|
|
1548
|
+
}
|
|
1549
|
+
lr[0] = l
|
|
1550
|
+
lr[1] = r
|
|
1551
|
+
for (let n: i32 = 0; n < 64; n++) {
|
|
1552
|
+
bcryptEncryptAt(st, at, lr)
|
|
1553
|
+
}
|
|
1554
|
+
bcryptPutBlock(dst, to, lr[0], lr[1])
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* The batch's hash, on the batch state with its keys loaded: the salted
|
|
1559
|
+
* expansion, 2^cost rounds and the magic string on slots 0 to `width` - 1,
|
|
1560
|
+
* and the 31 digest characters of slot k into `digests` at 31k, which the
|
|
1561
|
+
* caller made and wipes. The block and digest copies are wiped here.
|
|
1562
|
+
*/
|
|
1563
|
+
const bcryptEksN = (st: u32[], salts: u32[], cost: i32, width: i32, digests: u8[]): void => {
|
|
1564
|
+
if (toI32(st.length) < BCRYPT_BATCH_WORDS || salts.length < 24 || width < 2 || width > BCRYPT_BATCH_LANES) {
|
|
1565
|
+
return
|
|
1566
|
+
}
|
|
1567
|
+
const lr: u32[] = new Array<u32>(2)
|
|
1568
|
+
for (let k: i32 = 0; k < width; k++) {
|
|
1569
|
+
bcryptExpandAt(st, k * BCRYPT_STATE_WORDS, salts, k, lr)
|
|
1570
|
+
}
|
|
1187
1571
|
|
|
1188
1572
|
let rounds: u32 = toU32(1) << toU32(cost)
|
|
1189
1573
|
while (rounds !== 0) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1574
|
+
bcryptXorKeyN(st, width)
|
|
1575
|
+
bcryptBodyN(st, width)
|
|
1576
|
+
bcryptXorSaltN(st, salts, width)
|
|
1577
|
+
bcryptBodyN(st, width)
|
|
1194
1578
|
rounds -= 1
|
|
1195
1579
|
}
|
|
1196
1580
|
|
|
1197
|
-
const digest: u8[] = new Array<u8>(
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
one[j] = digest[24 * k + j]
|
|
1205
|
-
}
|
|
1206
|
-
bcryptEncodeInto(digests, 31 * k, one, 23)
|
|
1581
|
+
const digest: u8[] = new Array<u8>(24)
|
|
1582
|
+
for (let k: i32 = 0; k < width; k++) {
|
|
1583
|
+
const at: i32 = k * BCRYPT_STATE_WORDS
|
|
1584
|
+
bcryptMagicAt(st, at, lr, digest, 0, 0x4f727068, 0x65616e42)
|
|
1585
|
+
bcryptMagicAt(st, at, lr, digest, 8, 0x65686f6c, 0x64657253)
|
|
1586
|
+
bcryptMagicAt(st, at, lr, digest, 16, 0x63727944, 0x6f756274)
|
|
1587
|
+
bcryptEncodeInto(digests, 31 * k, digest, 23)
|
|
1207
1588
|
}
|
|
1208
1589
|
wipe(lr)
|
|
1209
1590
|
wipe(digest)
|
|
1210
|
-
wipe(one)
|
|
1211
1591
|
}
|
|
1212
1592
|
|
|
1213
1593
|
/**
|
|
1214
|
-
* The
|
|
1215
|
-
* loaded batch state
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1594
|
+
* The running slots' 60-byte hashes, slot k at 60k, for `exposeWith` on the
|
|
1595
|
+
* loaded batch state. They are the hashes `bcryptHashN` returns, so they are
|
|
1596
|
+
* not secret and are not wiped; the digest characters they are joined from
|
|
1597
|
+
* are wiped here.
|
|
1218
1598
|
*/
|
|
1219
|
-
const
|
|
1220
|
-
const out: u8[] = new Array<u8>(
|
|
1221
|
-
const digests: u8[] = new Array<u8>(
|
|
1222
|
-
|
|
1223
|
-
for (let k: i32 = 0; k <
|
|
1224
|
-
|
|
1225
|
-
bcryptJoin(out, BCRYPT_HASH_LENGTH * k, batch.prefixes[k], digests, k)
|
|
1226
|
-
}
|
|
1599
|
+
const bcryptHashNExposed = (st: u32[], batch: BcryptBatch): u8[] => {
|
|
1600
|
+
const out: u8[] = new Array<u8>(BCRYPT_BATCH_LANES * BCRYPT_HASH_LENGTH)
|
|
1601
|
+
const digests: u8[] = new Array<u8>(31 * BCRYPT_BATCH_LANES)
|
|
1602
|
+
bcryptEksN(st, batch.salts, batch.cost, batch.width, digests)
|
|
1603
|
+
for (let k: i32 = 0; k < batch.width && k < toI32(batch.prefixes.length); k++) {
|
|
1604
|
+
bcryptJoin(out, BCRYPT_HASH_LENGTH * k, batch.prefixes[k], digests, k)
|
|
1227
1605
|
}
|
|
1228
1606
|
wipe(digests)
|
|
1229
1607
|
return out
|
|
1230
1608
|
}
|
|
1231
1609
|
|
|
1232
1610
|
/**
|
|
1233
|
-
* Bit k set for each running
|
|
1234
|
-
* `exposeWith` on the loaded batch state. The digest characters are built
|
|
1235
|
-
* wiped here, so the bits are all that leaves.
|
|
1611
|
+
* Bit k set for each running slot whose rebuilt hash is `batch.hashes[k]`,
|
|
1612
|
+
* for `exposeWith` on the loaded batch state. The digest characters are built
|
|
1613
|
+
* and wiped here, so the bits are all that leaves.
|
|
1236
1614
|
*/
|
|
1237
|
-
const
|
|
1238
|
-
const digests: u8[] = new Array<u8>(
|
|
1239
|
-
|
|
1615
|
+
const bcryptVerifyNExposed = (st: u32[], batch: BcryptBatch): i32 => {
|
|
1616
|
+
const digests: u8[] = new Array<u8>(31 * BCRYPT_BATCH_LANES)
|
|
1617
|
+
bcryptEksN(st, batch.salts, batch.cost, batch.width, digests)
|
|
1240
1618
|
let same: i32 = 0
|
|
1241
|
-
for (
|
|
1242
|
-
|
|
1619
|
+
for (
|
|
1620
|
+
let k: i32 = 0;
|
|
1621
|
+
k < batch.width && k < toI32(batch.prefixes.length) && k < toI32(batch.hashes.length);
|
|
1622
|
+
k++
|
|
1623
|
+
) {
|
|
1624
|
+
if (bcryptJoinedOk(batch.prefixes[k], digests, k, batch.hashes[k])) {
|
|
1243
1625
|
same |= 1 << k
|
|
1244
1626
|
}
|
|
1245
1627
|
}
|
|
@@ -1247,59 +1629,53 @@ const bcryptVerify4Exposed = (st: u32[], batch: BcryptBatch): i32 => {
|
|
|
1247
1629
|
return same
|
|
1248
1630
|
}
|
|
1249
1631
|
|
|
1250
|
-
/** `bcryptMagic` on all four lanes: lane k's eight bytes into `dst` at `24k + at`. */
|
|
1251
|
-
const bcryptMagic4 = (st: u32[], lr: u32[], dst: u8[], at: i32, l: u32, r: u32): void => {
|
|
1252
|
-
if (lr.length < 8) {
|
|
1253
|
-
return
|
|
1254
|
-
}
|
|
1255
|
-
for (let k: i32 = 0; k < 4; k++) {
|
|
1256
|
-
lr[2 * k] = l
|
|
1257
|
-
lr[2 * k + 1] = r
|
|
1258
|
-
}
|
|
1259
|
-
for (let n: i32 = 0; n < 64; n++) {
|
|
1260
|
-
bcryptEncrypt4(st, lr)
|
|
1261
|
-
}
|
|
1262
|
-
for (let k: i32 = 0; k < 4; k++) {
|
|
1263
|
-
bcryptPutBlock(dst, 24 * k + at, lr[2 * k], lr[2 * k + 1])
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
1632
|
/**
|
|
1268
|
-
* The batch `state` set up
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
* given, and a null lane must be outside the mask.
|
|
1633
|
+
* The batch `state` set up: the six states set to π, the safety words stored
|
|
1634
|
+
* and the password of caller lane `lanes[s]` loaded into slot s for each of
|
|
1635
|
+
* the `batch.width` slots. A lane no slot names is not read.
|
|
1272
1636
|
*/
|
|
1273
|
-
const
|
|
1637
|
+
const bcryptLoadN = (
|
|
1274
1638
|
state: Secret<u32[]>,
|
|
1275
1639
|
p0: Secret<u8[]>,
|
|
1276
1640
|
p1: Secret<u8[]> | null,
|
|
1277
1641
|
p2: Secret<u8[]> | null,
|
|
1278
1642
|
p3: Secret<u8[]> | null,
|
|
1643
|
+
p4: Secret<u8[]> | null,
|
|
1644
|
+
p5: Secret<u8[]> | null,
|
|
1645
|
+
lanes: i32[],
|
|
1279
1646
|
batch: BcryptBatch
|
|
1280
1647
|
): void => {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1648
|
+
exposeWith(state, batch, bcryptInitN)
|
|
1649
|
+
for (let s: i32 = 0; s < batch.width && s < toI32(lanes.length); s++) {
|
|
1650
|
+
const k: i32 = lanes[s]
|
|
1651
|
+
if (k === 0) {
|
|
1652
|
+
bcryptLoadSlot(state, p0, s)
|
|
1653
|
+
} else if (k === 1 && p1 !== null) {
|
|
1654
|
+
bcryptLoadSlot(state, p1, s)
|
|
1655
|
+
} else if (k === 2 && p2 !== null) {
|
|
1656
|
+
bcryptLoadSlot(state, p2, s)
|
|
1657
|
+
} else if (k === 3 && p3 !== null) {
|
|
1658
|
+
bcryptLoadSlot(state, p3, s)
|
|
1659
|
+
} else if (k === 4 && p4 !== null) {
|
|
1660
|
+
bcryptLoadSlot(state, p4, s)
|
|
1661
|
+
} else if (k === 5 && p5 !== null) {
|
|
1662
|
+
bcryptLoadSlot(state, p5, s)
|
|
1663
|
+
}
|
|
1294
1664
|
}
|
|
1295
1665
|
}
|
|
1296
1666
|
|
|
1297
|
-
/**
|
|
1667
|
+
/** Slot k's 60-byte hash out of the batch's `all`, as a string. */
|
|
1298
1668
|
const bcryptLaneString = (all: u8[], k: i32): string =>
|
|
1299
1669
|
String.fromBytes(all, BCRYPT_HASH_LENGTH * k, BCRYPT_HASH_LENGTH * (k + 1))
|
|
1300
1670
|
|
|
1301
|
-
/** Bit k set for each lane given: lane 0 always, lanes 1–
|
|
1302
|
-
const bcryptMaskOf = (
|
|
1671
|
+
/** Bit k set for each lane given: lane 0 always, lanes 1–5 when not null. */
|
|
1672
|
+
const bcryptMaskOf = (
|
|
1673
|
+
p1: Secret<u8[]> | null,
|
|
1674
|
+
p2: Secret<u8[]> | null,
|
|
1675
|
+
p3: Secret<u8[]> | null,
|
|
1676
|
+
p4: Secret<u8[]> | null,
|
|
1677
|
+
p5: Secret<u8[]> | null
|
|
1678
|
+
): i32 => {
|
|
1303
1679
|
let mask: i32 = 1
|
|
1304
1680
|
if (p1 !== null) {
|
|
1305
1681
|
mask |= 2
|
|
@@ -1310,82 +1686,129 @@ const bcryptMaskOf = (p1: Secret<u8[]> | null, p2: Secret<u8[]> | null, p3: Secr
|
|
|
1310
1686
|
if (p3 !== null) {
|
|
1311
1687
|
mask |= 8
|
|
1312
1688
|
}
|
|
1689
|
+
if (p4 !== null) {
|
|
1690
|
+
mask |= 16
|
|
1691
|
+
}
|
|
1692
|
+
if (p5 !== null) {
|
|
1693
|
+
mask |= 32
|
|
1694
|
+
}
|
|
1313
1695
|
return mask
|
|
1314
1696
|
}
|
|
1315
1697
|
|
|
1698
|
+
/** The lanes whose bit is set in `mask`, lowest first: the caller lane each slot runs. */
|
|
1699
|
+
const bcryptSlotsOf = (mask: i32): i32[] => {
|
|
1700
|
+
const lanes: i32[] = []
|
|
1701
|
+
for (let k: i32 = 0; k < BCRYPT_BATCH_LANES; k++) {
|
|
1702
|
+
if ((mask & (1 << k)) !== 0) {
|
|
1703
|
+
lanes.push(k)
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
return lanes
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1316
1709
|
/**
|
|
1317
|
-
* The `$2b$` hashes of up to
|
|
1710
|
+
* The `$2b$` hashes of up to six passwords at once, each as `bcryptHash`
|
|
1318
1711
|
* makes it: lane k with the 16 bytes of `salts` at 16k and 2^`cost` rounds.
|
|
1319
1712
|
* Lane 0 is always hashed; a null lane gives "" and its salt bytes are not
|
|
1320
|
-
* read.
|
|
1321
|
-
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1713
|
+
* read. The w lanes given run as one computation on one thread with their
|
|
1714
|
+
* cost rounds interleaved, whatever positions they are in; one lane runs as
|
|
1715
|
+
* `bcryptHash`. Which w is fastest per hash depends on the core
|
|
1716
|
+
* (`bcryptCalibrate` measures it). An `Err` for `salts` of another length
|
|
1717
|
+
* than 96 or a cost outside 4–31.
|
|
1324
1718
|
*/
|
|
1325
|
-
export const
|
|
1719
|
+
export const bcryptHashN = (
|
|
1326
1720
|
p0: Secret<u8[]>,
|
|
1327
1721
|
p1: Secret<u8[]> | null,
|
|
1328
1722
|
p2: Secret<u8[]> | null,
|
|
1329
1723
|
p3: Secret<u8[]> | null,
|
|
1724
|
+
p4: Secret<u8[]> | null,
|
|
1725
|
+
p5: Secret<u8[]> | null,
|
|
1330
1726
|
salts: u8[],
|
|
1331
1727
|
cost: i32
|
|
1332
1728
|
): Result<string[], string> => {
|
|
1333
|
-
if (salts.length !==
|
|
1334
|
-
return Err("bcrypt: the salts are not
|
|
1729
|
+
if (salts.length !== 96) {
|
|
1730
|
+
return Err("bcrypt: the salts are not 96 bytes")
|
|
1335
1731
|
}
|
|
1336
1732
|
if (cost < BCRYPT_MIN_COST || cost > BCRYPT_MAX_COST) {
|
|
1337
1733
|
return Err("bcrypt: the cost is outside 4 to 31")
|
|
1338
1734
|
}
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
if (mask === 1) {
|
|
1735
|
+
const lanes: i32[] = bcryptSlotsOf(bcryptMaskOf(p1, p2, p3, p4, p5))
|
|
1736
|
+
if (lanes.length === 1) {
|
|
1342
1737
|
const one: Result<string, string> = bcryptHash(p0, bcryptSaltOf(salts, 0), cost)
|
|
1343
1738
|
if (one.isErr()) {
|
|
1344
1739
|
return Err(one.error)
|
|
1345
1740
|
}
|
|
1346
|
-
|
|
1347
|
-
return Ok(hashes)
|
|
1741
|
+
return Ok([one.value, "", "", "", "", ""])
|
|
1348
1742
|
}
|
|
1349
|
-
const words: u32[] = new Array<u32>(
|
|
1743
|
+
const words: u32[] = new Array<u32>(24)
|
|
1350
1744
|
const prefixes: u8[][] = []
|
|
1351
|
-
for (let
|
|
1352
|
-
|
|
1353
|
-
prefixes.push([])
|
|
1354
|
-
continue
|
|
1355
|
-
}
|
|
1356
|
-
prefixes.push(bcryptBatchSalt(words, salts, k, cost))
|
|
1745
|
+
for (let s: i32 = 0; s < toI32(lanes.length); s++) {
|
|
1746
|
+
prefixes.push(bcryptBatchSalt(words, salts, lanes[s], s, cost))
|
|
1357
1747
|
}
|
|
1358
1748
|
const none: string[] = []
|
|
1359
1749
|
const batch: BcryptBatch = {
|
|
1360
1750
|
salts: words,
|
|
1361
|
-
safety: new Array<u32>(
|
|
1751
|
+
safety: new Array<u32>(BCRYPT_BATCH_LANES),
|
|
1362
1752
|
cost: cost,
|
|
1363
|
-
|
|
1753
|
+
width: toI32(lanes.length),
|
|
1364
1754
|
prefixes: prefixes,
|
|
1365
1755
|
hashes: none,
|
|
1366
1756
|
}
|
|
1367
1757
|
const state: Secret<u32[]> = secret(new Array<u32>(BCRYPT_BATCH_WORDS))
|
|
1368
|
-
|
|
1369
|
-
const all: u8[] = exposeWith(state, batch,
|
|
1758
|
+
bcryptLoadN(state, p0, p1, p2, p3, p4, p5, lanes, batch)
|
|
1759
|
+
const all: u8[] = exposeWith(state, batch, bcryptHashNExposed)
|
|
1370
1760
|
wipe(state)
|
|
1761
|
+
// Slot s ran lane lanes[s]; a lane not given stays "".
|
|
1762
|
+
const out: string[] = ["", "", "", "", "", ""]
|
|
1763
|
+
for (let s: i32 = 0; s < toI32(lanes.length); s++) {
|
|
1764
|
+
out[lanes[s]] = bcryptLaneString(all, s)
|
|
1765
|
+
}
|
|
1766
|
+
return Ok(out)
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* `bcryptHashN` for up to four passwords, `salts` 64 bytes: the same hashes,
|
|
1771
|
+
* four strings. An `Err` for `salts` of another length than 64 or a cost
|
|
1772
|
+
* outside 4–31.
|
|
1773
|
+
*/
|
|
1774
|
+
export const bcryptHash4 = (
|
|
1775
|
+
p0: Secret<u8[]>,
|
|
1776
|
+
p1: Secret<u8[]> | null,
|
|
1777
|
+
p2: Secret<u8[]> | null,
|
|
1778
|
+
p3: Secret<u8[]> | null,
|
|
1779
|
+
salts: u8[],
|
|
1780
|
+
cost: i32
|
|
1781
|
+
): Result<string[], string> => {
|
|
1782
|
+
if (salts.length !== 64) {
|
|
1783
|
+
return Err("bcrypt: the salts are not 64 bytes")
|
|
1784
|
+
}
|
|
1785
|
+
const wide: u8[] = new Array<u8>(96)
|
|
1786
|
+
for (let i: i32 = 0; i < 64 && i < toI32(salts.length); i++) {
|
|
1787
|
+
wide[i] = salts[i]
|
|
1788
|
+
}
|
|
1789
|
+
const made: Result<string[], string> = bcryptHashN(p0, p1, p2, p3, null, null, wide, cost)
|
|
1790
|
+
if (made.isErr()) {
|
|
1791
|
+
return Err(made.error)
|
|
1792
|
+
}
|
|
1793
|
+
const six: string[] = made.value
|
|
1371
1794
|
const out: string[] = []
|
|
1372
|
-
for (let k: i32 = 0; k < 4; k++) {
|
|
1373
|
-
out.push(
|
|
1795
|
+
for (let k: i32 = 0; k < 4 && k < toI32(six.length); k++) {
|
|
1796
|
+
out.push(six[k])
|
|
1374
1797
|
}
|
|
1375
1798
|
return Ok(out)
|
|
1376
1799
|
}
|
|
1377
1800
|
|
|
1378
|
-
/** Lane `k`'s salt from the
|
|
1379
|
-
const bcryptBatchSalt = (words: u32[], salts: u8[], k: i32, cost: i32): u8[] => {
|
|
1801
|
+
/** Lane `k`'s salt from the 96 bytes of `salts` into `words` at 4s as four words, and its 29-byte setting. */
|
|
1802
|
+
const bcryptBatchSalt = (words: u32[], salts: u8[], k: i32, s: i32, cost: i32): u8[] => {
|
|
1380
1803
|
const salt: u8[] = bcryptSaltOf(salts, k)
|
|
1381
1804
|
const four: u32[] = bcryptSaltWords(salt)
|
|
1382
|
-
for (let j: i32 = 0; j < 4 && j < toI32(four.length) && 4 *
|
|
1383
|
-
words[4 *
|
|
1805
|
+
for (let j: i32 = 0; j < 4 && j < toI32(four.length) && 4 * s + j < toI32(words.length); j++) {
|
|
1806
|
+
words[4 * s + j] = four[j]
|
|
1384
1807
|
}
|
|
1385
1808
|
return bcryptSettingOf(salt, cost)
|
|
1386
1809
|
}
|
|
1387
1810
|
|
|
1388
|
-
/** The 16 salt bytes of lane `k` from the
|
|
1811
|
+
/** The 16 salt bytes of lane `k` from the bytes of a batch. */
|
|
1389
1812
|
const bcryptSaltOf = (salts: u8[], k: i32): u8[] => {
|
|
1390
1813
|
const salt: u8[] = new Array<u8>(16)
|
|
1391
1814
|
for (let j: i32 = 0; j < 16 && 16 * k + j < toI32(salts.length); j++) {
|
|
@@ -1394,7 +1817,7 @@ const bcryptSaltOf = (salts: u8[], k: i32): u8[] => {
|
|
|
1394
1817
|
return salt
|
|
1395
1818
|
}
|
|
1396
1819
|
|
|
1397
|
-
/** The 60 bytes of
|
|
1820
|
+
/** The 60 bytes of slot `k`'s hash into `out` at `at`: its 29-byte setting, then its 31 digest characters from the batch's. */
|
|
1398
1821
|
const bcryptJoin = (out: u8[], at: i32, prefix: u8[], digests: u8[], k: i32): void => {
|
|
1399
1822
|
bcryptPut(out, at, prefix)
|
|
1400
1823
|
const o: i32 = at + BCRYPT_SETTING_LENGTH
|
|
@@ -1408,7 +1831,7 @@ const bcryptJoin = (out: u8[], at: i32, prefix: u8[], digests: u8[], k: i32): vo
|
|
|
1408
1831
|
}
|
|
1409
1832
|
|
|
1410
1833
|
/**
|
|
1411
|
-
* Whether each of `hashes` (
|
|
1834
|
+
* Whether each of `hashes` (six strings) is its lane's password's, as
|
|
1412
1835
|
* `bcryptVerify` decides it: lane 0 always, a null lane `false` and its
|
|
1413
1836
|
* string not read. Lanes are grouped by the cost their hash names and each
|
|
1414
1837
|
* group of two or more runs as one interleaved computation; a group of one
|
|
@@ -1416,19 +1839,21 @@ const bcryptJoin = (out: u8[], at: i32, prefix: u8[], digests: u8[], k: i32): vo
|
|
|
1416
1839
|
* call an `Err` naming the lane ("bcrypt: lane 2: …") before any hashing, so
|
|
1417
1840
|
* one bad row in a batch cannot be read as a wrong password.
|
|
1418
1841
|
*/
|
|
1419
|
-
export const
|
|
1842
|
+
export const bcryptVerifyN = (
|
|
1420
1843
|
p0: Secret<u8[]>,
|
|
1421
1844
|
p1: Secret<u8[]> | null,
|
|
1422
1845
|
p2: Secret<u8[]> | null,
|
|
1423
1846
|
p3: Secret<u8[]> | null,
|
|
1847
|
+
p4: Secret<u8[]> | null,
|
|
1848
|
+
p5: Secret<u8[]> | null,
|
|
1424
1849
|
hashes: string[]
|
|
1425
1850
|
): Result<boolean[], string> => {
|
|
1426
|
-
if (hashes.length !==
|
|
1427
|
-
return Err("bcrypt: a batch is
|
|
1851
|
+
if (hashes.length !== 6) {
|
|
1852
|
+
return Err("bcrypt: a batch is six hashes")
|
|
1428
1853
|
}
|
|
1429
|
-
const mask: i32 = bcryptMaskOf(p1, p2, p3)
|
|
1854
|
+
const mask: i32 = bcryptMaskOf(p1, p2, p3, p4, p5)
|
|
1430
1855
|
const lanes: BcryptParsed[] = []
|
|
1431
|
-
for (let k: i32 = 0; k <
|
|
1856
|
+
for (let k: i32 = 0; k < BCRYPT_BATCH_LANES && k < toI32(hashes.length); k++) {
|
|
1432
1857
|
if ((mask & (1 << k)) !== 0) {
|
|
1433
1858
|
const parsed: Result<BcryptParsed, string> = bcryptParseHash(hashes[k])
|
|
1434
1859
|
if (parsed.isErr()) {
|
|
@@ -1443,41 +1868,75 @@ export const bcryptVerify4 = (
|
|
|
1443
1868
|
})
|
|
1444
1869
|
}
|
|
1445
1870
|
}
|
|
1446
|
-
const ok: boolean[] = [false, false, false, false]
|
|
1447
|
-
let done: i32 = ~mask &
|
|
1871
|
+
const ok: boolean[] = [false, false, false, false, false, false]
|
|
1872
|
+
let done: i32 = ~mask & 63
|
|
1448
1873
|
for (
|
|
1449
1874
|
let k: i32 = 0;
|
|
1450
|
-
k <
|
|
1875
|
+
k < BCRYPT_BATCH_LANES && k < toI32(lanes.length) && k < toI32(hashes.length) && k < toI32(ok.length);
|
|
1451
1876
|
k++
|
|
1452
1877
|
) {
|
|
1453
1878
|
if ((done & (1 << k)) === 0) {
|
|
1454
1879
|
const cost: i32 = lanes[k].setting.cost
|
|
1455
1880
|
let group: i32 = 0
|
|
1456
|
-
for (let j: i32 = k; j <
|
|
1881
|
+
for (let j: i32 = k; j < BCRYPT_BATCH_LANES && j < toI32(lanes.length); j++) {
|
|
1457
1882
|
if ((done & (1 << j)) === 0 && lanes[j].setting.cost === cost) {
|
|
1458
1883
|
group |= 1 << j
|
|
1459
1884
|
}
|
|
1460
1885
|
}
|
|
1461
1886
|
done |= group
|
|
1462
1887
|
if (group === 1 << k) {
|
|
1463
|
-
const one: boolean = bcryptLaneOk(p0, p1, p2, p3, k, lanes[k], hashes[k])
|
|
1888
|
+
const one: boolean = bcryptLaneOk(p0, p1, p2, p3, p4, p5, k, lanes[k], hashes[k])
|
|
1464
1889
|
if (k < toI32(ok.length)) {
|
|
1465
1890
|
ok[k] = one
|
|
1466
1891
|
}
|
|
1467
1892
|
} else {
|
|
1468
|
-
bcryptVerifyGroup(p0, p1, p2, p3, group, lanes, hashes, ok)
|
|
1893
|
+
bcryptVerifyGroup(p0, p1, p2, p3, p4, p5, group, lanes, hashes, ok)
|
|
1469
1894
|
}
|
|
1470
1895
|
}
|
|
1471
1896
|
}
|
|
1472
1897
|
return Ok(ok)
|
|
1473
1898
|
}
|
|
1474
1899
|
|
|
1900
|
+
/**
|
|
1901
|
+
* `bcryptVerifyN` for up to four passwords and four hashes: the same
|
|
1902
|
+
* answers, four of them, and the same lane errors.
|
|
1903
|
+
*/
|
|
1904
|
+
export const bcryptVerify4 = (
|
|
1905
|
+
p0: Secret<u8[]>,
|
|
1906
|
+
p1: Secret<u8[]> | null,
|
|
1907
|
+
p2: Secret<u8[]> | null,
|
|
1908
|
+
p3: Secret<u8[]> | null,
|
|
1909
|
+
hashes: string[]
|
|
1910
|
+
): Result<boolean[], string> => {
|
|
1911
|
+
if (hashes.length !== 4) {
|
|
1912
|
+
return Err("bcrypt: a batch is four hashes")
|
|
1913
|
+
}
|
|
1914
|
+
const six: string[] = []
|
|
1915
|
+
for (let k: i32 = 0; k < toI32(hashes.length); k++) {
|
|
1916
|
+
six.push(hashes[k])
|
|
1917
|
+
}
|
|
1918
|
+
six.push("")
|
|
1919
|
+
six.push("")
|
|
1920
|
+
const said: Result<boolean[], string> = bcryptVerifyN(p0, p1, p2, p3, null, null, six)
|
|
1921
|
+
if (said.isErr()) {
|
|
1922
|
+
return Err(said.error)
|
|
1923
|
+
}
|
|
1924
|
+
const all: boolean[] = said.value
|
|
1925
|
+
const out: boolean[] = []
|
|
1926
|
+
for (let k: i32 = 0; k < 4 && k < toI32(all.length); k++) {
|
|
1927
|
+
out.push(all[k])
|
|
1928
|
+
}
|
|
1929
|
+
return Ok(out)
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1475
1932
|
/** Whether lane `k`'s password, hashed alone with `lane`'s setting, gives `hash`. */
|
|
1476
1933
|
const bcryptLaneOk = (
|
|
1477
1934
|
p0: Secret<u8[]>,
|
|
1478
1935
|
p1: Secret<u8[]> | null,
|
|
1479
1936
|
p2: Secret<u8[]> | null,
|
|
1480
1937
|
p3: Secret<u8[]> | null,
|
|
1938
|
+
p4: Secret<u8[]> | null,
|
|
1939
|
+
p5: Secret<u8[]> | null,
|
|
1481
1940
|
k: i32,
|
|
1482
1941
|
lane: BcryptParsed,
|
|
1483
1942
|
hash: string
|
|
@@ -1494,10 +1953,16 @@ const bcryptLaneOk = (
|
|
|
1494
1953
|
if (k === 3 && p3 !== null) {
|
|
1495
1954
|
return bcryptVerifyOne(p3, lane, hash)
|
|
1496
1955
|
}
|
|
1956
|
+
if (k === 4 && p4 !== null) {
|
|
1957
|
+
return bcryptVerifyOne(p4, lane, hash)
|
|
1958
|
+
}
|
|
1959
|
+
if (k === 5 && p5 !== null) {
|
|
1960
|
+
return bcryptVerifyOne(p5, lane, hash)
|
|
1961
|
+
}
|
|
1497
1962
|
return false
|
|
1498
1963
|
}
|
|
1499
1964
|
|
|
1500
|
-
/** Whether
|
|
1965
|
+
/** Whether slot `k`'s hash joined from `prefix` and the batch's digests is `hash`. */
|
|
1501
1966
|
const bcryptJoinedOk = (prefix: u8[], digests: u8[], k: i32, hash: string): boolean => {
|
|
1502
1967
|
const joined: u8[] = new Array<u8>(BCRYPT_HASH_LENGTH)
|
|
1503
1968
|
bcryptJoin(joined, 0, prefix, digests, k)
|
|
@@ -1510,48 +1975,119 @@ const bcryptVerifyGroup = (
|
|
|
1510
1975
|
p1: Secret<u8[]> | null,
|
|
1511
1976
|
p2: Secret<u8[]> | null,
|
|
1512
1977
|
p3: Secret<u8[]> | null,
|
|
1978
|
+
p4: Secret<u8[]> | null,
|
|
1979
|
+
p5: Secret<u8[]> | null,
|
|
1513
1980
|
group: i32,
|
|
1514
1981
|
lanes: BcryptParsed[],
|
|
1515
1982
|
hashes: string[],
|
|
1516
1983
|
ok: boolean[]
|
|
1517
1984
|
): void => {
|
|
1518
|
-
const words: u32[] = new Array<u32>(
|
|
1519
|
-
const safety: u32[] = new Array<u32>(
|
|
1985
|
+
const words: u32[] = new Array<u32>(24)
|
|
1986
|
+
const safety: u32[] = new Array<u32>(BCRYPT_BATCH_LANES)
|
|
1520
1987
|
const prefixes: u8[][] = []
|
|
1988
|
+
// Copies, so no callee is handed the caller's `hashes` (the thread rule).
|
|
1521
1989
|
const given: string[] = []
|
|
1990
|
+
// The lanes loaded, in slot order: slot s holds lane slots[s].
|
|
1991
|
+
const slots: i32[] = []
|
|
1522
1992
|
let cost: i32 = 0
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
1530
|
-
for (let k: i32 = 0; k < 4 && k < toI32(lanes.length) && k < toI32(safety.length); k++) {
|
|
1531
|
-
if ((group & (1 << k)) !== 0) {
|
|
1532
|
-
const setting: BcryptSetting = lanes[k].setting
|
|
1993
|
+
for (const k of bcryptSlotsOf(group)) {
|
|
1994
|
+
const s: i32 = toI32(slots.length)
|
|
1995
|
+
if (s < toI32(safety.length) && k >= 0 && k < toI32(lanes.length) && k < toI32(hashes.length)) {
|
|
1996
|
+
const lane: BcryptParsed = lanes[k]
|
|
1997
|
+
const hash: string = hashes[k]
|
|
1998
|
+
const setting: BcryptSetting = lane.setting
|
|
1533
1999
|
cost = setting.cost
|
|
1534
|
-
safety[
|
|
2000
|
+
safety[s] = setting.safety
|
|
1535
2001
|
for (let j: i32 = 0; j < 4 && j < toI32(setting.salt.length); j++) {
|
|
1536
|
-
words[4 *
|
|
2002
|
+
words[4 * s + j] = setting.salt[j]
|
|
1537
2003
|
}
|
|
2004
|
+
given.push(hash)
|
|
2005
|
+
prefixes.push(lane.prefix)
|
|
2006
|
+
slots.push(k)
|
|
1538
2007
|
}
|
|
1539
2008
|
}
|
|
1540
2009
|
const batch: BcryptBatch = {
|
|
1541
2010
|
salts: words,
|
|
1542
2011
|
safety: safety,
|
|
1543
2012
|
cost: cost,
|
|
1544
|
-
|
|
2013
|
+
width: toI32(prefixes.length),
|
|
1545
2014
|
prefixes: prefixes,
|
|
1546
2015
|
hashes: given,
|
|
1547
2016
|
}
|
|
1548
2017
|
const state: Secret<u32[]> = secret(new Array<u32>(BCRYPT_BATCH_WORDS))
|
|
1549
|
-
|
|
1550
|
-
const same: i32 = exposeWith(state, batch,
|
|
2018
|
+
bcryptLoadN(state, p0, p1, p2, p3, p4, p5, slots, batch)
|
|
2019
|
+
const same: i32 = exposeWith(state, batch, bcryptVerifyNExposed)
|
|
1551
2020
|
wipe(state)
|
|
1552
|
-
for (let
|
|
1553
|
-
|
|
1554
|
-
|
|
2021
|
+
for (let s: i32 = 0; s < toI32(slots.length); s++) {
|
|
2022
|
+
const k: i32 = slots[s]
|
|
2023
|
+
if (k >= 0 && k < toI32(ok.length)) {
|
|
2024
|
+
ok[k] = (same & (1 << s)) !== 0
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
/** The time a width that never hashed is given: an hour, in nanoseconds. */
|
|
2030
|
+
const BCRYPT_CALIBRATE_NEVER: i64 = 3600000000000
|
|
2031
|
+
|
|
2032
|
+
/** Throwaway passwords hashed when calibrating: one byte each, not secret, wiped all the same. */
|
|
2033
|
+
const bcryptCalibrateKey = (k: i32): Secret<u8[]> => secret([toU8(0x41 + k)])
|
|
2034
|
+
|
|
2035
|
+
/** Nanoseconds of one cost-4 `bcryptHashN` of `width` throwaway passwords, the least of a few runs. */
|
|
2036
|
+
const bcryptCalibrateTime = (width: i32): i64 => {
|
|
2037
|
+
const salts: u8[] = new Array<u8>(96)
|
|
2038
|
+
let best: i64 = -1
|
|
2039
|
+
for (let run: i32 = 0; run < 3; run++) {
|
|
2040
|
+
const p0: Secret<u8[]> = bcryptCalibrateKey(0)
|
|
2041
|
+
const p1: Secret<u8[]> | null = width > 1 ? bcryptCalibrateKey(1) : null
|
|
2042
|
+
const p2: Secret<u8[]> | null = width > 2 ? bcryptCalibrateKey(2) : null
|
|
2043
|
+
const p3: Secret<u8[]> | null = width > 3 ? bcryptCalibrateKey(3) : null
|
|
2044
|
+
const p4: Secret<u8[]> | null = width > 4 ? bcryptCalibrateKey(4) : null
|
|
2045
|
+
const p5: Secret<u8[]> | null = width > 5 ? bcryptCalibrateKey(5) : null
|
|
2046
|
+
const start: i64 = monotonicNanos()
|
|
2047
|
+
const made: Result<string[], string> = bcryptHashN(p0, p1, p2, p3, p4, p5, salts, BCRYPT_MIN_COST)
|
|
2048
|
+
const took: i64 = monotonicNanos() - start
|
|
2049
|
+
if (made.isOk() && (best < 0 || took < best)) {
|
|
2050
|
+
best = took
|
|
2051
|
+
}
|
|
2052
|
+
wipe(p0)
|
|
2053
|
+
if (p1 !== null) {
|
|
2054
|
+
wipe(p1)
|
|
2055
|
+
}
|
|
2056
|
+
if (p2 !== null) {
|
|
2057
|
+
wipe(p2)
|
|
2058
|
+
}
|
|
2059
|
+
if (p3 !== null) {
|
|
2060
|
+
wipe(p3)
|
|
2061
|
+
}
|
|
2062
|
+
if (p4 !== null) {
|
|
2063
|
+
wipe(p4)
|
|
2064
|
+
}
|
|
2065
|
+
if (p5 !== null) {
|
|
2066
|
+
wipe(p5)
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
// No run hashed: an hour, so this width never wins and the products stay in range.
|
|
2070
|
+
return best < 0 ? BCRYPT_CALIBRATE_NEVER : best
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* The batch width, 1 to 6, that hashes fastest per password on this core:
|
|
2075
|
+
* each width timed on throwaway passwords at cost 4, the least time of a few
|
|
2076
|
+
* runs divided by the width. It measures rather than guesses, since the best
|
|
2077
|
+
* width turns on the core's load ports, its registers and what else is
|
|
2078
|
+
* running, and it keeps nothing between calls, so call it once, at startup,
|
|
2079
|
+
* and keep the answer. A few tens of milliseconds of one core.
|
|
2080
|
+
*/
|
|
2081
|
+
export const bcryptCalibrate = (): i32 => {
|
|
2082
|
+
let best: i32 = 1
|
|
2083
|
+
let bestTime: i64 = bcryptCalibrateTime(1)
|
|
2084
|
+
for (let w: i32 = 2; w <= BCRYPT_BATCH_LANES; w++) {
|
|
2085
|
+
const took: i64 = bcryptCalibrateTime(w)
|
|
2086
|
+
// took / w < bestTime / best, without dividing.
|
|
2087
|
+
if (took * toI64(best) < bestTime * toI64(w)) {
|
|
2088
|
+
best = w
|
|
2089
|
+
bestTime = took
|
|
1555
2090
|
}
|
|
1556
2091
|
}
|
|
2092
|
+
return best
|
|
1557
2093
|
}
|