Week 10

Lecture slides

  • (Last week) intro to constant-time: pdf, key,
  • Constant-time programming in C: pdf, key,
  • Constant-time programming in FaCT: pdf, key,

Code snippets

FaCT example

/*
 FaCT tutorial file
 for CSE 130
 */

/* Basic stuff */

export // functions are not exposed to C without `export` keyword
public int32 simple_fn() { // return value must be `public` or `secret`
  return 5;
}

export
public int32 demo_fn(
    public int32 x, // arguments require a label
    secret mut uint32 y) { // y can be used as an output parameter since it is `mut`

  public int32 z = x + 5; // variables also need a label
  // the following line will cause an error, since z is not `mut`
  // z += 2;

  public mut int32 t = z;
  // this is ok, since t is mutable
  t += 22;

  secret mut uint32 w = 16;

  // error: cannot assign `secret` value to `public` variable
  // w + x is secret because w is secret
  // t = w + (uint32)x;

  // ok: y is secret so it can accept secret expressions
  y = w + (uint32)x;

  // this is an error: the return value is public but w is secret
  // return w;

  // ok: z is public
  return z;
}

export
secret uint32 call_demo_fn(
    public int32 x) {
  secret mut uint32 output = 0; // has to be `mut` since we're passing it to be updated by `demo_fn`
  demo_fn(x, ref output); // `ref` keyword is necessary for mutable arguments
  return output;
}

export
void fill_conditionally(
    public uint32[4] pattern, // fixed length buffer
    secret mut uint8[] buf, // buffer length won't be known until run time
    secret bool b) {
  // loop iterator must be declared in the for loop header
  for (uint32 i = 0; i < len buf; i += 1) { // runtime length of buf via `len` keyword
    // b is secret, so conditional will get transformed
    //   into constant time code during compilation
    if (b) {
      // ok to update buf since it is mutable
      buf[i] = (uint8)pattern[i % 4]; // cast to uint8 so the types match
    }
  }
}

// no export because this is a helper function
void twiddle_bytes(
    secret mut uint8[4] buf) {
  secret uint8 tmp = buf[0];
  buf[0] = buf[2];
  buf[2] = tmp;
  // can't reuse tmp because it was not declared `mut`
  //   (although we could simply change it to be `mut`)
  secret uint8 tmp2 = buf[1];
  buf[1] = buf[3];
  buf[3] = tmp2;
}

void poorly_constructed_hash_fn(
    secret mut uint8[20] out,
    secret uint8[] in) {
  secret mut uint8[20] local = arrzeros(20); // local mutable array, initialized to all zeros
  for (uint32 i = 0; i < len in; i += 1) {
    local[i % len local] += in[i];
  }

  for (uint32 i = 0; i < 20; i += 4) { // incrementing by 4s
    // create a "view" of `local` so that it matches with the signature of `twiddle_bytes`
    twiddle_bytes(ref arrview(local, i, 4)); // view of `local`, starting at index `i`, with a length of 4
  }

  for (uint32 i = 0; i < 20; i += 1) {
    out[i] = local[i];
  }
}


/* More "real" functions */

public int32 conditional_assign(
    secret mut uint8[] x,
    secret uint8[] y,
    secret bool assign) {
  // public branch
  if (len x != len y) {
    return -1;
  }

  // secret branch
  if (assign) {
    for (uint32 i = 0; i < len x; i += 1) {
      x[i] = y[i];
    }
  }

  return 0;
}

// assuming lengths are public and are equal
secret int32 safe_memcmp(secret uint8[] x, secret uint8[] y) {
  for (uint32 i = 0; i < len x; i += 1) {
    if (x[i] != y[i]) {
      return (int32)(x[i] - y[i]);
    }
  }
  return 0;
}

Compiler-introduced branches

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

void mpi_safe_cond_assign(uint8_t *X, const uint8_t *Y, unsigned char assign) {
     size_t i = 0;

    /* make sure assign is 0 or 1 */
    assign = ( assign != 0 );

    X[i] = X[i] * ( 1 - assign ) + Y[i] * assign;
 }

Compiled with clang 3.9.1 with -O2, introduces a branch:

mpi_safe_cond_assign(unsigned char*, unsigned char const*, unsigned char):
        test    dl, dl
        setne   al
        je      .LBB0_2
        mov     dl, byte ptr [rsi]
.LBB0_2:
        or      al, -2
        inc     al
        and     al, byte ptr [rdi]
        add     al, dl
        mov     byte ptr [rdi], al
        ret

Play with this code on godbolt