Revision 493d130bb523940efde89a74951e7a449fec93b0 authored by Aymeric Fromherz on 24 March 2020, 14:39:08 UTC, committed by Aymeric Fromherz on 24 March 2020, 14:39:08 UTC
2 parent s 24d3821 + 26c43ab
Raw File
Hacl_Chacha20.c
/* MIT License
 *
 * Copyright (c) 2016-2020 INRIA, CMU and Microsoft Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include "Hacl_Chacha20.h"

u32
Hacl_Impl_Chacha20_Vec_chacha20_constants[4U] =
  { (u32)0x61707865U, (u32)0x3320646eU, (u32)0x79622d32U, (u32)0x6b206574U };

static inline void quarter_round(u32 *st, u32 a, u32 b, u32 c, u32 d)
{
  u32 sta0 = st[a];
  u32 stb0 = st[b];
  u32 std0 = st[d];
  u32 sta10 = sta0 + stb0;
  u32 std10 = std0 ^ sta10;
  u32 std20 = std10 << (u32)16U | std10 >> (u32)16U;
  u32 sta2;
  u32 stb1;
  u32 std3;
  u32 sta11;
  u32 std11;
  u32 std21;
  u32 sta3;
  u32 stb2;
  u32 std4;
  u32 sta12;
  u32 std12;
  u32 std22;
  u32 sta;
  u32 stb;
  u32 std;
  u32 sta1;
  u32 std1;
  u32 std2;
  st[a] = sta10;
  st[d] = std20;
  sta2 = st[c];
  stb1 = st[d];
  std3 = st[b];
  sta11 = sta2 + stb1;
  std11 = std3 ^ sta11;
  std21 = std11 << (u32)12U | std11 >> (u32)20U;
  st[c] = sta11;
  st[b] = std21;
  sta3 = st[a];
  stb2 = st[b];
  std4 = st[d];
  sta12 = sta3 + stb2;
  std12 = std4 ^ sta12;
  std22 = std12 << (u32)8U | std12 >> (u32)24U;
  st[a] = sta12;
  st[d] = std22;
  sta = st[c];
  stb = st[d];
  std = st[b];
  sta1 = sta + stb;
  std1 = std ^ sta1;
  std2 = std1 << (u32)7U | std1 >> (u32)25U;
  st[c] = sta1;
  st[b] = std2;
}

static inline void double_round(u32 *st)
{
  quarter_round(st, (u32)0U, (u32)4U, (u32)8U, (u32)12U);
  quarter_round(st, (u32)1U, (u32)5U, (u32)9U, (u32)13U);
  quarter_round(st, (u32)2U, (u32)6U, (u32)10U, (u32)14U);
  quarter_round(st, (u32)3U, (u32)7U, (u32)11U, (u32)15U);
  quarter_round(st, (u32)0U, (u32)5U, (u32)10U, (u32)15U);
  quarter_round(st, (u32)1U, (u32)6U, (u32)11U, (u32)12U);
  quarter_round(st, (u32)2U, (u32)7U, (u32)8U, (u32)13U);
  quarter_round(st, (u32)3U, (u32)4U, (u32)9U, (u32)14U);
}

static inline void rounds(u32 *st)
{
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
  double_round(st);
}

static inline void chacha20_core(u32 *k, u32 *ctx, u32 ctr)
{
  u32 ctr_u32;
  memcpy(k, ctx, (u32)16U * sizeof (ctx[0U]));
  ctr_u32 = ctr;
  k[12U] = k[12U] + ctr_u32;
  rounds(k);
  {
    u32 i;
    for (i = (u32)0U; i < (u32)16U; i++)
    {
      u32 *os = k;
      u32 x = k[i] + ctx[i];
      os[i] = x;
    }
  }
  k[12U] = k[12U] + ctr_u32;
}

static u32
chacha20_constants[4U] =
  { (u32)0x61707865U, (u32)0x3320646eU, (u32)0x79622d32U, (u32)0x6b206574U };

static inline void chacha20_init(u32 *ctx, u8 *k, u8 *n1, u32 ctr)
{
  u32 *uu____0 = ctx;
  u32 *uu____1;
  u32 *uu____2;
  u32 i;
  {
    u32 i0;
    for (i0 = (u32)0U; i0 < (u32)4U; i0++)
    {
      u32 *os = uu____0;
      u32 x = chacha20_constants[i0];
      os[i0] = x;
    }
  }
  uu____1 = ctx + (u32)4U;
  {
    u32 i0;
    for (i0 = (u32)0U; i0 < (u32)8U; i0++)
    {
      u32 *os = uu____1;
      u8 *bj = k + i0 * (u32)4U;
      u32 u = load32_le(bj);
      u32 r = u;
      u32 x = r;
      os[i0] = x;
    }
  }
  ctx[12U] = ctr;
  uu____2 = ctx + (u32)13U;
  for (i = (u32)0U; i < (u32)3U; i++)
  {
    u32 *os = uu____2;
    u8 *bj = n1 + i * (u32)4U;
    u32 u = load32_le(bj);
    u32 r = u;
    u32 x = r;
    os[i] = x;
  }
}

static inline void chacha20_encrypt_block(u32 *ctx, u8 *out, u32 incr1, u8 *text)
{
  u32 k[16U] = { 0U };
  chacha20_core(k, ctx, incr1);
  {
    u32 bl[16U] = { 0U };
    {
      u32 i;
      for (i = (u32)0U; i < (u32)16U; i++)
      {
        u32 *os = bl;
        u8 *bj = text + i * (u32)4U;
        u32 u = load32_le(bj);
        u32 r = u;
        u32 x = r;
        os[i] = x;
      }
    }
    {
      u32 i;
      for (i = (u32)0U; i < (u32)16U; i++)
      {
        u32 *os = bl;
        u32 x = bl[i] ^ k[i];
        os[i] = x;
      }
    }
    {
      u32 i;
      for (i = (u32)0U; i < (u32)16U; i++)
        store32_le(out + i * (u32)4U, bl[i]);
    }
  }
}

static inline void chacha20_encrypt_last(u32 *ctx, u32 len, u8 *out, u32 incr1, u8 *text)
{
  u8 plain[64U] = { 0U };
  memcpy(plain, text, len * sizeof (text[0U]));
  chacha20_encrypt_block(ctx, plain, incr1, plain);
  memcpy(out, plain, len * sizeof (plain[0U]));
}

static inline void chacha20_update(u32 *ctx, u32 len, u8 *out, u8 *text)
{
  u32 rem1 = len % (u32)64U;
  u32 nb = len / (u32)64U;
  u32 rem2 = len % (u32)64U;
  {
    u32 i;
    for (i = (u32)0U; i < nb; i++)
      chacha20_encrypt_block(ctx, out + i * (u32)64U, i, text + i * (u32)64U);
  }
  if (rem2 > (u32)0U)
    chacha20_encrypt_last(ctx, rem1, out + nb * (u32)64U, nb, text + nb * (u32)64U);
}

void Hacl_Chacha20_chacha20_encrypt(u32 len, u8 *out, u8 *text, u8 *key, u8 *n1, u32 ctr)
{
  u32 ctx[16U] = { 0U };
  chacha20_init(ctx, key, n1, ctr);
  chacha20_update(ctx, len, out, text);
}

void Hacl_Chacha20_chacha20_decrypt(u32 len, u8 *out, u8 *cipher, u8 *key, u8 *n1, u32 ctr)
{
  u32 ctx[16U] = { 0U };
  chacha20_init(ctx, key, n1, ctr);
  chacha20_update(ctx, len, out, cipher);
}

back to top