_Z16htole32_internalj:
   39|  53.5M|{
   40|       |    if constexpr (std::endian::native == std::endian::big) return internal_bswap_32(host_32bits);
   41|  53.5M|        else return host_32bits;
   42|  53.5M|}
_Z16le32toh_internalj:
   49|  12.0M|{
   50|       |    if constexpr (std::endian::native == std::endian::big) return internal_bswap_32(little_endian_32bits);
   51|  12.0M|        else return little_endian_32bits;
   52|  12.0M|}

_ZN15ChaCha20Aligned6SetKeyE4SpanIKSt4byteE:
   26|    864|{
   27|    864|    assert(key.size() == KEYLEN);
   28|    864|    input[0] = ReadLE32(key.data() + 0);
   29|    864|    input[1] = ReadLE32(key.data() + 4);
   30|    864|    input[2] = ReadLE32(key.data() + 8);
   31|    864|    input[3] = ReadLE32(key.data() + 12);
   32|    864|    input[4] = ReadLE32(key.data() + 16);
   33|    864|    input[5] = ReadLE32(key.data() + 20);
   34|    864|    input[6] = ReadLE32(key.data() + 24);
   35|    864|    input[7] = ReadLE32(key.data() + 28);
   36|    864|    input[8] = 0;
   37|    864|    input[9] = 0;
   38|    864|    input[10] = 0;
   39|    864|    input[11] = 0;
   40|    864|}
_ZN15ChaCha20AlignedD2Ev:
   43|    864|{
   44|    864|    memory_cleanse(input, sizeof(input));
   45|    864|}
_ZN15ChaCha20AlignedC2E4SpanIKSt4byteE:
   48|    864|{
   49|    864|    SetKey(key);
   50|    864|}
_ZN15ChaCha20Aligned4SeekENSt3__14pairIjmEEj:
   53|    864|{
   54|    864|    input[8] = block_counter;
   55|    864|    input[9] = nonce.first;
   56|    864|    input[10] = nonce.second;
   57|    864|    input[11] = nonce.second >> 32;
   58|    864|}
_ZN8ChaCha209KeystreamE4SpanISt4byteE:
  283|  44.6k|{
  284|  44.6k|    if (out.empty()) return;
  ------------------
  |  Branch (284:9): [True: 41.2k, False: 3.43k]
  ------------------
  285|  3.43k|    if (m_bufleft) {
  ------------------
  |  Branch (285:9): [True: 2.52k, False: 904]
  ------------------
  286|  2.52k|        unsigned reuse = std::min<size_t>(m_bufleft, out.size());
  287|  2.52k|        std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft + reuse, out.begin());
  288|  2.52k|        m_bufleft -= reuse;
  289|  2.52k|        out = out.subspan(reuse);
  290|  2.52k|    }
  291|  3.43k|    if (out.size() >= m_aligned.BLOCKLEN) {
  ------------------
  |  Branch (291:9): [True: 1.74k, False: 1.69k]
  ------------------
  292|  1.74k|        size_t blocks = out.size() / m_aligned.BLOCKLEN;
  293|  1.74k|        m_aligned.Keystream(out.first(blocks * m_aligned.BLOCKLEN));
  294|  1.74k|        out = out.subspan(blocks * m_aligned.BLOCKLEN);
  295|  1.74k|    }
  296|  3.43k|    if (!out.empty()) {
  ------------------
  |  Branch (296:9): [True: 1.95k, False: 1.48k]
  ------------------
  297|  1.95k|        m_aligned.Keystream(m_buffer);
  298|  1.95k|        std::copy(m_buffer.begin(), m_buffer.begin() + out.size(), out.begin());
  299|  1.95k|        m_bufleft = m_aligned.BLOCKLEN - out.size();
  300|  1.95k|    }
  301|  3.43k|}
_ZN8ChaCha205CryptE4SpanIKSt4byteES0_IS1_E:
  304|  1.90k|{
  305|  1.90k|    assert(input.size() == output.size());
  306|       |
  307|  1.90k|    if (!input.size()) return;
  ------------------
  |  Branch (307:9): [True: 245, False: 1.66k]
  ------------------
  308|  1.66k|    if (m_bufleft) {
  ------------------
  |  Branch (308:9): [True: 1.41k, False: 245]
  ------------------
  309|  1.41k|        unsigned reuse = std::min<size_t>(m_bufleft, input.size());
  310|  31.6k|        for (unsigned i = 0; i < reuse; i++) {
  ------------------
  |  Branch (310:30): [True: 30.2k, False: 1.41k]
  ------------------
  311|  30.2k|            output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
  312|  30.2k|        }
  313|  1.41k|        m_bufleft -= reuse;
  314|  1.41k|        output = output.subspan(reuse);
  315|  1.41k|        input = input.subspan(reuse);
  316|  1.41k|    }
  317|  1.66k|    if (input.size() >= m_aligned.BLOCKLEN) {
  ------------------
  |  Branch (317:9): [True: 502, False: 1.15k]
  ------------------
  318|    502|        size_t blocks = input.size() / m_aligned.BLOCKLEN;
  319|    502|        m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN), output.first(blocks * m_aligned.BLOCKLEN));
  320|    502|        output = output.subspan(blocks * m_aligned.BLOCKLEN);
  321|    502|        input = input.subspan(blocks * m_aligned.BLOCKLEN);
  322|    502|    }
  323|  1.66k|    if (!input.empty()) {
  ------------------
  |  Branch (323:9): [True: 897, False: 764]
  ------------------
  324|    897|        m_aligned.Keystream(m_buffer);
  325|  25.2k|        for (unsigned i = 0; i < input.size(); i++) {
  ------------------
  |  Branch (325:30): [True: 24.3k, False: 897]
  ------------------
  326|  24.3k|            output[i] = input[i] ^ m_buffer[i];
  327|  24.3k|        }
  328|    897|        m_bufleft = m_aligned.BLOCKLEN - input.size();
  329|    897|    }
  330|  1.66k|}
