author Andy Polyakov Wed, 2 Nov 2016 19:13:53 +0000 (20:13 +0100) committer Andy Polyakov Fri, 11 Nov 2016 12:32:35 +0000 (13:32 +0100)
Reviewed-by: Richard Levitte <levitte@openssl.org>

index 9e08c504c75e0ecc0ce25dc6591064abd982f1a6..1056f89281898837f0f274db5ba3f5d8292c907b 100644 (file)
#define ROL64(a, offset) ((offset) ? (((a) << offset) | ((a) >> (64-offset))) \
: a)

+#if defined(KECCAK_REF)
+/*
+ * This is straightforward or "maximum clarity" implementation aiming
+ * to resemble section 3.2 of the FIPS PUB 202 "SHA-3 Standard:
+ * Permutation-Based Hash and Extendible-Output Functions" as much as
+ * possible. With one caveat. Because of the way C stores matrices,
+ * references to A[x,y] in the specification are presented as A[y][x].
+ * Implementation unrolls inner x-loops so that modulo 5 operations are
+ * explicitly pre-computed.
+ */
static void Theta(uint64_t A)
{
uint64_t C, D;
size_t y;

-    C = A ^ A ^ A ^ A ^ A;
-    C = A ^ A ^ A ^ A ^ A;
-    C = A ^ A ^ A ^ A ^ A;
-    C = A ^ A ^ A ^ A ^ A;
-    C = A ^ A ^ A ^ A ^ A;
+    C = A;
+    C = A;
+    C = A;
+    C = A;
+    C = A;
+
+    for (y = 1; y < 5; y++) {
+        C ^= A[y];
+        C ^= A[y];
+        C ^= A[y];
+        C ^= A[y];
+        C ^= A[y];
+    }

D = ROL64(C, 1) ^ C;
D = ROL64(C, 1) ^ C;
@@ -151,6 +169,568 @@ void KeccakF1600(uint64_t A)
}
}

