int foundation_rngV1_generate(uint8_t newkey[CHACHA_KEY_SIZE], uint8_t *dst, uint8_t key[CHACHA_KEY_SIZE], FsCountOf bytes)
{
	const int rounds = 20;
	uint8_t nonce[CHACHA_NONCE_SIZE] = { 0 };
	uint8_t buf[CHACHA_OUTPUT_SIZE]; /* for partial buffer */

	if (!bytes)
		return 0;
	for (; bytes >= CHACHA_OUTPUT_SIZE; bytes -= CHACHA_OUTPUT_SIZE, dst += CHACHA_OUTPUT_SIZE) {
		chacha_core(rounds, dst, key, nonce);
		if (++nonce[0] == 0)
			nonce[1]++;
	}

	assert(bytes < CHACHA_OUTPUT_SIZE);

	chacha_core(rounds, buf, key, nonce);
	int remaining = CHACHA_OUTPUT_SIZE - bytes;
	if (remaining >= CHACHA_KEY_SIZE) {
		memcpy(dst, buf, bytes);
		memcpy(newkey, buf + bytes, CHACHA_KEY_SIZE);
	} else {
		memcpy(dst, buf, bytes);
		if (++nonce[0] == 0)
			nonce[1]++;
		chacha_core(rounds, buf, key, nonce);
		memcpy(newkey, buf, CHACHA_KEY_SIZE);
	}
	memset(buf, 0, CHACHA_OUTPUT_SIZE);
	return 0;
}
void cryptonite_chacha_combine(uint8_t *dst, cryptonite_chacha_context *ctx, const uint8_t *src, uint32_t bytes)
{
    block out;
    cryptonite_chacha_state *st;
    int i;

    if (!bytes)
        return;

    /* xor the previous buffer first (if any) */
    if (ctx->prev_len > 0) {
        int to_copy = (ctx->prev_len < bytes) ? ctx->prev_len : bytes;
        for (i = 0; i < to_copy; i++)
            dst[i] = src[i] ^ ctx->prev[ctx->prev_ofs+i];
        memset(ctx->prev + ctx->prev_ofs, 0, to_copy);
        ctx->prev_len -= to_copy;
        ctx->prev_ofs += to_copy;
        src += to_copy;
        dst += to_copy;
        bytes -= to_copy;
    }

    if (bytes == 0)
        return;

    st = &ctx->st;

    /* xor new 64-bytes chunks and store the left over if any */
    for (; bytes >= 64; bytes -= 64, src += 64, dst += 64) {
        /* generate new chunk and update state */
        chacha_core(ctx->nb_rounds, &out, st);
        st->d[12] += 1;
        if (st->d[12] == 0)
            st->d[13] += 1;

        for (i = 0; i < 64; ++i)
            dst[i] = src[i] ^ out.b[i];
    }

    if (bytes > 0) {
        /* generate new chunk and update state */
        chacha_core(ctx->nb_rounds, &out, st);
        st->d[12] += 1;
        if (st->d[12] == 0)
            st->d[13] += 1;

        /* xor as much as needed */
        for (i = 0; i < bytes; i++)
            dst[i] = src[i] ^ out.b[i];

        /* copy the left over in the buffer */
        ctx->prev_len = 64 - bytes;
        ctx->prev_ofs = i;
        for (; i < 64; i++) {
            ctx->prev[i] = out.b[i];
        }
    }
}
void cryptonite_chacha_random(uint32_t rounds, uint8_t *dst, cryptonite_chacha_state *st, uint32_t bytes)
{
    block out;

    if (!bytes)
        return;
    for (; bytes >= 16; bytes -= 16, dst += 16) {
        chacha_core(rounds, &out, st);
        memcpy(dst, out.b + 40, 16);
        cryptonite_chacha_init_core(st, 32, out.b, 8, out.b + 32);
    }
    if (bytes) {
        chacha_core(rounds, &out, st);
        memcpy(dst, out.b + 40, bytes);
        cryptonite_chacha_init_core(st, 32, out.b, 8, out.b + 32);
    }
}