_ZN8ChaCha20D2Ev:
  333|    864|{
  334|    864|    memory_cleanse(m_buffer.data(), m_buffer.size());
  335|    864|}
_ZN15ChaCha20Aligned9KeystreamE4SpanISt4byteE:
   61|  4.58k|{
   62|  4.58k|    std::byte* c = output.data();
   63|  4.58k|    size_t blocks = output.size() / BLOCKLEN;
   64|  4.58k|    assert(blocks * BLOCKLEN == output.size());
   65|       |
   66|  4.58k|    uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
   67|  4.58k|    uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
   68|       |
   69|  4.58k|    if (!blocks) return;
  ------------------
  |  Branch (69:9): [True: 0, False: 4.58k]
  ------------------
   70|       |
   71|  4.58k|    j4 = input[0];
   72|  4.58k|    j5 = input[1];
   73|  4.58k|    j6 = input[2];
   74|  4.58k|    j7 = input[3];
   75|  4.58k|    j8 = input[4];
   76|  4.58k|    j9 = input[5];
   77|  4.58k|    j10 = input[6];
   78|  4.58k|    j11 = input[7];
   79|  4.58k|    j12 = input[8];
   80|  4.58k|    j13 = input[9];
   81|  4.58k|    j14 = input[10];
   82|  4.58k|    j15 = input[11];
   83|       |
   84|  2.59M|    for (;;) {
   85|  2.59M|        x0 = 0x61707865;
   86|  2.59M|        x1 = 0x3320646e;
   87|  2.59M|        x2 = 0x79622d32;
   88|  2.59M|        x3 = 0x6b206574;
   89|  2.59M|        x4 = j4;
   90|  2.59M|        x5 = j5;
   91|  2.59M|        x6 = j6;
   92|  2.59M|        x7 = j7;
   93|  2.59M|        x8 = j8;
   94|  2.59M|        x9 = j9;
   95|  2.59M|        x10 = j10;
   96|  2.59M|        x11 = j11;
   97|  2.59M|        x12 = j12;
   98|  2.59M|        x13 = j13;
   99|  2.59M|        x14 = j14;
  100|  2.59M|        x15 = j15;
  101|       |
  102|       |        // The 20 inner ChaCha20 rounds are unrolled here for performance.
  103|  2.59M|        REPEAT10(
  ------------------
  |  |   23|  2.59M|#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
  |  |  ------------------
  |  |  |  Branch (23:84): [Folded - Ignored]
  |  |  ------------------
  ------------------
  104|  2.59M|            QUARTERROUND( x0, x4, x8,x12);
  105|  2.59M|            QUARTERROUND( x1, x5, x9,x13);
  106|  2.59M|            QUARTERROUND( x2, x6,x10,x14);
  107|  2.59M|            QUARTERROUND( x3, x7,x11,x15);
  108|  2.59M|            QUARTERROUND( x0, x5,x10,x15);
  109|  2.59M|            QUARTERROUND( x1, x6,x11,x12);
  110|  2.59M|            QUARTERROUND( x2, x7, x8,x13);
  111|  2.59M|            QUARTERROUND( x3, x4, x9,x14);
  112|  2.59M|        );
  113|       |
  114|  2.59M|        x0 += 0x61707865;
  115|  2.59M|        x1 += 0x3320646e;
  116|  2.59M|        x2 += 0x79622d32;
  117|  2.59M|        x3 += 0x6b206574;
  118|  2.59M|        x4 += j4;
  119|  2.59M|        x5 += j5;
  120|  2.59M|        x6 += j6;
  121|  2.59M|        x7 += j7;
  122|  2.59M|        x8 += j8;
  123|  2.59M|        x9 += j9;
  124|  2.59M|        x10 += j10;
  125|  2.59M|        x11 += j11;
  126|  2.59M|        x12 += j12;
  127|  2.59M|        x13 += j13;
  128|  2.59M|        x14 += j14;
  129|  2.59M|        x15 += j15;
  130|       |
  131|  2.59M|        ++j12;
  132|  2.59M|        if (!j12) ++j13;
  ------------------
  |  Branch (132:13): [True: 18, False: 2.59M]
  ------------------
  133|       |
  134|  2.59M|        WriteLE32(c + 0, x0);
  135|  2.59M|        WriteLE32(c + 4, x1);
  136|  2.59M|        WriteLE32(c + 8, x2);
  137|  2.59M|        WriteLE32(c + 12, x3);
  138|  2.59M|        WriteLE32(c + 16, x4);
  139|  2.59M|        WriteLE32(c + 20, x5);
  140|  2.59M|        WriteLE32(c + 24, x6);
  141|  2.59M|        WriteLE32(c + 28, x7);
  142|  2.59M|        WriteLE32(c + 32, x8);
  143|  2.59M|        WriteLE32(c + 36, x9);
  144|  2.59M|        WriteLE32(c + 40, x10);
  145|  2.59M|        WriteLE32(c + 44, x11);
  146|  2.59M|        WriteLE32(c + 48, x12);
  147|  2.59M|        WriteLE32(c + 52, x13);
  148|  2.59M|        WriteLE32(c + 56, x14);
  149|  2.59M|        WriteLE32(c + 60, x15);
  150|       |
  151|  2.59M|        if (blocks == 1) {
  ------------------
  |  Branch (151:13): [True: 4.58k, False: 2.59M]
  ------------------
  152|  4.58k|            input[8] = j12;
  153|  4.58k|            input[9] = j13;
  154|  4.58k|            return;
  155|  4.58k|        }
  156|  2.59M|        blocks -= 1;
  157|  2.59M|        c += BLOCKLEN;
  158|  2.59M|    }
  159|  4.58k|}
