From a94ce2527754cb1bff82a1257ed641cfa7240ee0 Mon Sep 17 00:00:00 2001 From: Micah Elizabeth Scott Date: Fri, 11 Aug 2023 14:34:05 -0700 Subject: [PATCH] hashx: Fix rare compiler output overflow on aarch64 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 --- src/ext/equix/hashx/src/compiler.h | 53 ++- src/ext/equix/hashx/src/compiler_a64.c | 7 + src/ext/equix/hashx/src/compiler_x86.c | 7 + src/ext/equix/src/lib.rs | 618 +++++++++++++++++++++++++ 4 files changed, 678 insertions(+), 7 deletions(-) diff --git a/src/ext/equix/hashx/src/compiler.h b/src/ext/equix/hashx/src/compiler.h index f248e8c1ea..b7b47dfcb5 100644 --- a/src/ext/equix/hashx/src/compiler.h +++ b/src/ext/equix/hashx/src/compiler.h @@ -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 diff --git a/src/ext/equix/hashx/src/compiler_a64.c b/src/ext/equix/hashx/src/compiler_a64.c index 1b7081f537..c8a28661bb 100644 --- a/src/ext/equix/hashx/src/compiler_a64.c +++ b/src/ext/equix/hashx/src/compiler_a64.c @@ -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; diff --git a/src/ext/equix/hashx/src/compiler_x86.c b/src/ext/equix/hashx/src/compiler_x86.c index 12f59a1d0b..df4fdbebb8 100644 --- a/src/ext/equix/hashx/src/compiler_x86.c +++ b/src/ext/equix/hashx/src/compiler_x86.c @@ -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); } diff --git a/src/ext/equix/src/lib.rs b/src/ext/equix/src/lib.rs index 8eb163075a..5d0896ef5b 100644 --- a/src/ext/equix/src/lib.rs +++ b/src/ext/equix/src/lib.rs @@ -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")); + } + } }