harness.c (3153B)
1 /* 2 * harness.c: the harness the flake's probe check runs under both 3 * instruments. 4 * 5 * Copyright (c) 2026 Jared Tobin 6 * License: MIT 7 * 8 * Its secret, the first argument in hex (of one width for every 9 * secret, so that runs lay out alike), reaches a loop's bound, a 10 * table index, which of two calls a helper returns to, a dividend, 11 * a divisor, a floating-point division (outside either ISA's 12 * data-independent-timing contract), and, on a path the third secret 13 * alone takes, another table index; a constant-time select reaches 14 * none of them. 15 */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 19 #include "vestigia.h" 20 21 static unsigned char table[256]; 22 static volatile unsigned modulus = 3329; 23 24 __attribute__((noinline)) unsigned branchy(unsigned s) { 25 unsigned r = 0; 26 for (unsigned i = 0; i < (s & 7); i++) r += i; 27 return r; 28 } 29 30 __attribute__((noinline)) unsigned lookup(unsigned s) { 31 return table[s & 0xff]; 32 } 33 34 __attribute__((noinline)) unsigned leaf(unsigned x) { 35 return x * 3u + 1u; 36 } 37 38 /* leaf runs eight times whatever the secret, but returns to one call 39 or the other as the secret's bits say */ 40 __attribute__((noinline)) unsigned calls(unsigned s) { 41 unsigned r = 0; 42 for (unsigned i = 0; i < 8; i++) { 43 if ((s >> i) & 1u) r += leaf(i); 44 else r ^= leaf(i + 1u); 45 } 46 return r; 47 } 48 49 /* a secret divided by a public modulus, the divisor in a register */ 50 __attribute__((noinline)) unsigned divide(unsigned s) { 51 #if defined(__x86_64__) 52 unsigned q, r; 53 __asm__ volatile("divl %4" 54 : "=a"(q), "=d"(r) 55 : "a"(s * 2654435761u), "d"(0u), "r"(modulus)); 56 return q ^ r; 57 #else 58 return (s * 2654435761u) / modulus; 59 #endif 60 } 61 62 /* a public value divided by a secret, which x86_64 reads from memory 63 as the division's operand */ 64 __attribute__((noinline)) unsigned divide_memory(unsigned s) { 65 unsigned d = (s & 0xffu) | 1u; 66 #if defined(__x86_64__) 67 unsigned q, r; 68 __asm__ volatile("divl %4" 69 : "=a"(q), "=d"(r) 70 : "a"(1000003u), "d"(0u), "m"(d)); 71 return q ^ r; 72 #else 73 return 1000003u / d; 74 #endif 75 } 76 77 /* a secret divided in floating point, which neither Arm's DIT nor 78 Intel's DOITM covers */ 79 __attribute__((noinline)) unsigned fpdivide(unsigned s) { 80 return (unsigned)((double)s / 7.0); 81 } 82 83 /* a table index on a path one secret takes */ 84 __attribute__((noinline)) unsigned rare(unsigned s) { 85 if ((s & 0xffu) == 0xc3u) return table[(s >> 1) & 0xffu]; 86 return 0; 87 } 88 89 __attribute__((noinline)) unsigned ct(unsigned s, unsigned p) { 90 unsigned m = 0u - (p & 1u); 91 return (s & m) | (~s & ~m); 92 } 93 94 int main(int argc, char **argv) { 95 unsigned s = (unsigned)strtoul(argc > 1 ? argv[1] : "0", NULL, 16); 96 unsigned out[8]; 97 for (int i = 0; i < 256; i++) table[i] = (unsigned char)i; 98 vestigia_secret(&s, sizeof s); 99 out[0] = branchy(s); 100 out[1] = lookup(s); 101 out[2] = calls(s); 102 out[3] = divide(s); 103 out[4] = divide_memory(s); 104 out[5] = rare(s); 105 out[6] = ct(s, 1); 106 out[7] = fpdivide(s); 107 vestigia_public(out, sizeof out); 108 printf("%u %u %u %u %u %u %u %u\n", out[0], out[1], out[2], out[3], 109 out[4], out[5], out[6], out[7]); 110 return 0; 111 }