_ZN15ChaCha20Aligned5CryptE4SpanIKSt4byteES0_IS1_E:
  162|    502|{
  163|    502|    assert(in_bytes.size() == out_bytes.size());
  164|    502|    const std::byte* m = in_bytes.data();
  165|    502|    std::byte* c = out_bytes.data();
  166|    502|    size_t blocks = out_bytes.size() / BLOCKLEN;
  167|    502|    assert(blocks * BLOCKLEN == out_bytes.size());
  168|       |
  169|    502|    uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
  170|    502|    uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
  171|       |
  172|    502|    if (!blocks) return;
  ------------------
  |  Branch (172:9): [True: 0, False: 502]
  ------------------
  173|       |
  174|    502|    j4 = input[0];
  175|    502|    j5 = input[1];
  176|    502|    j6 = input[2];
  177|    502|    j7 = input[3];
  178|    502|    j8 = input[4];
  179|    502|    j9 = input[5];
  180|    502|    j10 = input[6];
  181|    502|    j11 = input[7];
  182|    502|    j12 = input[8];
  183|    502|    j13 = input[9];
  184|    502|    j14 = input[10];
  185|    502|    j15 = input[11];
  186|       |
  187|   753k|    for (;;) {
  188|   753k|        x0 = 0x61707865;
  189|   753k|        x1 = 0x3320646e;
  190|   753k|        x2 = 0x79622d32;
  191|   753k|        x3 = 0x6b206574;
  192|   753k|        x4 = j4;
  193|   753k|        x5 = j5;
  194|   753k|        x6 = j6;
  195|   753k|        x7 = j7;
  196|   753k|        x8 = j8;
  197|   753k|        x9 = j9;
  198|   753k|        x10 = j10;
  199|   753k|        x11 = j11;
  200|   753k|        x12 = j12;
  201|   753k|        x13 = j13;
  202|   753k|        x14 = j14;
  203|   753k|        x15 = j15;
  204|       |
  205|       |        // The 20 inner ChaCha20 rounds are unrolled here for performance.
  206|   753k|        REPEAT10(
  ------------------
  |  |   23|   753k|#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
  |  |  ------------------
  |  |  |  Branch (23:84): [Folded - Ignored]
  |  |  ------------------
  ------------------
  207|   753k|            QUARTERROUND( x0, x4, x8,x12);
  208|   753k|            QUARTERROUND( x1, x5, x9,x13);
  209|   753k|            QUARTERROUND( x2, x6,x10,x14);
  210|   753k|            QUARTERROUND( x3, x7,x11,x15);
  211|   753k|            QUARTERROUND( x0, x5,x10,x15);
  212|   753k|            QUARTERROUND( x1, x6,x11,x12);
  213|   753k|            QUARTERROUND( x2, x7, x8,x13);
  214|   753k|            QUARTERROUND( x3, x4, x9,x14);
  215|   753k|        );
  216|       |
  217|   753k|        x0 += 0x61707865;
  218|   753k|        x1 += 0x3320646e;
  219|   753k|        x2 += 0x79622d32;
  220|   753k|        x3 += 0x6b206574;
  221|   753k|        x4 += j4;
  222|   753k|        x5 += j5;
  223|   753k|        x6 += j6;
  224|   753k|        x7 += j7;
  225|   753k|        x8 += j8;
  226|   753k|        x9 += j9;
  227|   753k|        x10 += j10;
  228|   753k|        x11 += j11;
  229|   753k|        x12 += j12;
  230|   753k|        x13 += j13;
  231|   753k|        x14 += j14;
  232|   753k|        x15 += j15;
  233|       |
  234|   753k|        x0 ^= ReadLE32(m + 0);
  235|   753k|        x1 ^= ReadLE32(m + 4);
  236|   753k|        x2 ^= ReadLE32(m + 8);
  237|   753k|        x3 ^= ReadLE32(m + 12);
  238|   753k|        x4 ^= ReadLE32(m + 16);
  239|   753k|        x5 ^= ReadLE32(m + 20);
  240|   753k|        x6 ^= ReadLE32(m + 24);
  241|   753k|        x7 ^= ReadLE32(m + 28);
  242|   753k|        x8 ^= ReadLE32(m + 32);
  243|   753k|        x9 ^= ReadLE32(m + 36);
  244|   753k|        x10 ^= ReadLE32(m + 40);
  245|   753k|        x11 ^= ReadLE32(m + 44);
  246|   753k|        x12 ^= ReadLE32(m + 48);
  247|   753k|        x13 ^= ReadLE32(m + 52);
  248|   753k|        x14 ^= ReadLE32(m + 56);
  249|   753k|        x15 ^= ReadLE32(m + 60);
  250|       |
  251|   753k|        ++j12;
  252|   753k|        if (!j12) ++j13;
  ------------------
  |  Branch (252:13): [True: 0, False: 753k]
  ------------------
  253|       |
  254|   753k|        WriteLE32(c + 0, x0);
  255|   753k|        WriteLE32(c + 4, x1);
  256|   753k|        WriteLE32(c + 8, x2);
  257|   753k|        WriteLE32(c + 12, x3);
  258|   753k|        WriteLE32(c + 16, x4);
  259|   753k|        WriteLE32(c + 20, x5);
  260|   753k|        WriteLE32(c + 24, x6);
  261|   753k|        WriteLE32(c + 28, x7);
  262|   753k|        WriteLE32(c + 32, x8);
  263|   753k|        WriteLE32(c + 36, x9);
  264|   753k|        WriteLE32(c + 40, x10);
  265|   753k|        WriteLE32(c + 44, x11);
  266|   753k|        WriteLE32(c + 48, x12);
  267|   753k|        WriteLE32(c + 52, x13);
  268|   753k|        WriteLE32(c + 56, x14);
  269|   753k|        WriteLE32(c + 60, x15);
  270|       |
  271|   753k|        if (blocks == 1) {
  ------------------
  |  Branch (271:13): [True: 502, False: 753k]
  ------------------
  272|    502|            input[8] = j12;
  273|    502|            input[9] = j13;
  274|    502|            return;
  275|    502|        }
  276|   753k|        blocks -= 1;
  277|   753k|        c += BLOCKLEN;
  278|   753k|        m += BLOCKLEN;
  279|   753k|    }
  280|    502|}

