LCOV - code coverage report
Current view: top level - src/crypto - chacha20.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 186 186 100.0 %
Date: 2025-02-23 09:33:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2017 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : // Based on the public domain implementation 'merged' by D. J. Bernstein
       6             : // See https://cr.yp.to/chacha.html.
       7             : 
       8             : #include "crypto/common.h"
       9             : #include "crypto/chacha20.h"
      10             : 
      11             : #include <string.h>
      12             : 
      13   148379500 : constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
      14             : 
      15             : #define QUARTERROUND(a,b,c,d) \
      16             :   a += b; d = rotl32(d ^ a, 16); \
      17             :   c += d; b = rotl32(b ^ c, 12); \
      18             :   a += b; d = rotl32(d ^ a, 8); \
      19             :   c += d; b = rotl32(b ^ c, 7);
      20             : 
      21             : static const unsigned char sigma[] = "expand 32-byte k";
      22             : static const unsigned char tau[] = "expand 16-byte k";
      23             : 
      24     2566690 : void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
      25             : {
      26     2566690 :     const unsigned char *constants;
      27             : 
      28     2566690 :     input[4] = ReadLE32(k + 0);
      29     2566690 :     input[5] = ReadLE32(k + 4);
      30     2566690 :     input[6] = ReadLE32(k + 8);
      31     2566690 :     input[7] = ReadLE32(k + 12);
      32     2566690 :     if (keylen == 32) { /* recommended */
      33     2566690 :         k += 16;
      34     2566690 :         constants = sigma;
      35             :     } else { /* keylen == 16 */
      36             :         constants = tau;
      37             :     }
      38     2566690 :     input[8] = ReadLE32(k + 0);
      39     2566690 :     input[9] = ReadLE32(k + 4);
      40     2566690 :     input[10] = ReadLE32(k + 8);
      41     2566690 :     input[11] = ReadLE32(k + 12);
      42     2566690 :     input[0] = ReadLE32(constants + 0);
      43     2566690 :     input[1] = ReadLE32(constants + 4);
      44     2566690 :     input[2] = ReadLE32(constants + 8);
      45     2566690 :     input[3] = ReadLE32(constants + 12);
      46     2566690 :     input[12] = 0;
      47     2566690 :     input[13] = 0;
      48     2566690 :     input[14] = 0;
      49     2566690 :     input[15] = 0;
      50     2566690 : }
      51             : 
      52     2571246 : ChaCha20::ChaCha20()
      53             : {
      54     2571246 :     memset(input, 0, sizeof(input));
      55     2571246 : }
      56             : 
      57           7 : ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
      58             : {
      59           7 :     SetKey(k, keylen);
      60           7 : }
      61             : 
      62           8 : void ChaCha20::SetIV(uint64_t iv)
      63             : {
      64           8 :     input[14] = iv;
      65           8 :     input[15] = iv >> 32;
      66           8 : }
      67             : 
      68           8 : void ChaCha20::Seek(uint64_t pos)
      69             : {
      70           8 :     input[12] = pos;
      71           8 :     input[13] = pos >> 32;
      72           8 : }
      73             : 
      74    14836900 : void ChaCha20::Keystream(unsigned char* c, size_t bytes)
      75             : {
      76    14836900 :     uint32_t x[16];
      77    14836900 :     uint32_t j[16];
      78    14836900 :     unsigned char *ctarget = nullptr;
      79    14836900 :     unsigned char tmp[64];
      80    14836900 :     unsigned int i;
      81             : 
      82    14836900 :     if (!bytes) return;
      83             : 
      84   252227700 :     for (uint32_t i=0; i<16; i++) {
      85   237390600 :         j[i] = input[i];
      86             :     }
      87             : 
      88    14838990 :     for (;;) {
      89    14837940 :         if (bytes < 64) {
      90        1003 :             ctarget = c;
      91        1003 :             c = tmp;
      92             :         }
      93   252245500 :         for (uint32_t i=0; i<16; i++) {
      94   237407300 :             x[i] = j[i];
      95             :         }
      96   163217600 :         for (i = 20;i > 0;i -= 2) {
      97   148379400 :             QUARTERROUND( x[0], x[4], x[8],x[12])
      98   148379400 :             QUARTERROUND( x[1], x[5], x[9],x[13])
      99   148379400 :             QUARTERROUND( x[2], x[6],x[10],x[14])
     100   148379400 :             QUARTERROUND( x[3], x[7],x[11],x[15])
     101   148379400 :             QUARTERROUND( x[0], x[5],x[10],x[15])
     102   148379400 :             QUARTERROUND( x[1], x[6],x[11],x[12])
     103   148379400 :             QUARTERROUND( x[2], x[7], x[8],x[13])
     104   148379400 :             QUARTERROUND( x[3], x[4], x[9],x[14])
     105             :         }
     106   252245500 :         for (uint32_t i=0; i<16; i++) {
     107   237407300 :             x[i] += j[i];
     108             :         }
     109             : 
     110    14837940 :         ++j[12];
     111    14837940 :         if (!j[12]) ++j[13];
     112             : 
     113   252245500 :         for (uint32_t i=0; i<16; i++) {
     114   237407300 :             WriteLE32(c + 4*i, x[i]);
     115             :         }
     116             : 
     117    14837940 :         if (bytes <= 64) {
     118    14836900 :             if (bytes < 64) {
     119       31387 :                 for (i = 0;i < bytes;++i) ctarget[i] = c[i];
     120             :             }
     121    14836900 :             input[12] = j[12];
     122    14836900 :             input[13] = j[13];
     123    14836900 :             return;
     124             :         }
     125        1044 :         bytes -= 64;
     126        1044 :         c += 64;
     127        1044 :     }
     128             : }
     129             : 
     130           1 : void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
     131             : {
     132           1 :     uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
     133           1 :     uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
     134           1 :     unsigned char *ctarget = nullptr;
     135           1 :     unsigned char tmp[64];
     136           1 :     unsigned int i;
     137             : 
     138           1 :     if (!bytes) return;
     139             : 
     140           1 :     j0 = input[0];
     141           1 :     j1 = input[1];
     142           1 :     j2 = input[2];
     143           1 :     j3 = input[3];
     144           1 :     j4 = input[4];
     145           1 :     j5 = input[5];
     146           1 :     j6 = input[6];
     147           1 :     j7 = input[7];
     148           1 :     j8 = input[8];
     149           1 :     j9 = input[9];
     150           1 :     j10 = input[10];
     151           1 :     j11 = input[11];
     152           1 :     j12 = input[12];
     153           1 :     j13 = input[13];
     154           1 :     j14 = input[14];
     155           1 :     j15 = input[15];
     156             : 
     157           3 :     for (;;) {
     158           2 :         if (bytes < 64) {
     159             :             // if m has fewer than 64 bytes available, copy m to tmp and
     160             :             // read from tmp instead
     161          51 :             for (i = 0;i < bytes;++i) tmp[i] = m[i];
     162             :             m = tmp;
     163             :             ctarget = c;
     164             :             c = tmp;
     165             :         }
     166           2 :         x0 = j0;
     167           2 :         x1 = j1;
     168           2 :         x2 = j2;
     169           2 :         x3 = j3;
     170           2 :         x4 = j4;
     171           2 :         x5 = j5;
     172           2 :         x6 = j6;
     173           2 :         x7 = j7;
     174           2 :         x8 = j8;
     175           2 :         x9 = j9;
     176           2 :         x10 = j10;
     177           2 :         x11 = j11;
     178           2 :         x12 = j12;
     179           2 :         x13 = j13;
     180           2 :         x14 = j14;
     181           2 :         x15 = j15;
     182          22 :         for (i = 20;i > 0;i -= 2) {
     183          20 :             QUARTERROUND( x0, x4, x8,x12)
     184          20 :             QUARTERROUND( x1, x5, x9,x13)
     185          20 :             QUARTERROUND( x2, x6,x10,x14)
     186          20 :             QUARTERROUND( x3, x7,x11,x15)
     187          20 :             QUARTERROUND( x0, x5,x10,x15)
     188          20 :             QUARTERROUND( x1, x6,x11,x12)
     189          20 :             QUARTERROUND( x2, x7, x8,x13)
     190          20 :             QUARTERROUND( x3, x4, x9,x14)
     191             :         }
     192           2 :         x0 += j0;
     193           2 :         x1 += j1;
     194           2 :         x2 += j2;
     195           2 :         x3 += j3;
     196           2 :         x4 += j4;
     197           2 :         x5 += j5;
     198           2 :         x6 += j6;
     199           2 :         x7 += j7;
     200           2 :         x8 += j8;
     201           2 :         x9 += j9;
     202           2 :         x10 += j10;
     203           2 :         x11 += j11;
     204           2 :         x12 += j12;
     205           2 :         x13 += j13;
     206           2 :         x14 += j14;
     207           2 :         x15 += j15;
     208             : 
     209           2 :         x0 ^= ReadLE32(m + 0);
     210           2 :         x1 ^= ReadLE32(m + 4);
     211           2 :         x2 ^= ReadLE32(m + 8);
     212           2 :         x3 ^= ReadLE32(m + 12);
     213           2 :         x4 ^= ReadLE32(m + 16);
     214           2 :         x5 ^= ReadLE32(m + 20);
     215           2 :         x6 ^= ReadLE32(m + 24);
     216           2 :         x7 ^= ReadLE32(m + 28);
     217           2 :         x8 ^= ReadLE32(m + 32);
     218           2 :         x9 ^= ReadLE32(m + 36);
     219           2 :         x10 ^= ReadLE32(m + 40);
     220           2 :         x11 ^= ReadLE32(m + 44);
     221           2 :         x12 ^= ReadLE32(m + 48);
     222           2 :         x13 ^= ReadLE32(m + 52);
     223           2 :         x14 ^= ReadLE32(m + 56);
     224           2 :         x15 ^= ReadLE32(m + 60);
     225             : 
     226           2 :         ++j12;
     227           2 :         if (!j12) ++j13;
     228             : 
     229           2 :         WriteLE32(c + 0, x0);
     230           2 :         WriteLE32(c + 4, x1);
     231           2 :         WriteLE32(c + 8, x2);
     232           2 :         WriteLE32(c + 12, x3);
     233           2 :         WriteLE32(c + 16, x4);
     234           2 :         WriteLE32(c + 20, x5);
     235           2 :         WriteLE32(c + 24, x6);
     236           2 :         WriteLE32(c + 28, x7);
     237           2 :         WriteLE32(c + 32, x8);
     238           2 :         WriteLE32(c + 36, x9);
     239           2 :         WriteLE32(c + 40, x10);
     240           2 :         WriteLE32(c + 44, x11);
     241           2 :         WriteLE32(c + 48, x12);
     242           2 :         WriteLE32(c + 52, x13);
     243           2 :         WriteLE32(c + 56, x14);
     244           2 :         WriteLE32(c + 60, x15);
     245             : 
     246           2 :         if (bytes <= 64) {
     247           1 :             if (bytes < 64) {
     248          51 :                 for (i = 0;i < bytes;++i) ctarget[i] = c[i];
     249             :             }
     250           1 :             input[12] = j12;
     251           1 :             input[13] = j13;
     252           1 :             return;
     253             :         }
     254           1 :         bytes -= 64;
     255           1 :         c += 64;
     256           1 :         m += 64;
     257             :     }
     258             : }

Generated by: LCOV version 1.14