]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
hashx: Fix rare compiler output overflow on aarch64
authorMicah Elizabeth Scott <beth@torproject.org>
Fri, 11 Aug 2023 21:34:05 +0000 (14:34 -0700)
committerMicah Elizabeth Scott <beth@torproject.org>
Fri, 11 Aug 2023 22:05:11 +0000 (15:05 -0700)
This is a fix for a very rare buffer overflow in hashx, specific to the
dynamic compiler on aarch64 platforms.

In practice this issue is extremely unlikely to hit randomly, and it's
only been seen in unit tests that supply unusual mock PRNG output to the
program generator. My best attempt at estimating the probability of
hitting the overflow randomly is about 10^-23. Crafting an input with
the intent to overflow can be done only as fast as an exhaustive search,
so long as Blake2B is unbroken.

The root cause is that hashx writes assembly code without any length
checks, and it uses an estimated size rather than an absolute maximum
size to allocate the buffer for compiled code. Some instructions are
much longer than others, especially on aarch64.

The length of the overflow is nearly 300 bytes in the worst synthetic
test cases I've developed so far. Overflow occurs during hashx_make(),
and the subsequent hashx_exec() will always SIGSEGV as the written code
crosses outside the region that's been marked executable. In typical use,
hashx_exec() is called immediately after hashx_make().

This fix increases the buffer size from 1 page to 2 pages on aarch64,
adds an analysis of the compiled code size, and adds runtime checks so we
can gracefully fail on overflow. It also adds a unit test (written in
Rust) that includes a PRNG sequence exercising the overflow. Without
this patch the unit test shows a SIGSEGV on aarch64, with this patch it
runs successfully and matches interpreter output.

Signed-off-by: Micah Elizabeth Scott <beth@torproject.org>
src/ext/equix/hashx/src/compiler.h
src/ext/equix/hashx/src/compiler_a64.c
src/ext/equix/hashx/src/compiler_x86.c
src/ext/equix/src/lib.rs