_ZN8ChaCha20C2E4SpanIKSt4byteE:
   92|    864|    ChaCha20(Span<const std::byte> key) noexcept : m_aligned(key) {}
_ZN8ChaCha204SeekENSt3__14pairIjmEEj:
  105|    864|    {
  106|    864|        m_aligned.Seek(nonce, block_counter);
  107|    864|        m_bufleft = 0;
  108|    864|    }

_Z9WriteLE32ITk8ByteTypeSt4byteEvPT_j:
   51|  53.5M|{
   52|  53.5M|    uint32_t v = htole32_internal(x);
   53|  53.5M|    memcpy(ptr, &v, 4);
   54|  53.5M|}
_Z8ReadLE32ITk8ByteTypeSt4byteEjPKT_:
   28|  12.0M|{
   29|  12.0M|    uint32_t x;
   30|  12.0M|    memcpy(&x, ptr, 4);
   31|  12.0M|    return le32toh_internal(x);
   32|  12.0M|}

_ZNK4SpanIKSt4byteE5firstEm:
  206|    502|    {
  207|    502|        ASSERT_IF_DEBUG(size() >= count);
  208|    502|        return Span<C>(m_data, count);
  209|    502|    }
_ZNK4SpanISt4byteE5firstEm:
  206|  2.24k|    {
  207|  2.24k|        ASSERT_IF_DEBUG(size() >= count);
  208|  2.24k|        return Span<C>(m_data, count);
  209|  2.24k|    }
_ZNK4SpanIKSt4byteE4sizeEv:
  187|  36.5k|    constexpr std::size_t size() const noexcept { return m_size; }
_ZNK4SpanIKSt4byteE4dataEv:
  174|  7.41k|    constexpr C* data() const noexcept { return m_data; }
_ZNK4SpanISt4byteE4sizeEv:
  187|  72.2k|    constexpr std::size_t size() const noexcept { return m_size; }
_ZNK4SpanISt4byteEixEm:
  191|  54.5k|    {
  192|  54.5k|        ASSERT_IF_DEBUG(size() > pos);
  193|  54.5k|        return m_data[pos];
  194|  54.5k|    }
_ZNK4SpanIKSt4byteEixEm:
  191|  54.5k|    {
  192|  54.5k|        ASSERT_IF_DEBUG(size() > pos);
  193|  54.5k|        return m_data[pos];
  194|  54.5k|    }
_ZNK4SpanISt4byteE4dataEv:
  174|  5.09k|    constexpr C* data() const noexcept { return m_data; }
_ZNK4SpanISt4byteE7subspanEmm:
  201|  48.0k|    {
  202|  48.0k|        ASSERT_IF_DEBUG(size() >= offset + count);
  203|  48.0k|        return Span<C>(m_data + offset, count);
  204|  48.0k|    }
_ZNK4SpanISt4byteE7subspanEm:
  196|  6.18k|    {
  197|  6.18k|        ASSERT_IF_DEBUG(size() >= offset);
  198|  6.18k|        return Span<C>(m_data + offset, m_size - offset);
  199|  6.18k|    }
_ZN4SpanIKSt4byteEC2IS1_TnNSt3__19enable_ifIXsr3std14is_convertibleIPA_T_PA_S1_EE5valueEiE4typeELi0EEEPS6_m:
  119|  2.42k|    constexpr Span(T* begin, std::size_t size) noexcept : m_data(begin), m_size(size) {}
_ZN4SpanISt4byteEC2IS0_TnNSt3__19enable_ifIXsr3std14is_convertibleIPA_T_PA_S0_EE5valueEiE4typeELi0EEEPS5_m:
  119|  56.4k|    constexpr Span(T* begin, std::size_t size) noexcept : m_data(begin), m_size(size) {}
_ZN4SpanIKSt4byteEC2INSt3__16vectorIS0_NS4_9allocatorIS0_EEEEEERT_NS4_9enable_ifIXaaaantsr7is_SpanIS9_EE5valuesr3std14is_convertibleIPA_NS4_14remove_pointerIDTcldtclsr3stdE7declvalISA_EE4dataEEE4typeEPA_S1_EE5valuesr3std14is_convertibleIDTcldtclsr3stdE7declvalISA_EE4sizeEEmEE5valueEDnE4typeE:
  165|    864|        : m_data(other.data()), m_size(other.size()){}
_ZN4SpanISt4byteEC2INSt3__16vectorIS0_NS3_9allocatorIS0_EEEEEERT_NS3_9enable_ifIXaaaantsr7is_SpanIS8_EE5valuesr3std14is_convertibleIPA_NS3_14remove_pointerIDTcldtclsr3stdE7declvalIS9_EE4dataEEE4typeEPA_S0_EE5valuesr3std14is_convertibleIDTcldtclsr3stdE7declvalIS9_EE4sizeEEmEE5valueEDnE4typeE:
  165|  48.4k|        : m_data(other.data()), m_size(other.size()){}
