@amritk/nish-x86_64-linux 0.14.0 → 0.16.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.
@@ -435,8 +435,19 @@ export class Sha256 {
435
435
  }
436
436
  }
437
437
 
438
- /** The SHA-256 digest of all of `data`, as a fresh 32-byte array. */
438
+ /**
439
+ * The SHA-256 digest of all of `data`, as a fresh 32-byte array.
440
+ *
441
+ * An array longer than 2^31 - 1 bytes panics. A window's length is an `i32`,
442
+ * and under `--number-mode f64` `toI32` of a longer length saturates, so
443
+ * hashing `toI32(data.length)` bytes would answer the digest of a prefix: one
444
+ * digest for every message that shares its first 2^31 - 1 bytes. The length
445
+ * is compared as the `number` it is, before any `toI32`.
446
+ */
439
447
  export const sha256 = (data: u8[]): u8[] => {
448
+ if (data.length > 2147483647) {
449
+ panic("sha256: a message longer than 2^31 - 1 bytes")
450
+ }
440
451
  const hasher: Sha256 = new Sha256()
441
452
  const from: i32 = 0
442
453
  hasher.update(data, from, toI32(data.length))
@@ -495,15 +495,29 @@ export class Sha384 {
495
495
  }
496
496
  }
497
497
 
498
- /** The SHA-512 digest of all of `data`, as a fresh 64-byte array. */
498
+ /**
499
+ * The SHA-512 digest of all of `data`, as a fresh 64-byte array. An array
500
+ * longer than 2^31 - 1 bytes panics, for the reason `sha256` gives: a longer
501
+ * length does not survive `toI32` under `--number-mode f64`, and the digest
502
+ * would be of a prefix.
503
+ */
499
504
  export const sha512 = (data: u8[]): u8[] => {
505
+ if (data.length > 2147483647) {
506
+ panic("sha512: a message longer than 2^31 - 1 bytes")
507
+ }
500
508
  const hasher = new Sha512()
501
509
  hasher.update(data, OFFSET_ZERO, toI32(data.length))
502
510
  return hasher.digest()
503
511
  }
504
512
 
505
- /** The SHA-384 digest of all of `data`, as a fresh 48-byte array. */
513
+ /**
514
+ * The SHA-384 digest of all of `data`, as a fresh 48-byte array. An array
515
+ * longer than 2^31 - 1 bytes panics, as in `sha512`.
516
+ */
506
517
  export const sha384 = (data: u8[]): u8[] => {
518
+ if (data.length > 2147483647) {
519
+ panic("sha384: a message longer than 2^31 - 1 bytes")
520
+ }
507
521
  const hasher = new Sha384()
508
522
  hasher.update(data, OFFSET_ZERO, toI32(data.length))
509
523
  return hasher.digest()
@@ -26,13 +26,28 @@
26
26
  * nicety: each function states what it accepts and what it answers, and
27
27
  * `f25519Mul` says why its sums fit.
28
28
  *
29
- * **Constant time, by construction and not yet by proof.** Nothing branches
30
- * on, or indexes by, a secret: the ladder swaps with a mask and runs all 255
31
- * steps whatever the scalar, and the final reduction subtracts p by adding a
32
- * carry bit times 19 rather than by comparing. Every `if` and every loop bound
33
- * here is on a public quantity — a limb number, a bit position or an input
34
- * length. WP34 N6's `ctSelect` and its disassembly check are what will verify
35
- * that; they do not exist yet.
29
+ * **Constant time, by construction, and in part by disassembly.** Nothing
30
+ * branches on, or indexes by, a secret: the ladder swaps with a mask and runs
31
+ * all 255 steps whatever the scalar, and the final reduction subtracts p by
32
+ * adding a carry bit times 19 rather than by comparing. Every `if` and every
33
+ * loop bound here is on a public quantity — a limb number, a bit position or
34
+ * an input length.
35
+ *
36
+ * WP34 N6's disassembly check (`tests/ct-asm.js`) verifies the part a secret
37
+ * flows through: `tests/cases/ct_asm_x25519` holds copies of `f25519Mul`,
38
+ * `f25519Square`, `f25519MulA24`, `f25519Add`, `f25519Sub`, `f25519Swap` and
39
+ * one pass of `x25519Ladder`'s loop, and the check reads each one's `clang -O2`
40
+ * machine code for x86-64 and aarch64 and finds no branch and no load or store
41
+ * at an address the scalar bit or a limb reaches. They are copies because the
42
+ * check refuses every branch, loop back-edges included, and this module's own
43
+ * functions keep their loops and the early `return`s below; the copies drop the
44
+ * guards and write `f25519Mul`'s outer loop out a row at a time, and the
45
+ * fixture's `main` holds them to the same RFC 7748 vectors as this module. A
46
+ * change to one of those functions belongs in that fixture too. What stays
47
+ * discipline rather than proof is the rest: the loops around the step,
48
+ * `f25519Decode`, `f25519Encode` and `f25519Invert`, whose branches are all on
49
+ * public positions. Weekly, `tests/ct-timing.js` times the fixture's functions
50
+ * on real x86-64 and aarch64 hardware as well.
36
51
  *
37
52
  * **Loop bounds are literals.** A field element is always ten limbs and an
38
53
  * encoding always 32 bytes, and each function that indexes one opens with an
@@ -465,9 +480,10 @@ const x25519Ladder = (k: u8[], u: i64[]): u8[] => {
465
480
  *
466
481
  * Answers `null` unless both arguments are exactly `X25519_SIZE` bytes. An
467
482
  * all-zero answer is **returned, not refused**: it is what a low-order `u`
468
- * gives, and RFC 7748 §6.1 leaves checking for it to the protocol, which is
469
- * where TLS 1.3 (WP34 T1) makes that check. A caller doing a key exchange
470
- * outside TLS should make it too.
483
+ * gives, and RFC 7748 §6.1 leaves checking for it to the protocol. Nothing in
484
+ * this tree makes that check for you yet (TLS 1.3, WP34 T1, is planned to), so
485
+ * every caller doing a key exchange must refuse an all-zero answer itself —
486
+ * with `timingSafeEqual` against 32 zero bytes, since the answer is a secret.
471
487
  */
472
488
  export const x25519 = (scalar: u8[], u: u8[]): u8[] | null => {
473
489
  if (toI32(scalar.length) !== 32 || toI32(u.length) !== 32) {