+#elif defined(KECCAK_1X)
+/*
+ * This implementation is optimization of above code featuring unroll
+ * of even y-loops, their fusion and code motion. It also minimizes
+ * temporary storage. Compiler would normally do all these things for
+ * you, purpose of manual optimization is to provide "unobscured"
+ * reference for assembly implementation [in case this approach is
+ * chosen for implementation on some platform]. In the nutshell it's
+ * equivalent of "plane-per-plane processing" approach discussed in
+ * section 2.4 of "Keccak implementation overview".
+ */
+static void Round(uint64_t A, size_t i)
+{
+    uint64_t C, D, T;
+    static const unsigned char rhotates = {
+        {  0,  1, 62, 28, 27 },
+        { 36, 44,  6, 55, 20 },
+        {  3, 10, 43, 25, 39 },
+        { 41, 45, 15, 21,  8 },
+        { 18,  2, 61, 56, 14 }
+    };
+    static const uint64_t iotas[] = {
+        0x0000000000000001U, 0x0000000000008082U, 0x800000000000808aU,
+        0x8000000080008000U, 0x000000000000808bU, 0x0000000080000001U,
+        0x8000000080008081U, 0x8000000000008009U, 0x000000000000008aU,
+        0x0000000000000088U, 0x0000000080008009U, 0x000000008000000aU,
+        0x000000008000808bU, 0x800000000000008bU, 0x8000000000008089U,
+        0x8000000000008003U, 0x8000000000008002U, 0x8000000000000080U,
+        0x000000000000800aU, 0x800000008000000aU, 0x8000000080008081U,
+        0x8000000000008080U, 0x0000000080000001U, 0x8000000080008008U
+    };
+
+    assert(i < (sizeof(iotas) / sizeof(iotas)));
+
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    C =       A ^ D; /* rotate by 0 */
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    T = A ^ D; /* borrow T */
+    T = A ^ D;
+    T = A ^ D;
+    T = A ^ D;
+    T = A ^ D;
+
+    A = C ^ (~C & C) ^ iotas[i];
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+
+    C = ROL64(T,        rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    T = A ^ D;
+    T = A ^ D; /* borrow T */
+    T = A ^ D;
+    T = A ^ D;
+    T = A ^ D; /* borrow T */
+
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+
+    C = ROL64(T,        rhotates);
+    C = ROL64(T,        rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+
+    C = ROL64(T,        rhotates);
+    C = ROL64(T,        rhotates);
+    C = ROL64(T,        rhotates); /* originally A */
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+
+    C = ROL64(T,        rhotates);
+    C = ROL64(T,        rhotates);
+    C = ROL64(T,        rhotates); /* originally A */
+    C = ROL64(T,        rhotates); /* originally A */
+    C = ROL64(A ^ D, rhotates);
+
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+    A = C ^ (~C & C);
+}
+
+void KeccakF1600(uint64_t A)
+{
+    size_t i;
+
+    for (i = 0; i < 24; i++) {
+        Round(A, i);
+    }
+}
+
+#elif defined(KECCAK_2X)
+/*
+ * This implementation is variant of KECCAK_1X above with outer-most
+ * round loop unrolled twice. This allows to take temporary storage
+ * out of round procedure and simplify references to it by alternating
+ * it with actual data (see round loop below). Just like original, it's
+ * rather meant as reference for an assembly implementation. It's likely
+ * to provide best instruction per processed byte ratio at minimal
+ * round unroll factor...
+ */
+static void Round(uint64_t R, uint64_t A, size_t i)
+{
+    uint64_t C, D;
+    static const unsigned char rhotates = {
+        {  0,  1, 62, 28, 27 },
+        { 36, 44,  6, 55, 20 },
+        {  3, 10, 43, 25, 39 },
+        { 41, 45, 15, 21,  8 },
+        { 18,  2, 61, 56, 14 }
+    };
+    static const uint64_t iotas[] = {
+        0x0000000000000001U, 0x0000000000008082U, 0x800000000000808aU,
+        0x8000000080008000U, 0x000000000000808bU, 0x0000000080000001U,
+        0x8000000080008081U, 0x8000000000008009U, 0x000000000000008aU,
+        0x0000000000000088U, 0x0000000080008009U, 0x000000008000000aU,
+        0x000000008000808bU, 0x800000000000008bU, 0x8000000000008089U,
+        0x8000000000008003U, 0x8000000000008002U, 0x8000000000000080U,
+        0x000000000000800aU, 0x800000008000000aU, 0x8000000080008081U,
+        0x8000000000008080U, 0x0000000080000001U, 0x8000000080008008U
+    };
+
+    assert(i < (sizeof(iotas) / sizeof(iotas)));
+
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    C =       A ^ D; /* rotate by 0 */
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    R = C ^ (~C & C) ^ iotas[i];
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+    C = ROL64(A ^ D, rhotates);
+
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+    R = C ^ (~C & C);
+}
+
+void KeccakF1600(uint64_t A)
+{
+    uint64_t T;
+    size_t i;
+
+    for (i = 0; i < 24; i += 2) {
+        Round(T, A, i);
+        Round(A, T, i + 1);
+    }
+}
+
+#else
+/*
+ * This implementation is KECCAK_1X from above combined 4 times with
+ * a twist that allows to omit temporary storage and perform in-place
+ * processing. It's discussed in section 2.5 of "Keccak implementation
+ * overview". It's likely to be best suited for processors with large
+ * register bank...
+ */
+static void FourRounds(uint64_t A, size_t i)
+{
+    uint64_t B, C, D;
+    static const unsigned char rhotates = {
+        {  0,  1, 62, 28, 27 },
+        { 36, 44,  6, 55, 20 },
+        {  3, 10, 43, 25, 39 },
+        { 41, 45, 15, 21,  8 },
+        { 18,  2, 61, 56, 14 }
+    };
+    static const uint64_t iotas[] = {
+        0x0000000000000001U, 0x0000000000008082U, 0x800000000000808aU,
+        0x8000000080008000U, 0x000000000000808bU, 0x0000000080000001U,
+        0x8000000080008081U, 0x8000000000008009U, 0x000000000000008aU,
+        0x0000000000000088U, 0x0000000080008009U, 0x000000008000000aU,
+        0x000000008000808bU, 0x800000000000008bU, 0x8000000000008089U,
+        0x8000000000008003U, 0x8000000000008002U, 0x8000000000000080U,
+        0x000000000000800aU, 0x800000008000000aU, 0x8000000080008081U,
+        0x8000000000008080U, 0x0000000080000001U, 0x8000000080008008U
+    };
+
+    assert(i <= (sizeof(iotas) / sizeof(iotas) - 4));
+
+    /* Round 4*n */
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+    C = A ^ A ^ A ^ A ^ A;
+
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    B =       A ^ D; /* rotate by 0 */
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C = A = B ^ (~B & B) ^ iotas[i];
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    /* Round 4*n+1 */
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    B =       A ^ D; /* rotate by 0 */
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C = A = B ^ (~B & B) ^ iotas[i + 1];
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    /* Round 4*n+2 */
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    B =       A ^ D; /* rotate by 0 */
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C = A = B ^ (~B & B) ^ iotas[i + 2];
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+    C = A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+    C ^= A = B ^ (~B & B);
+
+    /* Round 4*n+3 */
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+    D = ROL64(C, 1) ^ C;
+
+    B =       A ^ D; /* rotate by 0 */
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    /* C = */ A = B ^ (~B & B) ^ iotas[i + 3];
+    /* C = */ A = B ^ (~B & B);
+    /* C = */ A = B ^ (~B & B);
+    /* C = */ A = B ^ (~B & B);
+    /* C = */ A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+    B = ROL64(A ^ D, rhotates);
+
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+    /* C ^= */ A = B ^ (~B & B);
+}
+
+void KeccakF1600(uint64_t A)
+{
+    size_t i;
+
+    for (i = 0; i < 24; i += 4) {
+        FourRounds(A, i);
+    }
+}
+
+#endif
+
/*
* SHA3_absorb can be called multiple times, but at each invocation
* largest multiple of |r| out of |len| bytes are processed. Then