_ZN4SpanIKSt4byteEC2IS0_TnNSt3__19enable_ifIXsr3std14is_convertibleIPA_T_PA_S1_EE5valueEiE4typeELi0EEERKS_IS6_E:
  141|  1.90k|    constexpr Span(const Span<O>& other) noexcept : m_data(other.m_data), m_size(other.m_size) {}
_ZNK4SpanISt4byteE5beginEv:
  175|  4.47k|    constexpr C* begin() const noexcept { return m_data; }
_ZNK4SpanIKSt4byteE7subspanEm:
  196|  1.91k|    {
  197|  1.91k|        ASSERT_IF_DEBUG(size() >= offset);
  198|  1.91k|        return Span<C>(m_data + offset, m_size - offset);
  199|  1.91k|    }
_ZNK4SpanISt4byteE5emptyEv:
  189|  48.0k|    constexpr bool empty() const noexcept { return size() == 0; }
_ZN4SpanISt4byteEC2INSt3__15arrayIS0_Lm64EEEEERT_NS3_9enable_ifIXaaaantsr7is_SpanIS6_EE5valuesr3std14is_convertibleIPA_NS3_14remove_pointerIDTcldtclsr3stdE7declvalIS7_EE4dataEEE4typeEPA_S0_EE5valuesr3std14is_convertibleIDTcldtclsr3stdE7declvalIS7_EE4sizeEEmEE5valueEDnE4typeE:
  165|  2.84k|        : m_data(other.data()), m_size(other.size()){}
_ZNK4SpanIKSt4byteE5emptyEv:
  189|  1.66k|    constexpr bool empty() const noexcept { return size() == 0; }

_Z14memory_cleansePvm:
   15|  1.72k|{
   16|       |#if defined(WIN32)
   17|       |    /* SecureZeroMemory is guaranteed not to be optimized out. */
   18|       |    SecureZeroMemory(ptr, len);
   19|       |#else
   20|  1.72k|    std::memset(ptr, 0, len);
   21|       |
   22|       |    /* Memory barrier that scares the compiler away from optimizing out the memset.
   23|       |     *
   24|       |     * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
   25|       |     * in BoringSSL (ISC License):
   26|       |     *    As best as we can tell, this is sufficient to break any optimisations that
   27|       |     *    might try to eliminate "superfluous" memsets.
   28|       |     * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
   29|       |     * is pretty efficient because the compiler can still implement the memset() efficiently,
   30|       |     * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
   31|       |     * Yang et al. (USENIX Security 2017) for more background.
   32|       |     */
   33|  1.72k|    __asm__ __volatile__("" : : "r"(ptr) : "memory");
   34|  1.72k|#endif
   35|  1.72k|}

_ZN18FuzzedDataProviderC2EPKhm:
   37|    432|      : data_ptr_(data), remaining_bytes_(size) {}
_ZN18FuzzedDataProvider15ConsumeIntegralImEET_v:
  195|    432|template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
  196|    432|  return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
  197|    432|                                std::numeric_limits<T>::max());
  198|    432|}
_ZN18FuzzedDataProvider22ConsumeIntegralInRangeImEET_S1_S1_:
  205|  46.5k|T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
  206|  46.5k|  static_assert(std::is_integral<T>::value, "An integral type is required.");
  207|  46.5k|  static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
  208|       |
  209|  46.5k|  if (min > max)
  ------------------
  |  Branch (209:7): [True: 0, False: 46.5k]
  ------------------
  210|      0|    abort();
  211|       |
  212|       |  // Use the biggest type possible to hold the range and the result.
  213|  46.5k|  uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
  214|  46.5k|  uint64_t result = 0;
  215|  46.5k|  size_t offset = 0;
  216|       |
  217|  67.9k|  while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
  ------------------
  |  Branch (217:10): [True: 67.5k, False: 405]
  |  Branch (217:43): [True: 57.8k, False: 9.65k]
  ------------------
  218|  67.9k|         remaining_bytes_ != 0) {
  ------------------
  |  Branch (218:10): [True: 21.3k, False: 36.4k]
  ------------------
  219|       |    // Pull bytes off the end of the seed data. Experimentally, this seems to
  220|       |    // allow the fuzzer to more easily explore the input space. This makes
  221|       |    // sense, since it works by modifying inputs that caused new code to run,
  222|       |    // and this data is often used to encode length of data read by
  223|       |    // |ConsumeBytes|. Separating out read lengths makes it easier modify the
  224|       |    // contents of the data that is actually read.
  225|  21.3k|    --remaining_bytes_;
  226|  21.3k|    result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
  227|  21.3k|    offset += CHAR_BIT;
  228|  21.3k|  }
  229|       |
  230|       |  // Avoid division by 0, in case |range + 1| results in overflow.
  231|  46.5k|  if (range != std::numeric_limits<decltype(range)>::max())
  ------------------
  |  Branch (231:7): [True: 46.1k, False: 432]
  ------------------
  232|  46.1k|    result = result % (range + 1);
  233|       |
  234|  46.5k|  return static_cast<T>(static_cast<uint64_t>(min) + result);
  235|  46.5k|}
_ZN18FuzzedDataProvider15ConsumeIntegralIjEET_v:
  195|    432|template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
  196|    432|  return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
  197|    432|                                std::numeric_limits<T>::max());
  198|    432|}
