LCOV - code coverage report
Current view: top level - src/crypto/x11 - echo.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 122 153 79.7 %
Date: 2026-06-25 07:23:51 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /* $Id: echo.c 227 2010-06-16 17:28:38Z tp $ */
       2             : /*
       3             :  * ECHO implementation.
       4             :  *
       5             :  * ==========================(LICENSE BEGIN)============================
       6             :  *
       7             :  * Copyright (c) 2007-2010  Projet RNRT SAPHIR
       8             :  *
       9             :  * Permission is hereby granted, free of charge, to any person obtaining
      10             :  * a copy of this software and associated documentation files (the
      11             :  * "Software"), to deal in the Software without restriction, including
      12             :  * without limitation the rights to use, copy, modify, merge, publish,
      13             :  * distribute, sublicense, and/or sell copies of the Software, and to
      14             :  * permit persons to whom the Software is furnished to do so, subject to
      15             :  * the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be
      18             :  * included in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      21             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      22             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      23             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      24             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      25             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      26             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      27             :  *
      28             :  * ===========================(LICENSE END)=============================
      29             :  *
      30             :  * @author   Thomas Pornin <thomas.pornin@cryptolog.com>
      31             :  */
      32             : 
      33             : #include <crypto/x11/aes.h>
      34             : #include <crypto/x11/dispatch.h>
      35             : 
      36             : #include <attributes.h>
      37             : 
      38             : #include <cstddef>
      39             : #include <cstring>
      40             : 
      41             : #include "sph_echo.h"
      42             : 
      43             : /*
      44             :  * We can use a 64-bit implementation only if a 64-bit type is available.
      45             :  */
      46             : #ifdef _MSC_VER
      47             : #pragma warning (disable: 4146)
      48             : #endif
      49             : 
      50             : #define T32   SPH_T32
      51             : #define C64   SPH_C64
      52             : 
      53             : namespace sapphire {
      54             : namespace soft_echo {
      55             : namespace {
      56       45320 : void ALWAYS_INLINE MixColumn(sph_u64 W[16][2], int ia, int ib, int ic, int id)
      57             : {
      58      135960 :         for (int n = 0; n < 2; n ++) {
      59       90640 :                 sph_u64 a = W[ia][n];
      60       90640 :                 sph_u64 b = W[ib][n];
      61       90640 :                 sph_u64 c = W[ic][n];
      62       90640 :                 sph_u64 d = W[id][n];
      63       90640 :                 sph_u64 ab = a ^ b;
      64       90640 :                 sph_u64 bc = b ^ c;
      65       90640 :                 sph_u64 cd = c ^ d;
      66      181280 :                 sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U
      67       90640 :                         ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1);
      68      181280 :                 sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U
      69       90640 :                         ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1);
      70      181280 :                 sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U
      71       90640 :                         ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1);
      72       90640 :                 W[ia][n] = abx ^ bc ^ d;
      73       90640 :                 W[ib][n] = bcx ^ a ^ cd;
      74       90640 :                 W[ic][n] = cdx ^ ab ^ d;
      75       90640 :                 W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c;
      76       90640 :         }
      77       45320 : }
      78             : 
      79       11330 : void ALWAYS_INLINE ShiftRows(uint64_t W[16][2])
      80             : {
      81             : #define SHIFT_ROW1(a, b, c, d)   do { \
      82             :                 sph_u64 tmp; \
      83             :                 tmp = W[a][0]; \
      84             :                 W[a][0] = W[b][0]; \
      85             :                 W[b][0] = W[c][0]; \
      86             :                 W[c][0] = W[d][0]; \
      87             :                 W[d][0] = tmp; \
      88             :                 tmp = W[a][1]; \
      89             :                 W[a][1] = W[b][1]; \
      90             :                 W[b][1] = W[c][1]; \
      91             :                 W[c][1] = W[d][1]; \
      92             :                 W[d][1] = tmp; \
      93             :         } while (0)
      94             : 
      95             : #define SHIFT_ROW2(a, b, c, d)   do { \
      96             :                 sph_u64 tmp; \
      97             :                 tmp = W[a][0]; \
      98             :                 W[a][0] = W[c][0]; \
      99             :                 W[c][0] = tmp; \
     100             :                 tmp = W[b][0]; \
     101             :                 W[b][0] = W[d][0]; \
     102             :                 W[d][0] = tmp; \
     103             :                 tmp = W[a][1]; \
     104             :                 W[a][1] = W[c][1]; \
     105             :                 W[c][1] = tmp; \
     106             :                 tmp = W[b][1]; \
     107             :                 W[b][1] = W[d][1]; \
     108             :                 W[d][1] = tmp; \
     109             :         } while (0)
     110             : 
     111             : #define SHIFT_ROW3(a, b, c, d)   SHIFT_ROW1(d, c, b, a)
     112             : 
     113       11330 :         SHIFT_ROW1(1, 5, 9, 13);
     114       11330 :         SHIFT_ROW2(2, 6, 10, 14);
     115       11330 :         SHIFT_ROW3(3, 7, 11, 15);
     116             : 
     117             : #undef SHIFT_ROW1
     118             : #undef SHIFT_ROW2
     119             : #undef SHIFT_ROW3
     120       11330 : }
     121             : } // anonymous namespace
     122             : 
     123       11330 : void FullStateRound(sph_u64 W[16][2], sph_u32& K0, sph_u32& K1, sph_u32& K2, sph_u32& K3)
     124             : {
     125      192610 :         for (int n = 0; n < 16; n ++) {
     126      181280 :                 sph_u64 Wl = W[n][0];
     127      181280 :                 sph_u64 Wh = W[n][1];
     128      181280 :                 sph_u32 X0 = (sph_u32)Wl;
     129      181280 :                 sph_u32 X1 = (sph_u32)(Wl >> 32);
     130      181280 :                 sph_u32 X2 = (sph_u32)Wh;
     131      181280 :                 sph_u32 X3 = (sph_u32)(Wh >> 32);
     132      181280 :                 sph_u32 Y0, Y1, Y2, Y3;
     133      181280 :                 soft_aes::Round(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3);
     134      181280 :                 soft_aes::RoundKeyless(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
     135      181280 :                 W[n][0] = (sph_u64)X0 | ((sph_u64)X1 << 32);
     136      181280 :                 W[n][1] = (sph_u64)X2 | ((sph_u64)X3 << 32);
     137      181280 :                 if ((K0 = T32(K0 + 1)) == 0) {
     138           0 :                         if ((K1 = T32(K1 + 1)) == 0) {
     139           0 :                                 if ((K2 = T32(K2 + 1)) == 0) {
     140           0 :                                         K3 = T32(K3 + 1);
     141           0 :                                 }
     142           0 :                         }
     143           0 :                 }
     144      181280 :         }
     145       11330 : }
     146             : 
     147       11330 : void ShiftAndMix(uint64_t W[16][2])
     148             : {
     149       11330 :         ShiftRows(W);
     150       11330 :         MixColumn(W, 0, 1, 2, 3);
     151       11330 :         MixColumn(W, 4, 5, 6, 7);
     152       11330 :         MixColumn(W, 8, 9, 10, 11);
     153       11330 :         MixColumn(W, 12, 13, 14, 15);
     154       11330 : }
     155             : } // namespace soft_echo
     156             : } // namespace sapphire
     157             : 
     158             : sapphire::dispatch::EchoRoundFn echo_round = sapphire::soft_echo::FullStateRound;
     159             : sapphire::dispatch::EchoShiftMix echo_shift_mix = sapphire::soft_echo::ShiftAndMix;
     160             : 
     161             : #define DECL_STATE_BIG   \
     162             :         alignas(16) sph_u64 W[16][2];
     163             : 
     164             : #define INPUT_BLOCK_BIG(sc)   do { \
     165             :                 unsigned u; \
     166             :                 memcpy(W, sc->u.Vb, 16 * sizeof(sph_u64)); \
     167             :                 for (u = 0; u < 8; u ++) { \
     168             :                         W[u + 8][0] = sph_dec64le_aligned( \
     169             :                                 sc->buf + 16 * u); \
     170             :                         W[u + 8][1] = sph_dec64le_aligned( \
     171             :                                 sc->buf + 16 * u + 8); \
     172             :                 } \
     173             :         } while (0)
     174             : 
     175             : #define BIG_ROUND   do { \
     176             :                 echo_round(W, K0, K1, K2, K3); \
     177             :                 echo_shift_mix(W); \
     178             :         } while (0)
     179             : 
     180             : #define FINAL_BIG   do { \
     181             :                 unsigned u; \
     182             :                 sph_u64 *VV = &sc->u.Vb[0][0]; \
     183             :                 sph_u64 *WW = &W[0][0]; \
     184             :                 for (u = 0; u < 16; u ++) { \
     185             :                         VV[u] ^= sph_dec64le_aligned(sc->buf + (u * 8)) \
     186             :                                 ^ WW[u] ^ WW[u + 16]; \
     187             :                 } \
     188             :         } while (0)
     189             : 
     190             : #define COMPRESS_BIG(sc)   do { \
     191             :                 sph_u32 K0 = sc->C0; \
     192             :                 sph_u32 K1 = sc->C1; \
     193             :                 sph_u32 K2 = sc->C2; \
     194             :                 sph_u32 K3 = sc->C3; \
     195             :                 unsigned u; \
     196             :                 INPUT_BLOCK_BIG(sc); \
     197             :                 for (u = 0; u < 10; u ++) { \
     198             :                         BIG_ROUND; \
     199             :                 } \
     200             :                 FINAL_BIG; \
     201             :         } while (0)
     202             : 
     203             : #define INCR_COUNTER(sc, val)   do { \
     204             :                 sc->C0 = T32(sc->C0 + (sph_u32)(val)); \
     205             :                 if (sc->C0 < (sph_u32)(val)) { \
     206             :                         if ((sc->C1 = T32(sc->C1 + 1)) == 0) \
     207             :                                 if ((sc->C2 = T32(sc->C2 + 1)) == 0) \
     208             :                                         sc->C3 = T32(sc->C3 + 1); \
     209             :                 } \
     210             :         } while (0)
     211             : 
     212             : static void
     213     2040217 : echo_big_init(sph_echo_big_context *sc, unsigned out_len)
     214             : {
     215     2040217 :         sc->u.Vb[0][0] = (sph_u64)out_len;
     216     2040217 :         sc->u.Vb[0][1] = 0;
     217     2040217 :         sc->u.Vb[1][0] = (sph_u64)out_len;
     218     2040217 :         sc->u.Vb[1][1] = 0;
     219     2040217 :         sc->u.Vb[2][0] = (sph_u64)out_len;
     220     2040217 :         sc->u.Vb[2][1] = 0;
     221     2040217 :         sc->u.Vb[3][0] = (sph_u64)out_len;
     222     2040217 :         sc->u.Vb[3][1] = 0;
     223     2040217 :         sc->u.Vb[4][0] = (sph_u64)out_len;
     224     2040217 :         sc->u.Vb[4][1] = 0;
     225     2040217 :         sc->u.Vb[5][0] = (sph_u64)out_len;
     226     2040217 :         sc->u.Vb[5][1] = 0;
     227     2040217 :         sc->u.Vb[6][0] = (sph_u64)out_len;
     228     2040217 :         sc->u.Vb[6][1] = 0;
     229     2040217 :         sc->u.Vb[7][0] = (sph_u64)out_len;
     230     2040217 :         sc->u.Vb[7][1] = 0;
     231     2040217 :         sc->ptr = 0;
     232     2040217 :         sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
     233     2040217 : }
     234             : 
     235             : static void
     236     1020110 : echo_big_compress(sph_echo_big_context *sc)
     237             : {
     238     1020110 :         DECL_STATE_BIG
     239             : 
     240    35703720 :         COMPRESS_BIG(sc);
     241     1020110 : }
     242             : 
     243             : static void
     244     1020108 : echo_big_core(sph_echo_big_context *sc,
     245             :         const unsigned char *data, size_t len)
     246             : {
     247     1020108 :         unsigned char *buf;
     248     1020108 :         size_t ptr;
     249             : 
     250     1020108 :         buf = sc->buf;
     251     1020108 :         ptr = sc->ptr;
     252     1020108 :         if (len < (sizeof sc->buf) - ptr) {
     253     1020108 :                 memcpy(buf + ptr, data, len);
     254     1020108 :                 ptr += len;
     255     1020108 :                 sc->ptr = ptr;
     256     1020108 :                 return;
     257             :         }
     258             : 
     259           0 :         while (len > 0) {
     260           0 :                 size_t clen;
     261             : 
     262           0 :                 clen = (sizeof sc->buf) - ptr;
     263           0 :                 if (clen > len)
     264           0 :                         clen = len;
     265           0 :                 memcpy(buf + ptr, data, clen);
     266           0 :                 ptr += clen;
     267           0 :                 data += clen;
     268           0 :                 len -= clen;
     269           0 :                 if (ptr == sizeof sc->buf) {
     270           0 :                         INCR_COUNTER(sc, 1024);
     271           0 :                         echo_big_compress(sc);
     272           0 :                         ptr = 0;
     273           0 :                 }
     274           0 :         }
     275           0 :         sc->ptr = ptr;
     276     1020108 : }
     277             : 
     278             : static void
     279     1020109 : echo_big_close(sph_echo_big_context *sc, unsigned ub, unsigned n,
     280             :         void *dst, unsigned out_size_w32)
     281             : {
     282     1020109 :         unsigned char *buf;
     283     1020109 :         size_t ptr;
     284     1020109 :         unsigned z;
     285     1020109 :         unsigned elen;
     286     1020109 :         union {
     287             :                 unsigned char tmp[64];
     288             :                 sph_u32 dummy;
     289             :                 sph_u64 dummy2;
     290             :         } u;
     291     1020109 :         sph_u64 *VV;
     292     1020109 :         unsigned k;
     293             : 
     294     1020109 :         buf = sc->buf;
     295     1020109 :         ptr = sc->ptr;
     296     1020109 :         elen = ((unsigned)ptr << 3) + n;
     297     1020109 :         INCR_COUNTER(sc, elen);
     298     1020109 :         sph_enc32le_aligned(u.tmp, sc->C0);
     299     1020109 :         sph_enc32le_aligned(u.tmp + 4, sc->C1);
     300     1020109 :         sph_enc32le_aligned(u.tmp + 8, sc->C2);
     301     1020109 :         sph_enc32le_aligned(u.tmp + 12, sc->C3);
     302             :         /*
     303             :          * If elen is zero, then this block actually contains no message
     304             :          * bit, only the first padding bit.
     305             :          */
     306     1020109 :         if (elen == 0) {
     307           0 :                 sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
     308           0 :         }
     309     1020109 :         z = 0x80 >> n;
     310     1020109 :         buf[ptr ++] = ((ub & -z) | z) & 0xFF;
     311     1020109 :         memset(buf + ptr, 0, (sizeof sc->buf) - ptr);
     312     1020109 :         if (ptr > ((sizeof sc->buf) - 18)) {
     313           0 :                 echo_big_compress(sc);
     314           0 :                 sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
     315           0 :                 memset(buf, 0, sizeof sc->buf);
     316           0 :         }
     317     1020109 :         sph_enc16le(buf + (sizeof sc->buf) - 18, out_size_w32 << 5);
     318     1020109 :         memcpy(buf + (sizeof sc->buf) - 16, u.tmp, 16);
     319     1020109 :         echo_big_compress(sc);
     320     9180973 :         for (VV = &sc->u.Vb[0][0], k = 0; k < ((out_size_w32 + 1) >> 1); k ++)
     321     8160864 :                 sph_enc64le_aligned(u.tmp + (k << 3), VV[k]);
     322     1020109 :         memcpy(dst, u.tmp, out_size_w32 << 2);
     323     1020109 :         echo_big_init(sc, out_size_w32 << 5);
     324     1020109 : }
     325             : 
     326             : /* see sph_echo.h */
     327             : void
     328     1020107 : sph_echo512_init(sph_echo512_context *cc)
     329             : {
     330     1020107 :         echo_big_init(cc, 512);
     331     1020107 : }
     332             : 
     333             : /* see sph_echo.h */
     334             : void
     335     1020107 : sph_echo512(sph_echo512_context *cc, const void *data, size_t len)
     336             : {
     337     1020107 :         echo_big_core(cc, static_cast<const unsigned char*>(data), len);
     338     1020107 : }
     339             : 
     340             : /* see sph_echo.h */
     341             : void
     342     1020107 : sph_echo512_close(sph_echo512_context *cc, void *dst)
     343             : {
     344     1020107 :         echo_big_close(cc, 0, 0, dst, 16);
     345     1020107 : }
     346             : 
     347             : /* see sph_echo.h */
     348             : void
     349           0 : sph_echo512_addbits_and_close(sph_echo512_context *cc, unsigned ub, unsigned n, void *dst)
     350             : {
     351           0 :         echo_big_close(cc, ub, n, dst, 16);
     352           0 : }

Generated by: LCOV version 1.16