| 1 | module subtle |
| 2 | |
| 3 | // constant_time_byte_eq returns 1 when x == y. |
| 4 | pub fn constant_time_byte_eq(x u8, y u8) int { |
| 5 | return int((u32(x ^ y) - 1) >> 31) |
| 6 | } |
| 7 | |
| 8 | // constant_time_eq returns 1 when x == y. |
| 9 | pub fn constant_time_eq(x int, y int) int { |
| 10 | return int((u64(u32(x ^ y)) - 1) >> 63) |
| 11 | } |
| 12 | |
| 13 | // constant_time_select returns x when v == 1, and y when v == 0. |
| 14 | // it is undefined when v is any other value |
| 15 | pub fn constant_time_select(v int, x int, y int) int { |
| 16 | return (~(v - 1) & x) | ((v - 1) & y) |
| 17 | } |
| 18 | |
| 19 | // constant_time_compare returns 1 when x and y have equal contents. |
| 20 | // The runtime of this function is proportional of the length of x and y. |
| 21 | // It is *NOT* dependent on their content. |
| 22 | pub fn constant_time_compare(x []u8, y []u8) int { |
| 23 | if x.len != y.len { |
| 24 | return 0 |
| 25 | } |
| 26 | mut v := u8(0) |
| 27 | for i in 0 .. x.len { |
| 28 | v |= x[i] ^ y[i] |
| 29 | } |
| 30 | return constant_time_byte_eq(v, 0) |
| 31 | } |
| 32 | |
| 33 | // constant_time_copy copies the contents of y into x, when v == 1. |
| 34 | // When v == 0, x is left unchanged. this function is undefined, when |
| 35 | // v takes any other value |
| 36 | pub fn constant_time_copy(v int, mut x []u8, y []u8) { |
| 37 | if x.len != y.len { |
| 38 | panic('subtle: arrays have different lengths') |
| 39 | } |
| 40 | xmask := u8(v - 1) |
| 41 | ymask := u8(~(v - 1)) |
| 42 | for i := 0; i < x.len; i++ { |
| 43 | x[i] = x[i] & xmask | y[i] & ymask |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | // constant_time_less_or_eq returns 1 if x <= y, and 0 otherwise. |
| 48 | // it is undefined when x or y are negative, or > (2^32 - 1) |
| 49 | pub fn constant_time_less_or_eq(x int, y int) int { |
| 50 | x32 := int(x) |
| 51 | y32 := int(y) |
| 52 | return int(((x32 - y32 - 1) >> 31) & 1) |
| 53 | } |
| 54 | |