_ZN18FuzzedDataProvider22ConsumeIntegralInRangeIjEET_S1_S1_:
  205|    864|T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
  206|    864|  static_assert(std::is_integral<T>::value, "An integral type is required.");
  207|    864|  static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
  208|       |
  209|    864|  if (min > max)
  ------------------
  |  Branch (209:7): [True: 0, False: 864]
  ------------------
  210|      0|    abort();
  211|       |
  212|       |  // Use the biggest type possible to hold the range and the result.
  213|    864|  uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
  214|    864|  uint64_t result = 0;
  215|    864|  size_t offset = 0;
  216|       |
  217|  3.88k|  while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
  ------------------
  |  Branch (217:10): [True: 3.13k, False: 751]
  |  Branch (217:43): [True: 3.13k, False: 0]
  ------------------
  218|  3.88k|         remaining_bytes_ != 0) {
  ------------------
  |  Branch (218:10): [True: 3.02k, False: 113]
  ------------------
  219|       |    // Pull bytes off the end of the seed data. Experimentally, this seems to
  220|       |    // allow the fuzzer to more easily explore the input space. This makes
  221|       |    // sense, since it works by modifying inputs that caused new code to run,
  222|       |    // and this data is often used to encode length of data read by
  223|       |    // |ConsumeBytes|. Separating out read lengths makes it easier modify the
  224|       |    // contents of the data that is actually read.
  225|  3.02k|    --remaining_bytes_;
  226|  3.02k|    result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
  227|  3.02k|    offset += CHAR_BIT;
  228|  3.02k|  }
  229|       |
  230|       |  // Avoid division by 0, in case |range + 1| results in overflow.
  231|    864|  if (range != std::numeric_limits<decltype(range)>::max())
  ------------------
  |  Branch (231:7): [True: 864, False: 0]
  ------------------
  232|    864|    result = result % (range + 1);
  233|       |
  234|    864|  return static_cast<T>(static_cast<uint64_t>(min) + result);
  235|    864|}
_ZN18FuzzedDataProvider15ConsumeIntegralIhEET_v:
  195|  91.9k|template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
  196|  91.9k|  return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
  197|  91.9k|                                std::numeric_limits<T>::max());
  198|  91.9k|}
_ZN18FuzzedDataProvider22ConsumeIntegralInRangeIhEET_S1_S1_:
  205|  91.9k|T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
  206|  91.9k|  static_assert(std::is_integral<T>::value, "An integral type is required.");
  207|  91.9k|  static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
  208|       |
  209|  91.9k|  if (min > max)
  ------------------
  |  Branch (209:7): [True: 0, False: 91.9k]
  ------------------
  210|      0|    abort();
  211|       |
  212|       |  // Use the biggest type possible to hold the range and the result.
  213|  91.9k|  uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
  214|  91.9k|  uint64_t result = 0;
  215|  91.9k|  size_t offset = 0;
  216|       |
  217|   110k|  while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
  ------------------
  |  Branch (217:10): [True: 91.9k, False: 18.9k]
  |  Branch (217:43): [True: 91.9k, False: 0]
  ------------------
  218|   110k|         remaining_bytes_ != 0) {
  ------------------
  |  Branch (218:10): [True: 18.9k, False: 73.0k]
  ------------------
  219|       |    // Pull bytes off the end of the seed data. Experimentally, this seems to
  220|       |    // allow the fuzzer to more easily explore the input space. This makes
  221|       |    // sense, since it works by modifying inputs that caused new code to run,
  222|       |    // and this data is often used to encode length of data read by
  223|       |    // |ConsumeBytes|. Separating out read lengths makes it easier modify the
  224|       |    // contents of the data that is actually read.
  225|  18.9k|    --remaining_bytes_;
  226|  18.9k|    result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
  227|  18.9k|    offset += CHAR_BIT;
  228|  18.9k|  }
  229|       |
  230|       |  // Avoid division by 0, in case |range + 1| results in overflow.
  231|  91.9k|  if (range != std::numeric_limits<decltype(range)>::max())
  ------------------
  |  Branch (231:7): [True: 91.9k, False: 0]
  ------------------
  232|  91.9k|    result = result % (range + 1);
  233|       |
  234|  91.9k|  return static_cast<T>(static_cast<uint64_t>(min) + result);
  235|  91.9k|}
_ZN18FuzzedDataProvider11ConsumeBoolEv:
  289|  91.9k|inline bool FuzzedDataProvider::ConsumeBool() {
  290|  91.9k|  return 1 & ConsumeIntegral<uint8_t>();
  291|  91.9k|}
_ZN18FuzzedDataProvider14CopyAndAdvanceEPvm:
  339|    432|                                               size_t num_bytes) {
  340|    432|  std::memcpy(destination, data_ptr_, num_bytes);
  341|    432|  Advance(num_bytes);
  342|    432|}
_ZN18FuzzedDataProvider7AdvanceEm:
  344|    432|inline void FuzzedDataProvider::Advance(size_t num_bytes) {
  345|    432|  if (num_bytes > remaining_bytes_)
  ------------------
  |  Branch (345:7): [True: 0, False: 432]
  ------------------
  346|      0|    abort();
  347|       |
  348|    432|  data_ptr_ += num_bytes;
  349|    432|  remaining_bytes_ -= num_bytes;
  350|    432|}
_ZN18FuzzedDataProvider12ConsumeBytesISt4byteEENSt3__16vectorIT_NS2_9allocatorIS4_EEEEm:
  109|    432|std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
  110|    432|  num_bytes = std::min(num_bytes, remaining_bytes_);
  111|    432|  return ConsumeBytes<T>(num_bytes, num_bytes);
  112|    432|}
