diff --git a/src/crypto_stream/chacha/common/armv7m/ref/chacha.jinc b/src/crypto_stream/chacha/common/armv7m/ref/chacha.jinc new file mode 100644 index 00000000..8af2aae8 --- /dev/null +++ b/src/crypto_stream/chacha/common/armv7m/ref/chacha.jinc @@ -0,0 +1,3 @@ +require "chacha_state.jinc" +require "chacha_store.jinc" +require "chacha_core.jinc" diff --git a/src/crypto_stream/chacha/common/armv7m/ref/chacha_core.jinc b/src/crypto_stream/chacha/common/armv7m/ref/chacha_core.jinc new file mode 100644 index 00000000..a9cc77cc --- /dev/null +++ b/src/crypto_stream/chacha/common/armv7m/ref/chacha_core.jinc @@ -0,0 +1,160 @@ +// the following implementation requires: +// - (even) param int CHACHA_ROUNDS; +// - inline fn __init_ref(reg u64 nonce key) -> stack u32[16] (check chacha_state.jinc) +// - inline fn __increment_counter_ref(stack u32[16] state) -> stack u32[16] (check chacha_state.jinc) + +fn _copy_state_ref(reg ptr u32[16] k st) -> reg ptr u32[16] +{ + reg u32 i t; + + i = 0; + while(i < 16) + { t = st[(int)i]; + k[(int)i] = t; + i += 1; + } + + return k; +} + +inline fn __line_ref(reg ptr u32[16] k, inline int a b c r) -> reg ptr u32[16] +{ + reg u32 ka kb kc; + + ka = k[a]; + kb = k[b]; + kc = k[c]; + + ka += kb; + kc ^= ka; + kc = #ROR(kc, (32-r)); + + k[a] = ka; + k[c] = kc; + + return k; +} + +inline fn __quarter_round_ref(reg ptr u32[16] k, inline int a b c d) -> reg ptr u32[16] +{ + k = __line_ref(k, a, b, d, 16); + k = __line_ref(k, c, d, b, 12); + k = __line_ref(k, a, b, d, 8); + k = __line_ref(k, c, d, b, 7); + return k; +} + +inline fn __column_round_ref(reg ptr u32[16] k) -> reg ptr u32[16] +{ + k = __quarter_round_ref(k, 0, 4, 8, 12); + k = __quarter_round_ref(k, 1, 5, 9, 13); + k = __quarter_round_ref(k, 2, 6, 10, 14); + k = __quarter_round_ref(k, 3, 7, 11, 15); + return k; +} + +inline fn __diagonal_round_ref(reg ptr u32[16] k) -> reg ptr u32[16] +{ + k = __quarter_round_ref(k, 0, 5, 10, 15); + k = __quarter_round_ref(k, 1, 6, 11, 12); + k = __quarter_round_ref(k, 2, 7, 8, 13); + k = __quarter_round_ref(k, 3, 4, 9, 14); + return k; +} + +// TODO: write compact version of this: line_ref args from inline to reg +inline fn __double_round_ref(reg ptr u32[16] k) -> reg ptr u32[16] +{ + k = __column_round_ref(k); + k = __diagonal_round_ref(k); + return k; +} + +fn _rounds_ref(reg ptr u32[16] k) -> reg ptr u32[16] +{ + reg bool zf; + reg u32 c; + + c = (CHACHA_ROUNDS/2); + while + { k = __double_round_ref(k); + _, zf, _, _, c = #SUBS(c, 1); + } (!zf) + + return k; +} + +fn _sum_states_ref(reg ptr u32[16] k st) -> reg ptr u32[16] +{ + reg u32 i tk tst; + + i = 0; + while(i < 16) + { + tk = k[(int)i]; + tst = st[(int)i]; + tk += tst; + k[(int)i] = tk; + + i += 1; + } + + return k; +} + +inline fn __chacha_xor_ref(reg u32 output plain len nonce key) +{ + stack u32[16] k st; + reg ptr u32[16] kp stp; + + kp = k; + stp = st; + + nonce = nonce; // allow register swap + key = key; // same. + + stp = _init_ref(stp, nonce, key); + + while (len >= 64) + { kp = _copy_state_ref(kp, stp); + kp = _rounds_ref(kp); + output, plain, len = __sum_states_store_xor_ref(output, plain,len, kp, stp); + stp = __increment_counter_ref(stp); + } + + if(len > 0) + { kp = _copy_state_ref(kp, stp); + kp = _rounds_ref(kp); + kp = _sum_states_ref(kp, stp); + __store_xor_last_ref(output, plain, len, kp); + } +} + +inline fn __chacha_ref(reg u32 output len nonce key) +{ + stack u32[16] k st; + reg ptr u32[16] kp stp; + + kp = k; + stp = st; + + nonce = nonce; // allow register swap + key = key; // same. + + stp = _init_ref(stp, nonce, key); + + while (len >= 64) + { kp = _copy_state_ref(kp, stp); + kp = _rounds_ref(kp); + output, len = __sum_states_store_ref(output, len, kp, stp); + stp = __increment_counter_ref(stp); + } + + if(len > 0) + { kp = _copy_state_ref(kp, stp); + kp = _rounds_ref(kp); + kp = _sum_states_ref(kp, stp); + __store_last_ref(output, len, kp); + } +} + diff --git a/src/crypto_stream/chacha/common/armv7m/ref/chacha_state.jinc b/src/crypto_stream/chacha/common/armv7m/ref/chacha_state.jinc new file mode 100644 index 00000000..83fd6d74 --- /dev/null +++ b/src/crypto_stream/chacha/common/armv7m/ref/chacha_state.jinc @@ -0,0 +1,56 @@ + +u32[4] CHACHA_SIGMA = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + +// nonce : 8 bytes +// key : 32 bytes +// counter : 8 bytes (starts at 0) +fn _init_ref(reg ptr u32[16] st, reg u32 nonce key) -> reg ptr u32[16] +{ + // TODO: compress this function + + reg ptr u32[4] sigma; + reg u32 t; + inline int i; + + sigma = CHACHA_SIGMA; + for i=0 to 4 + { t = sigma[i]; + st[i] = t; } + + // reads 8 u32 from pointer key + for i=0 to 8 + { t = (u32)[key + 4*i]; + st[4+i] = t; } + + // 64-bit counter + t = 0; + st[12] = t; + st[13] = t; + + // nonce + t = (u32)[nonce + 0]; + st[14] = t; + t = (u32)[nonce + 4]; + st[15] = t; + + return st; +} + +// TODO: double check here: 64 bit counter +// increments 64-bit counter +inline fn __increment_counter_ref(reg ptr u32[16] st) -> reg ptr u32[16] +{ + reg bool cf; + reg u32 l h; + + l = st[12]; + h = st[13]; + + _, _, cf, _, l = #ADDS(l, 1); + h = #ADDcc(h, 1, cf, h); + + st[12] = l; + st[13] = h; + + return st; +} diff --git a/src/crypto_stream/chacha/common/armv7m/ref/chacha_store.jinc b/src/crypto_stream/chacha/common/armv7m/ref/chacha_store.jinc new file mode 100644 index 00000000..39294c4d --- /dev/null +++ b/src/crypto_stream/chacha/common/armv7m/ref/chacha_store.jinc @@ -0,0 +1,96 @@ + +// store 'xor' //////////////////////////////////////////////////////////////// + +inline fn __update_ptr_xor_ref(reg u32 output plain len, inline int n) -> reg u32, reg u32, reg u32 +{ + output += n; + plain += n; + len -= n; + return output, plain, len; +} + +inline fn __sum_states_store_xor_ref( + reg u32 output plain len, + reg ptr u32[16] k st) + -> + reg u32, reg u32, reg u32 +{ + reg u32 i t s v; + + i = 0; + while(i < 16) + { t = k[(int)i]; + s = st[(int)i]; + v = (u32)[plain + 4*i]; + t += s; + t ^= v; + (u32)[output + 4*i] = t; + i += 1; + } + + output, plain, len = __update_ptr_xor_ref(output, plain, len, 64); + + return output, plain, len; +} + + +// len bytes +inline fn __store_xor_last_ref(reg u32 output plain len, reg ptr u32[16] k) +{ + reg u32 i t v; + + i = 0; + while(i < len) + { t = (32u)k[u8 (int)i]; + v = (32u)(u8)[plain + i]; + t ^= v; + (u8)[output + i] = t; + i += 1; + } +} + +// store ////////////////////////////////////////////////////////////////////// + +inline fn __update_ptr_ref(reg u32 output len, inline int n) -> reg u32, reg u32 +{ + output += n; + len -= n; + return output, len; +} + +inline fn __sum_states_store_ref( + reg u32 output len, + reg ptr u32[16] k st) + -> + reg u32, reg u32 +{ + reg u32 i t s; + + i = 0; + while(i < 16) + { t = k[(int)i]; + s = st[(int)i]; + t += s; + [output + 4*i] = t; + i += 1; + } + + output, len = __update_ptr_ref(output, len, 64); + + return output, len; +} + +// len bytes +inline fn __store_last_ref(reg u32 output len, reg ptr u32[16] k) +{ + reg u32 i t; + + i = 0; + while(i < len) + { t = (32u)k[u8 (int)i]; + (u8)[output + i] = t; + i += 1; + } +} + +