index f248e8c1ea04c7cf808624bdbcc16f505ad1c1b3..b7b47dfcb523a45db8fe17aa9fc9a72b7d41a06c 100644 (file)
@@ -27,12 +27,51 @@ HASHX_PRIVATE bool hashx_compile_a64(const hashx_program* program, uint8_t* code
 HASHX_PRIVATE void hashx_compiler_init(hashx_ctx* compiler);
 HASHX_PRIVATE void hashx_compiler_destroy(hashx_ctx* compiler);
 
-#define COMP_PAGE_SIZE 4096
-#define COMP_RESERVE_SIZE 1024
-#define COMP_AVG_INSTR_SIZE 5
-#define COMP_CODE_SIZE                                                        \
-       ALIGN_SIZE(                                                               \
-               HASHX_PROGRAM_MAX_SIZE * COMP_AVG_INSTR_SIZE + COMP_RESERVE_SIZE,     \
-       COMP_PAGE_SIZE)
+/* Compiled code sizes in bytes:
+ *
+ *      Prologue   Epilogue   MulH   Reg-Reg   Reg-Imm32   Branch+Tgt   MaxInst
+ * X86  69         64         9      3..4      7           15           10 (br)
+ * A64  40         36         4      4         12          24           24 (br)
+ *
+ * Maximum code sizes, assuming an arbitrary instruction mix including unlimited
+ * branch instructions. (Branch size * 512 + prologue + epilogue)
+ *
+ *      Max possible code size (any instructions)
+ * X86  5253
+ * A64  12364
+ *
+ * Actual code sizes tend to be much smaller due to the instruction mix chosen
+ * by the program generator. To get a quick overview of the statistics, we
+ * measure the sample mean and sample standard deviation for 1 million random
+ * hash programs:
+ *
+ *      Mean     Std Deviation   4096 bytes at
+ * X86  2786.4   26.259          49.9 standard deviations
+ * A64  3507.7   58.526          10.1 standard deviations
+ *
+ * If we search for PRNG sequences that maximize generated code size, it's easy
+ * to find aarch64 code that needs in the range of 4100-4300 bytes. On x86, this
+ * search still doesn't turn up programs anywhere close to a full page.
+ *
+ * Anyway, this is all to say that a one-page buffer is fine except for in
+ * extremely rare cases on aarch64, and a two-page buffer is enough for any
+ * behavior we can expect from the program generator under arbitrary input,
+ * but only a 4-page buffer is enough for fully arbitrary instruction streams
+ * on any architecture.
+ *
+ * Let's use a 2-page buffer on aarch64, or 1-page elsewhere.
+ *
+ * Note that the buffer allocation is done by platform-independent code,
+ * so COMP_CODE_SIZE must always have a valid size even on platforms where
+ * it is not actually supported or used.
+ *
+ * If this buffer fills up, compilation will fail with a runtime error.
+ */
+
+#ifdef HASHX_COMPILER_A64
+#define COMP_CODE_SIZE (4096 * 2)
+#else
+#define COMP_CODE_SIZE (4096 * 1)
+#endif
 
 #endif
index 1b7081f53763fe3ac17479758041f86695705419..c8a28661bba4a47afd118259b5182e861870d532 100644 (file)
@@ -23,6 +23,9 @@
 
 #ifdef HASHX_COMPILER_A64
 
+/* Largest compiled instruction (BRANCH) */
+#define COMP_MAX_INSTR_SIZE 24
+
 static const uint8_t a64_prologue[] = {
        0x07, 0x1c, 0x40, 0xf9, /* ldr x7, [x0, #56] */
        0x06, 0x18, 0x40, 0xf9, /* ldr x6, [x0, #48] */
@@ -56,6 +59,8 @@ bool hashx_compile_a64(const hashx_program* program, uint8_t* code) {
        int creg = -1;
        EMIT(pos, a64_prologue);
        for (int i = 0; i < program->code_size; ++i) {
+               if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE)
+                       return false;
                const instruction* instr = &program->code[i];
                switch (instr->opcode)
                {
@@ -145,6 +150,8 @@ bool hashx_compile_a64(const hashx_program* program, uint8_t* code) {
                        UNREACHABLE;
                }
        }
+       if (pos + sizeof a64_epilogue > code + COMP_CODE_SIZE)
+               return false;
        EMIT(pos, a64_epilogue);
        if (!hashx_vm_rx(code, COMP_CODE_SIZE))
                return false;
index 12f59a1d0b64e39458fae62ec5d7d4fb775d3ec5..df4fdbebb8e4dc9b7f6c534610960bfd75c21a51 100644 (file)
@@ -25,6 +25,9 @@
 
 #ifdef HASHX_COMPILER_X86
 
+/* Largest compiled instruction (BRANCH) */
+#define COMP_MAX_INSTR_SIZE 10
+
 static const uint8_t x86_prologue[] = {
 #ifndef WINABI
        0x48, 0x89, 0xF9,             /* mov rcx, rdi */
@@ -88,6 +91,8 @@ bool hashx_compile_x86(const hashx_program* program, uint8_t* code) {
        uint8_t* target = NULL;
        EMIT(pos, x86_prologue);
        for (size_t i = 0; i < program->code_size; ++i) {
+               if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE)
+                       return false;
                const instruction* instr = &program->code[i];
                switch (instr->opcode)
                {
@@ -145,6 +150,8 @@ bool hashx_compile_x86(const hashx_program* program, uint8_t* code) {
                        UNREACHABLE;
                }
        }
+       if (pos + sizeof x86_epilogue > code + COMP_CODE_SIZE)
+               return false;
        EMIT(pos, x86_epilogue);
        return hashx_vm_rx(code, COMP_CODE_SIZE);
 }
index 8eb163075a5bd2271704449d076fba5c3cd894ba..5d0896ef5b9cb339294f9f0418c5f132ca3dea9f 100644 (file)
@@ -376,4 +376,622 @@ mod tests {
         assert_eq!(ctx.exec(12345).unwrap(), hex!("825a9b6dd5d074af"));
         assert_eq!(*counter.borrow(), 575);
     }
+
+    #[test]
+    fn rng_large_compiler_output() {
+        // This is really a general HashX test rather than a test for the Rust
+        // wrapper. It's easier to implement here than in hashx-test, since
+        // the Rng callback is disabled by default in the cmake build system.
+        //
+        // The purpose of this test is to use a specially crafted Rng sequence
+        // to generate an especially large compiled hash program, to test for
+        // length-related problems.
+        //
+        // There are various ways to generate these Rng sequences. The fuzzer
+        // in Arti will do this on its own. The sequence here was found with
+        // a simple ad-hoc optimizer that modifies one byte at a time in a
+        // search for peaks in either x86_64 or aarch64 code size.
+        //
+        // The expected compiled program length:
+        //
+        //  - On x86_64, 3188 bytes
+        //    (safely less than a page still)
+        //
+        //  - On aarch64, 4388 bytes
+        //    (would overflow a single page buffer by 292 bytes)
+        //
+
+        const SEQUENCE: [u64; 558] = [
+            0xffffffffffffffff, // 0
+            0xffffffffffffffff, // 1
+            0xfbfefefbfbfeffff, // 2
+            0xffffffffffffffff, // 3
+            0xffffffffffffffff, // 4
+            0xfffffffffffffdff, // 5
+            0xffffffffffffffff, // 6
+            0xffffffffffffffff, // 7
+            0xfffffffefffffffd, // 8
+            0xffffffffffffffff, // 9
+            0xffffffffffffffff, // 10
+            0xffffffffffffffff, // 11
+            0xfefffffeffffffff, // 12
+            0xffffffffffffffff, // 13
+            0xffffffffffffffff, // 14
+            0xfefbfcfdfefffefb, // 15
+            0xfffffffffffffffc, // 16
+            0xffffffffffffffff, // 17
+            0xffffffffffffffff, // 18
+            0xffffffffffffffff, // 19
+            0xffffffffffffffff, // 20
+            0xfffffffffffefffe, // 21
+            0xfffffefffbfefbfe, // 22
+            0xffffffffffffffff, // 23
+            0xfefeffffffffffff, // 24
+            0xffffffffffffffff, // 25
+            0xffffffffffffffff, // 26
+            0xffffffffffffffff, // 27
+            0xffffffffffffffff, // 28
+            0xffffffffffffffff, // 29
+            0xffffffffffffffff, // 30
+            0xffffffffffffffff, // 31
+            0xffffffffffffffff, // 32
+            0xffffffffffffffff, // 33
+            0xfffffffeffffffff, // 34
+            0xffffffffffffffff, // 35
+            0xfffffffffffffffe, // 36
+            0xffffffffffffffff, // 37
+            0xfbfbfffefffbffff, // 38
+            0xffffffffffffffff, // 39
+            0xfffffffffffffffe, // 40
+            0xffffffffffffffff, // 41
+            0xffffffffffffffff, // 42
+            0xffffffffffffffff, // 43
+            0xffffffffffffffff, // 44
+            0xfffffffeffffffff, // 45
+            0xffffffffffffffff, // 46
+            0xffffffffffffffff, // 47
+            0xffffffffffffffff, // 48
+            0xfefefffdffffffff, // 49
+            0xfefbfefefefcfdff, // 50
+            0xffffffffffffffff, // 51
+            0xffffffffffffffff, // 52
+            0xffffffffffffffff, // 53
+            0xffffffffffffffff, // 54
+            0xfefffffffefefffc, // 55
+            0xfffffffeffffffff, // 56
+            0xfbfefffefbfefefb, // 57
+            0xfffffffeffffffff, // 58
+            0xffffffffffffffff, // 59
+            0xfffffffffffffefc, // 60
+            0xfffffffffffffffc, // 61
+            0xffffffffffffffff, // 62
+            0xffffffffffffffff, // 63
+            0xffffffffffffffff, // 64
+            0xfffffefdffffffff, // 65
+            0xffffffffffffffff, // 66
+            0xffffffffffffffff, // 67
+            0xffffffffffffffff, // 68
+            0xfefbfefbfefbfbfe, // 69
+            0xffffffffffffffff, // 70
+            0xffffffffffffffff, // 71
+            0xfffefeffffffffff, // 72
+            0xfffffffffffffffe, // 73
+            0xffffffffffffffff, // 74
+            0xffffffffffffffff, // 75
+            0xfeffffffffffffff, // 76
+            0xffffffffffffffff, // 77
+            0xffffffffffffffff, // 78
+            0xffffffffffffffff, // 79
+            0xffffffffffffffff, // 80
+            0xffffffffffffffff, // 81
+            0xfffffffefcfdfeff, // 82
+            0xffffffffffffffff, // 83
+            0xfefeffffffffffff, // 84
+            0xffffffffffffffff, // 85
+            0xffffffffffffffff, // 86
+            0xffffffffffffffff, // 87
+            0xfffffffdffffffff, // 88
+            0xffffffffffffffff, // 89
+            0xffffffffffffffff, // 90
+            0xffffffffffffffff, // 91
+            0xfefbfffefefbfbfe, // 92
+            0xffffffffffffffff, // 93
+            0xfffffffeffffffff, // 94
+            0xfffffffffefeffff, // 95
+            0xffffffffffffffff, // 96
+            0xfffffffffffffffe, // 97
+            0xffffffffffffffff, // 98
+            0xffffffffffffffff, // 99
+            0xffffffffffffffff, // 100
+            0xfffffffffffffffe, // 101
+            0xfffffffffeffffff, // 102
+            0xfdfdffffffffffff, // 103
+            0xfbfefbfefefefefe, // 104
+            0xffffffffffffffff, // 105
+            0xffffffffffffffff, // 106
+            0xfffffffffffffffd, // 107
+            0xfefffffffffefdff, // 108
+            0xfffffffffefffffe, // 109
+            0xfffffffffffffffe, // 110
+            0xffffffffffffffff, // 111
+            0xffffffffffffffff, // 112
+            0xfbfefef8fffefefb, // 113
+            0xfffffffcffffffff, // 114
+            0xfefefefdffffffff, // 115
+            0xffffffffffffffff, // 116
+            0xfffffffdffffffff, // 117
+            0xfffffffffdfdfdfb, // 118
+            0xffffffffffffffff, // 119
+            0xfffdfdffffffffff, // 120
+            0xffffffffffffffff, // 121
+            0xffffffffffffffff, // 122
+            0xfffffffffffffffd, // 123
+            0xfdfffefffffcfffe, // 124
+            0xfcfefffffffefeff, // 125
+            0xffffffffffffffff, // 126
+            0xffffffffffffffff, // 127
+            0xffffffffffffffff, // 128
+            0xfffbf8f8fbf8fefe, // 129
+            0xfffffffffefcfdff, // 130
+            0xfffffffffffffffd, // 131
+            0xffffffffffffffff, // 132
+            0xfffffffffcfcffff, // 133
+            0xffffffffffffffff, // 134
+            0xffffffffffffffff, // 135
+            0xfffffffffdfefdff, // 136
+            0xffffffffffffffff, // 137
+            0xfcfefbfdfffffffe, // 138
+            0xfffffffffeffffff, // 139
+            0xf8fbfefefefffeff, // 140
+            0xffffffffffffffff, // 141
+            0xfefefefffefffffe, // 142
+            0xffffffffffffffff, // 143
+            0xfffffffffcfefeff, // 144
+            0xffffffffffffffff, // 145
+            0xfffffffffffffffe, // 146
+            0xfffffffffffffffe, // 147
+            0xffffffffffffffff, // 148
+            0xfffffffffefffeff, // 149
+            0xfffefffeffffffff, // 150
+            0xffffffffffffffff, // 151
+            0xffffffffffffffff, // 152
+            0xfffffbfefffffcff, // 153
+            0xffffffffffffffff, // 154
+            0xfdfefefaffffffff, // 155
+            0xffffffffffffffff, // 156
+            0xfffffffffffffffd, // 157
+            0xfffffffffffffffe, // 158
+            0xffffffffffffffff, // 159
+            0xffffffffffffffff, // 160
+            0xfdfefefbfffbfffe, // 161
+            0xfffffffefffffffe, // 162
+            0xffffffffffffffff, // 163
+            0xffffffffffffffff, // 164
+            0xfeffffffffffffff, // 165
+            0xfffdfffdffffffff, // 166
+            0xfffffffdffffffff, // 167
+            0xfeffffffffffffff, // 168
+            0xffffffffffffffff, // 169
+            0xffffffffffffffff, // 170
+            0xffffffffffffffff, // 171
+            0xfcfffefefffefbfe, // 172
+            0xffffffffffffffff, // 173
+            0xfffffffffffeffff, // 174
+            0xffffffffffffffff, // 175
+            0xfffffffffffffffe, // 176
+            0xfffffffffdfefdfd, // 177
+            0xffffffffffffffff, // 178
+            0xffffffffffffffff, // 179
+            0xfffffffdffffffff, // 180
+            0xffffffffffffffff, // 181
+            0xffffffffffffffff, // 182
+            0xffffffffffffffff, // 183
+            0xffffffffffffffff, // 184
+            0xfbfffefffefefbfd, // 185
+            0xfffffffffffeffff, // 186
+            0xffffffffffffffff, // 187
+            0xffffffffffffffff, // 188
+            0xffffffffffffffff, // 189
+            0xffffffffffffffff, // 190
+            0xfffdfeffffffffff, // 191
+            0xffffffffffffffff, // 192
+            0xfffffffeffffffff, // 193
+            0xffffffffffffffff, // 194
+            0xffffffffffffffff, // 195
+            0xfffffffefeffffff, // 196
+            0xfcfefff8fefffbfe, // 197
+            0xffffffffffffffff, // 198
+            0xffffffffffffffff, // 199
+            0xffffffffffffffff, // 200
+            0xffffffffffffffff, // 201
+            0xffffffffffffffff, // 202
+            0xffffffffffffffff, // 203
+            0xffffffffffffffff, // 204
+            0xfbfbfefbfefefeff, // 205
+            0xffffffffffffffff, // 206
+            0xfffeffffffffffff, // 207
+            0xffffffffffffffff, // 208
+            0xffffffffffffffff, // 209
+            0xffffffffffffffff, // 210
+            0xffffffffffffffff, // 211
+            0xffffffffffffffff, // 212
+            0xfffffffffefeffff, // 213
+            0xfefefefeffffffff, // 214
+            0xffffffffffffffff, // 215
+            0xffffffffffffffff, // 216
+            0xfffffffffefeffff, // 217
+            0xfbfefbfefffefefb, // 218
+            0xffffffffffffffff, // 219
+            0xfffffffffffffffe, // 220
+            0xfffffffefdfffefe, // 221
+            0xffffffffffffffff, // 222
+            0xffffffffffffffff, // 223
+            0xffffffffffffffff, // 224
+            0xfffefffcffffffff, // 225
+            0xfffffefffffdfdff, // 226
+            0xfffefeffffffffff, // 227
+            0xfffffeffffffffff, // 228
+            0xffffffffffffffff, // 229
+            0xfffffffffefefefd, // 230
+            0xfcfdfefffefffffe, // 231
+            0xfefdffffffffffff, // 232
+            0xfffffffeffffffff, // 233
+            0xfdfefdffffffffff, // 234
+            0xffffffffffffffff, // 235
+            0xfdfefffeffffffff, // 236
+            0xffffffffffffffff, // 237
+            0xffffffffffffffff, // 238
+            0xfbfffffefbfefefe, // 239
+            0xfefcfdffffffffff, // 240
+            0xfffffffffffffffe, // 241
+            0xfffffffefefdfefd, // 242
+            0xffffffffffffffff, // 243
+            0xfffeffffffffffff, // 244
+            0xffffffffffffffff, // 245
+            0xfffffffeffffffff, // 246
+            0xffffffffffffffff, // 247
+            0xfffffffffefefeff, // 248
+            0xfffffffdfefffefe, // 249
+            0xfffefeffffffffff, // 250
+            0xffffffffffffffff, // 251
+            0xfbfbfefefefbfffe, // 252
+            0xffffffffffffffff, // 253
+            0xfffffffeffffffff, // 254
+            0xfffffffeffffffff, // 255
+            0xfefffeffffffffff, // 256
+            0xfffffdffffffffff, // 257
+            0xffffffffffffffff, // 258
+            0xffffffffffffffff, // 259
+            0xfffffffffdfffdff, // 260
+            0xfffffffffefffffe, // 261
+            0xfefffffffffffefe, // 262
+            0xfefffcfdfffefefb, // 263
+            0xffffffffffffffff, // 264
+            0xffffffffffffffff, // 265
+            0xffffffffffffffff, // 266
+            0xfffffffffeffffff, // 267
+            0xffffffffffffffff, // 268
+            0xffffffffffffffff, // 269
+            0xffffffffffffffff, // 270
+            0xfefbfefbfbfefefe, // 271
+            0xfffffffffffffdff, // 272
+            0xfffffffffffffffe, // 273
+            0xffffffffffffffff, // 274
+            0xffffffffffffffff, // 275
+            0xffffffffffffffff, // 276
+            0xffffffffffffffff, // 277
+            0xffffffffffffffff, // 278
+            0xffffffffffffffff, // 279
+            0xfffffcfcfffffeff, // 280
+            0xffffffffffffffff, // 281
+            0xfbf8fefefbfbfeff, // 282
+            0xfffffffffffffffe, // 283
+            0xfffffffffffffffe, // 284
+            0xffffffffffffffff, // 285
+            0xffffffffffffffff, // 286
+            0xffffffffffffffff, // 287
+            0xffffffffffffffff, // 288
+            0xffffffffffffffff, // 289
+            0xffffffffffffffff, // 290
+            0xffffffffffffffff, // 291
+            0xffffffffffffffff, // 292
+            0xffffffffffffffff, // 293
+            0xffffffffffffffff, // 294
+            0xffffffffffffffff, // 295
+            0xfefefdfcfdfefffe, // 296
+            0xfffffffeffffffff, // 297
+            0xffffffffffffffff, // 298
+            0xfffffeffffffffff, // 299
+            0xffffffffffffffff, // 300
+            0xfffefffffefefffe, // 301
+            0xfffffffeffffffff, // 302
+            0xffffffffffffffff, // 303
+            0xfbfffefefbfefffe, // 304
+            0xffffffffffffffff, // 305
+            0xfffffffffffeffff, // 306
+            0xffffffffffffffff, // 307
+            0xfffeffffffffffff, // 308
+            0xffffffffffffffff, // 309
+            0xffffffffffffffff, // 310
+            0xffffffffffffffff, // 311
+            0xffffffffffffffff, // 312
+            0xffffffffffffffff, // 313
+            0xffffffffffffffff, // 314
+            0xffffffffffffffff, // 315
+            0xfffffffeffffffff, // 316
+            0xfbfefbfbfefbfeff, // 317
+            0xffffffffffffffff, // 318
+            0xfffffffefefeffff, // 319
+            0xfffffffeffffffff, // 320
+            0xffffffffffffffff, // 321
+            0xffffffffffffffff, // 322
+            0xffffffffffffffff, // 323
+            0xffffffffffffffff, // 324
+            0xffffffffffffffff, // 325
+            0xffffffffffffffff, // 326
+            0xffffffffffffffff, // 327
+            0xffffffffffffffff, // 328
+            0xfffffffffefefeff, // 329
+            0xfefefefefbfdfeff, // 330
+            0xffffffffffffffff, // 331
+            0xffffffffffffffff, // 332
+            0xfffffffffeffffff, // 333
+            0xffffffffffffffff, // 334
+            0xfefffffffffffffe, // 335
+            0xfcfbfefffefbfefe, // 336
+            0xfffffffffffefeff, // 337
+            0xffffffffffffffff, // 338
+            0xffffffffffffffff, // 339
+            0xfeffffffffffffff, // 340
+            0xfffdfeffffffffff, // 341
+            0xffffffffffffffff, // 342
+            0xffffffffffffffff, // 343
+            0xffffffffffffffff, // 344
+            0xffffffffffffffff, // 345
+            0xfffffffdffffffff, // 346
+            0xffffffffffffffff, // 347
+            0xfefbfbfefbfeffff, // 348
+            0xffffffffffffffff, // 349
+            0xffffffffffffffff, // 350
+            0xffffffffffffffff, // 351
+            0xffffffffffffffff, // 352
+            0xffffffffffffffff, // 353
+            0xffffffffffffffff, // 354
+            0xffffffffffffffff, // 355
+            0xfffffffeffffffff, // 356
+            0xffffffffffffffff, // 357
+            0xffffffffffffffff, // 358
+            0xfefbfefffefffbff, // 359
+            0xffffffffffffffff, // 360
+            0xfefffffffffffffe, // 361
+            0xffffffffffffffff, // 362
+            0xffffffffffffffff, // 363
+            0xffffffffffffffff, // 364
+            0xfffffefdffffffff, // 365
+            0xfffffffeffffffff, // 366
+            0xffffffffffffffff, // 367
+            0xfffefefefffffffe, // 368
+            0xfffffffffffffffe, // 369
+            0xfffffffffffffffc, // 370
+            0xfcfdfffefefbfffe, // 371
+            0xfcfdfcfcfffffffe, // 372
+            0xffffffffffffffff, // 373
+            0xffffffffffffffff, // 374
+            0xffffffffffffffff, // 375
+            0xfdfdfffeffffffff, // 376
+            0xfffffffffffffeff, // 377
+            0xfffffffeffffffff, // 378
+            0xfbfefefbfbfefefb, // 379
+            0xfffffffdffffffff, // 380
+            0xffffffffffffffff, // 381
+            0xffffffffffffffff, // 382
+            0xffffffffffffffff, // 383
+            0xffffffffffffffff, // 384
+            0xffffffffffffffff, // 385
+            0xffffffffffffffff, // 386
+            0xfffffffffffffffe, // 387
+            0xfffffffffffffffe, // 388
+            0xffffffffffffffff, // 389
+            0xffffffffffffffff, // 390
+            0xffffffffffffffff, // 391
+            0xfefefbfbfefffeff, // 392
+            0xfffffffffffffffe, // 393
+            0xffffffffffffffff, // 394
+            0xfffffffffffffffd, // 395
+            0xffffffffffffffff, // 396
+            0xffffffffffffffff, // 397
+            0xffffffffffffffff, // 398
+            0xfffeffffffffffff, // 399
+            0xffffffffffffffff, // 400
+            0xffffffffffffffff, // 401
+            0xfffffefeffffffff, // 402
+            0xfefdfcfefffffeff, // 403
+            0xffffffffffffffff, // 404
+            0xfffffffffffffffe, // 405
+            0xffffffffffffffff, // 406
+            0xffffffffffffffff, // 407
+            0xfffffffeffffffff, // 408
+            0xffffffffffffffff, // 409
+            0xfffffffffefeffff, // 410
+            0xfefefbfbfefbfefe, // 411
+            0xfffffffffffefffe, // 412
+            0xffffffffffffffff, // 413
+            0xffffffffffffffff, // 414
+            0xfffffffffffffffe, // 415
+            0xffffffffffffffff, // 416
+            0xffffffffffffffff, // 417
+            0xfffffffffffffffe, // 418
+            0xfffffffffffffffe, // 419
+            0xfffffffffffffffe, // 420
+            0xffffffffffffffff, // 421
+            0xfffffffefffeffff, // 422
+            0xfffffffeffffffff, // 423
+            0xfffffffeffffffff, // 424
+            0xfefefefefefbfbfe, // 425
+            0xfffffffffdfffefb, // 426
+            0xfffffffeffffffff, // 427
+            0xfffffffeffffffff, // 428
+            0xfffdfdfffffffffe, // 429
+            0xfef8fffbfefbfeff, // 430
+            0xffffffffffffffff, // 431
+            0xffffffffffffffff, // 432
+            0xfffffffffffefdfe, // 433
+            0xffffffffffffffff, // 434
+            0xffffffffffffffff, // 435
+            0xffffffffffffffff, // 436
+            0xffffffffffffffff, // 437
+            0xfefffeffffffffff, // 438
+            0xfcfdfefbfffefefb, // 439
+            0xffffffffffffffff, // 440
+            0xffffffffffffffff, // 441
+            0xffffffffffffffff, // 442
+            0xffffffffffffffff, // 443
+            0xfffefeffffffffff, // 444
+            0xffffffffffffffff, // 445
+            0xffffffffffffffff, // 446
+            0xfffffffeffffffff, // 447
+            0xffffffffffffffff, // 448
+            0xffffffffffffffff, // 449
+            0xfefbfbfefffffffe, // 450
+            0xffffffffffffffff, // 451
+            0xfffffffffeffffff, // 452
+            0xffffffffffffffff, // 453
+            0xffffffffffffffff, // 454
+            0xfffffffeffffffff, // 455
+            0xffffffffffffffff, // 456
+            0xffffffffffffffff, // 457
+            0xffffffffffffffff, // 458
+            0xffffffffffffffff, // 459
+            0xfffffffefffffffe, // 460
+            0xfbfefefbfffbfbfe, // 461
+            0xfffffffffffffffe, // 462
+            0xffffffffffffffff, // 463
+            0xfefdfeffffffffff, // 464
+            0xffffffffffffffff, // 465
+            0xffffffffffffffff, // 466
+            0xffffffffffffffff, // 467
+            0xfefffefeffffffff, // 468
+            0xfffffffffeffffff, // 469
+            0xffffffffffffffff, // 470
+            0xfffffffdffffffff, // 471
+            0xffffffffffffffff, // 472
+            0xfffffffffdfbfbfe, // 473
+            0xfcfdfefffefbfffe, // 474
+            0xfffffffffffdfffe, // 475
+            0xfffffffffefdffff, // 476
+            0xffffffffffffffff, // 477
+            0xfefffffeffffffff, // 478
+            0xfdfffefdfefffefd, // 479
+            0xffffffffffffffff, // 480
+            0xfffbfefbfefbfefb, // 481
+            0xfbfcfdfdffffffff, // 482
+            0xfffffffffffffffe, // 483
+            0xfffffffffffffffe, // 484
+            0xffffffffffffffff, // 485
+            0xfffffffffffffffe, // 486
+            0xfffffefffffffffe, // 487
+            0xffffffffffffffff, // 488
+            0xffffffffffffffff, // 489
+            0xffffffffffffffff, // 490
+            0xffffffffffffffff, // 491
+            0xffffffffffffffff, // 492
+            0xffffffffffffffff, // 493
+            0xffffffffffffffff, // 494
+            0xfbfefefbfffef8fe, // 495
+            0xffffffffffffffff, // 496
+            0xffffffffffffffff, // 497
+            0xffffffffffffffff, // 498
+            0xffffffffffffffff, // 499
+            0xfffffffeffffffff, // 500
+            0xffffffffffffffff, // 501
+            0xfffffffffffffffe, // 502
+            0xffffffffffffffff, // 503
+            0xfffffffffffffffe, // 504
+            0xffffffffffffffff, // 505
+            0xfffffffffffffffe, // 506
+            0xfcfdfffffefefbff, // 507
+            0xffffffffffffffff, // 508
+            0xffffffffffffffff, // 509
+            0xffffffffffffffff, // 510
+            0xffffffffffffffff, // 511
+            0xffffffffffffffff, // 512
+            0xfefbfefefefefbfe, // 513
+            0xffffffffffffffff, // 514
+            0xfffffeffffffffff, // 515
+            0xffffffffffffffff, // 516
+            0xfffffffeffffffff, // 517
+            0xfffffffeffffffff, // 518
+            0xfffffffeffffffff, // 519
+            0xfffffffefefeffff, // 520
+            0xffffffffffffffff, // 521
+            0xfefbfbfefbfefefb, // 522
+            0xffffffffffffffff, // 523
+            0xffffffffffffffff, // 524
+            0xffffffffffffffff, // 525
+            0xffffffffffffffff, // 526
+            0xffffffffffffffff, // 527
+            0xffffffffffffffff, // 528
+            0xffffffffffffffff, // 529
+            0xffffffffffffffff, // 530
+            0xffffffffffffffff, // 531
+            0xffffffffffffffff, // 532
+            0xffffffffffffffff, // 533
+            0xfffefefbfcfdfeff, // 534
+            0xffffffffffffffff, // 535
+            0xffffffffffffffff, // 536
+            0xffffffffffffffff, // 537
+            0xffffffffffffffff, // 538
+            0xffffffffffffffff, // 539
+            0xffffffffffffffff, // 540
+            0xffffffffffffffff, // 541
+            0xffffffffffffffff, // 542
+            0xfbfbfefffefefbfb, // 543
+            0xffffffffffffffff, // 544
+            0xffffffffffffffff, // 545
+            0xffffffffffffffff, // 546
+            0xffffffffffffffff, // 547
+            0xffffffffffffffff, // 548
+            0xffffffffffffffff, // 549
+            0xffffffffffffffff, // 550
+            0xffffffffffffffff, // 551
+            0xffffffffffffffff, // 552
+            0xfefefbffffffffff, // 553
+            0xffffffffffffffff, // 554
+            0xffffffffffffffff, // 555
+            0xffffffffffffffff, // 556
+            0xffffffffffffffff, // 557
+        ];
+
+        // Do a test run against the interpreter, then check the compiler.
+        for hash_type in [
+            HashXType::HASHX_TYPE_INTERPRETED,
+            HashXType::HASHX_TYPE_COMPILED,
+        ] {
+            let mut ctx = HashX::new(hash_type);
+
+            // Fully replace the Rng stream, which must be exactly the right size
+            let counter = Arc::new(RefCell::new(0_usize));
+            {
+                let counter = counter.clone();
+                ctx.rng_callback(Some(Box::new(move |_value| {
+                    let mut counter = counter.borrow_mut();
+                    let result = SEQUENCE[*counter];
+                    *counter += 1;
+                    result
+                })));
+            }
+
+            // Seed choice: This seed will normally fail constraint checks.
+            // Using it here is a way of verifying that Rng replacement works.
+            assert_eq!(*counter.borrow(), 0);
+            assert_eq!(ctx.make(b"qfjsfv"), HashXResult::HASHX_OK);
+            assert_eq!(*counter.borrow(), SEQUENCE.len());
+            assert_eq!(ctx.query_type(), Ok(hash_type));
+
+            // Make sure we can run the hash function, spot-testing the output.
+            assert_eq!(ctx.exec(0).unwrap(), hex!("7d7442b95fc9ea3d"));
+            assert_eq!(ctx.exec(123).unwrap(), hex!("1519ee923bf1e699"));
+            assert_eq!(ctx.exec(12345).unwrap(), hex!("726c4073ff1bb595"));
+        }
+    }
 }