_ZN18FuzzedDataProvider12ConsumeBytesISt4byteEENSt3__16vectorIT_NS2_9allocatorIS4_EEEEmm:
  353|    432|std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
  354|    432|  static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
  355|       |
  356|       |  // The point of using the size-based constructor below is to increase the
  357|       |  // odds of having a vector object with capacity being equal to the length.
  358|       |  // That part is always implementation specific, but at least both libc++ and
  359|       |  // libstdc++ allocate the requested number of bytes in that constructor,
  360|       |  // which seems to be a natural choice for other implementations as well.
  361|       |  // To increase the odds even more, we also call |shrink_to_fit| below.
  362|    432|  std::vector<T> result(size);
  363|    432|  if (size == 0) {
  ------------------
  |  Branch (363:7): [True: 0, False: 432]
  ------------------
  364|      0|    if (num_bytes != 0)
  ------------------
  |  Branch (364:9): [True: 0, False: 0]
  ------------------
  365|      0|      abort();
  366|      0|    return result;
  367|      0|  }
  368|       |
  369|    432|  CopyAndAdvance(result.data(), num_bytes);
  370|       |
  371|       |  // Even though |shrink_to_fit| is also implementation specific, we expect it
  372|       |  // to provide an additional assurance in case vector's constructor allocated
  373|       |  // a buffer which is larger than the actual amount of data we put inside it.
  374|    432|  result.shrink_to_fit();
  375|    432|  return result;
  376|    432|}

_Z36chacha20_split_keystream_fuzz_targetNSt3__14spanIKhLm18446744073709551615EEE:
  133|    432|{
  134|    432|    FuzzedDataProvider provider{buffer.data(), buffer.size()};
  135|    432|    ChaCha20SplitFuzz<false>(provider);
  136|    432|}
crypto_chacha20.cpp:_ZN12_GLOBAL__N_117ChaCha20SplitFuzzILb0EEEvR18FuzzedDataProvider:
   60|    432|{
   61|       |    // Determine key, iv, start position, length.
   62|    432|    auto key_bytes = ConsumeFixedLengthByteVector<std::byte>(provider, ChaCha20::KEYLEN);
   63|    432|    uint64_t iv = provider.ConsumeIntegral<uint64_t>();
   64|    432|    uint32_t iv_prefix = provider.ConsumeIntegral<uint32_t>();
   65|    432|    uint64_t total_bytes = provider.ConsumeIntegralInRange<uint64_t>(0, 1000000);
   66|       |    /* ~x = 2^BITS - 1 - x, so ~(total_bytes >> 6) is the maximal seek position. */
   67|    432|    uint32_t seek = provider.ConsumeIntegralInRange<uint32_t>(0, ~(uint32_t)(total_bytes >> 6));
   68|       |
   69|       |    // Initialize two ChaCha20 ciphers, with the same key/iv/position.
   70|    432|    ChaCha20 crypt1(key_bytes);
   71|    432|    ChaCha20 crypt2(key_bytes);
   72|    432|    crypt1.Seek({iv_prefix, iv}, seek);
   73|    432|    crypt2.Seek({iv_prefix, iv}, seek);
   74|       |
   75|       |    // Construct vectors with data.
   76|    432|    std::vector<std::byte> data1, data2;
   77|    432|    data1.resize(total_bytes);
   78|    432|    data2.resize(total_bytes);
   79|       |
   80|       |    // If using Crypt(), initialize data1 and data2 with the same InsecureRandomContext based
   81|       |    // stream.
   82|       |    if constexpr (UseCrypt) {
   83|       |        InsecureRandomContext(provider.ConsumeIntegral<uint64_t>()).fillrand(data1);
   84|       |        std::copy(data1.begin(), data1.end(), data2.begin());
   85|       |    }
   86|       |
   87|       |    // Whether UseCrypt is used or not, the two byte arrays must match.
   88|    432|    assert(data1 == data2);
   89|       |
   90|       |    // Encrypt data1, the whole array at once.
   91|       |    if constexpr (UseCrypt) {
   92|       |        crypt1.Crypt(data1, data1);
   93|    432|    } else {
   94|    432|        crypt1.Keystream(data1);
   95|    432|    }
   96|       |
   97|       |    // Encrypt data2, in at most 256 chunks.
   98|    432|    uint64_t bytes2 = 0;
   99|    432|    int iter = 0;
  100|  46.1k|    while (true) {
  ------------------
  |  Branch (100:12): [Folded - Ignored]
  ------------------
  101|  46.1k|        bool is_last = (iter == 255) || (bytes2 == total_bytes) || provider.ConsumeBool();
  ------------------
  |  Branch (101:24): [True: 170, False: 45.9k]
  |  Branch (101:41): [True: 68, False: 45.8k]
  |  Branch (101:68): [True: 194, False: 45.6k]
  ------------------
  102|  46.1k|        ++iter;
  103|       |        // Determine how many bytes to encrypt in this chunk: a fuzzer-determined
  104|       |        // amount for all but the last chunk (which processes all remaining bytes).
  105|  46.1k|        uint64_t now = is_last ? total_bytes - bytes2 :
  ------------------
  |  Branch (105:24): [True: 432, False: 45.6k]
  ------------------
  106|  46.1k|            provider.ConsumeIntegralInRange<uint64_t>(0, total_bytes - bytes2);
  107|       |        // For each chunk, consider using Crypt() even when UseCrypt is false.
  108|       |        // This tests that Keystream() has the same behavior as Crypt() applied
  109|       |        // to 0x00 input bytes.
  110|  46.1k|        if (UseCrypt || provider.ConsumeBool()) {
  ------------------
  |  Branch (110:13): [Folded - Ignored]
  |  Branch (110:25): [True: 1.90k, False: 44.2k]
  ------------------
  111|  1.90k|            crypt2.Crypt(Span{data2}.subspan(bytes2, now), Span{data2}.subspan(bytes2, now));
  112|  44.2k|        } else {
  113|  44.2k|            crypt2.Keystream(Span{data2}.subspan(bytes2, now));
  114|  44.2k|        }
  115|  46.1k|        bytes2 += now;
  116|  46.1k|        if (is_last) break;
  ------------------
  |  Branch (116:13): [True: 432, False: 45.6k]
  ------------------
  117|  46.1k|    }
  118|       |    // We should have processed everything now.
  119|    432|    assert(bytes2 == total_bytes);
  120|       |    // And the result should match.
  121|    432|    assert(data1 == data2);
  122|    432|}

LLVMFuzzerTestOneInput:
  222|    432|{
  223|    432|    test_one_input({data, size});
  224|    432|    return 0;
  225|    432|}
fuzz.cpp:_ZL14test_one_inputNSt3__14spanIKhLm18446744073709551615EEE:
   83|    432|{
   84|    432|    CheckGlobals check{};
   85|    432|    (*Assert(g_test_one_input))(buffer);
  ------------------
  |  |   85|    432|#define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val)
  ------------------
   86|    432|}

_Z28ConsumeFixedLengthByteVectorISt4byteENSt3__16vectorIT_NS1_9allocatorIS3_EEEER18FuzzedDataProviderm:
  257|    432|{
  258|    432|    static_assert(sizeof(B) == 1);
  259|    432|    auto random_bytes = fuzzed_data_provider.ConsumeBytes<B>(length);
  260|    432|    random_bytes.resize(length);
  261|    432|    return random_bytes;
  262|    432|}

_ZN12CheckGlobalsC2Ev:
   56|    432|CheckGlobals::CheckGlobals() : m_impl(std::make_unique<CheckGlobalsImpl>()) {}
_ZN12CheckGlobalsD2Ev:
   57|    432|CheckGlobals::~CheckGlobals() = default;
_ZN16CheckGlobalsImplC2Ev:
   17|    432|    {
   18|    432|        g_used_g_prng = false;
   19|    432|        g_seeded_g_prng_zero = false;
   20|    432|        g_used_system_time = false;
   21|    432|        SetMockTime(0s);
   22|    432|    }
_ZN16CheckGlobalsImplD2Ev:
   24|    432|    {
   25|    432|        if (g_used_g_prng && !g_seeded_g_prng_zero) {
  ------------------
  |  Branch (25:13): [True: 0, False: 432]
  |  Branch (25:30): [True: 0, False: 0]
  ------------------
   26|      0|            std::cerr << "\n\n"
   27|      0|                         "The current fuzz target used the global random state.\n\n"
   28|       |
   29|      0|                         "This is acceptable, but requires the fuzz target to call \n"
   30|      0|                         "SeedRandomStateForTest(SeedRand::ZEROS) in the first line \n"
   31|      0|                         "of the FUZZ_TARGET function.\n\n"
   32|       |
   33|      0|                         "An alternative solution would be to avoid any use of globals.\n\n"
   34|       |
   35|      0|                         "Without a solution, fuzz instability and non-determinism can lead \n"
   36|      0|                         "to non-reproducible bugs or inefficient fuzzing.\n\n"
   37|      0|                      << std::endl;
   38|      0|            std::abort(); // Abort, because AFL may try to recover from a std::exit
   39|      0|        }
   40|       |
   41|    432|        if (g_used_system_time) {
  ------------------
  |  Branch (41:13): [True: 0, False: 432]
  ------------------
   42|      0|            std::cerr << "\n\n"
   43|      0|                         "The current fuzz target accessed system time.\n\n"
   44|       |
   45|      0|                         "This is acceptable, but requires the fuzz target to call \n"
   46|      0|                         "SetMockTime() at the beginning of processing the fuzz input.\n\n"
   47|       |
   48|      0|                         "Without setting mock time, time-dependent behavior can lead \n"
   49|      0|                         "to non-reproducible bugs or inefficient fuzzing.\n\n"
   50|      0|                      << std::endl;
   51|      0|            std::abort();
   52|      0|        }
   53|    432|    }

_Z22inline_assertion_checkILb1EbEOT0_S1_PKciS3_S3_:
   52|    432|{
   53|    432|    if (IS_ASSERT || std::is_constant_evaluated() || G_FUZZING
  ------------------
  |  Branch (53:9): [Folded - Ignored]
  |  Branch (53:22): [Folded - Ignored]
  |  Branch (53:54): [Folded - Ignored]
  ------------------
   54|       |#ifdef ABORT_ON_FAILED_ASSUME
   55|       |        || true
   56|       |#endif
   57|    432|    ) {
   58|    432|        if (!val) {
  ------------------
  |  Branch (58:13): [True: 0, False: 432]
  ------------------
   59|      0|            assertion_fail(file, line, func, assertion);
   60|      0|        }
   61|    432|    }
   62|    432|    return std::forward<T>(val);
   63|    432|}
_Z22inline_assertion_checkILb1ERPKNSt3__18functionIFvNS0_4spanIKhLm18446744073709551615EEEEEEEOT0_SB_PKciSD_SD_:
   52|    432|{
   53|    432|    if (IS_ASSERT || std::is_constant_evaluated() || G_FUZZING
  ------------------
  |  Branch (53:9): [Folded - Ignored]
  |  Branch (53:22): [Folded - Ignored]
  |  Branch (53:54): [Folded - Ignored]
  ------------------
   54|       |#ifdef ABORT_ON_FAILED_ASSUME
   55|       |        || true
   56|       |#endif
   57|    432|    ) {
   58|    432|        if (!val) {
  ------------------
  |  Branch (58:13): [True: 0, False: 432]
  ------------------
   59|      0|            assertion_fail(file, line, func, assertion);
   60|      0|        }
   61|    432|    }
   62|    432|    return std::forward<T>(val);
   63|    432|}

_Z11SetMockTimeNSt3__16chrono8durationIxNS_5ratioILl1ELl1EEEEE:
   42|    432|{
   43|    432|    Assert(mock_time_in >= 0s);
  ------------------
  |  |   85|    432|#define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val)
  ------------------
   44|    432|    g_mock_time.store(mock_time_in, std::memory_order_relaxed);
   45|    432|}

