+#define SUPER_SIZE 256
+/*
+ * For 256-byte buffer filled with 256 bytes from 0 to 255;
+ * Digest them 256 times from the buffer end with lengths from 0 to 256,
+ * and from beginning of the buffer with lengths from 0 to 256;
+ * Each produced digest is digested again into final sum.
+ */
+static int do_stest_once(const struct hash_testvec *tv, unsigned int shifts)
+{
+ unsigned char *ibuf, *md;
+ T(ibuf = OPENSSL_zalloc(SUPER_SIZE + shifts));
+
+ /* fill with pattern */
+ unsigned int len;
+ for (len = 0; len < SUPER_SIZE; len++)
+ ibuf[shifts + len] = len & 0xff;
+
+ const EVP_MD *mdtype;
+ T(mdtype = EVP_get_digestbynid(tv->nid));
+ OPENSSL_assert(tv->nid == EVP_MD_type(mdtype));
+ EVP_MD_CTX *ctx, *ctx2;
+ T(ctx = EVP_MD_CTX_new());
+ T(ctx2 = EVP_MD_CTX_new());
+ T(EVP_DigestInit(ctx2, mdtype));
+ OPENSSL_assert(tv->nid == EVP_MD_CTX_type(ctx2));
+ OPENSSL_assert(EVP_MD_block_size(mdtype) == tv->block_size);
+ OPENSSL_assert(EVP_MD_CTX_size(ctx2) == tv->mdsize);
+ OPENSSL_assert(EVP_MD_CTX_block_size(ctx2) == tv->block_size);
+
+ const unsigned int mdlen = EVP_MD_size(mdtype);
+ OPENSSL_assert(mdlen == tv->mdsize);
+ T(md = OPENSSL_zalloc(mdlen + shifts));
+ md += shifts; /* test for output digest alignment problems */
+
+ /* digest cycles */
+ for (len = 0; len < SUPER_SIZE; len++) {
+ /* for each len digest len bytes from the end of buf */
+ T(EVP_DigestInit(ctx, mdtype));
+ T(EVP_DigestUpdate(ctx, ibuf + shifts + SUPER_SIZE - len, len));
+ T(EVP_DigestFinal(ctx, md, NULL));
+ T(EVP_DigestUpdate(ctx2, md, mdlen));
+ }
+
+ for (len = 0; len < SUPER_SIZE; len++) {
+ /* for each len digest len bytes from the beginning of buf */
+ T(EVP_DigestInit(ctx, mdtype));
+ T(EVP_DigestUpdate(ctx, ibuf + shifts, len));
+ T(EVP_DigestFinal(ctx, md, NULL));
+ T(EVP_DigestUpdate(ctx2, md, mdlen));
+ }
+
+ OPENSSL_free(ibuf);
+ EVP_MD_CTX_free(ctx);
+
+ T(EVP_DigestFinal(ctx2, md, &len));
+ EVP_MD_CTX_free(ctx2);
+
+ if (len != mdlen) {
+ printf(cRED "digest output len mismatch %u != %u (expected)\n" cNORM,
+ len, mdlen);
+ goto err;
+ }
+
+ if (memcmp(md, tv->digest, mdlen) != 0) {
+ printf(cRED "digest mismatch\n" cNORM);
+
+ unsigned int i;
+ printf(" Expected value is: ");
+ for (i = 0; i < mdlen; i++)
+ printf("\\x%02x", md[i]);
+ printf("\n");
+ goto err;
+ }
+
+ OPENSSL_free(md - shifts);
+ return 0;
+err:
+ OPENSSL_free(md - shifts);
+ return 1;
+}
+
+/* do different block sizes and different memory offsets */
+static int do_stest(const struct hash_testvec *tv)
+{
+ int ret = 0;
+
+ printf(cBLUE "Test 2 %s: " cNORM, tv->name);
+ fflush(stdout);
+
+ unsigned int shifts;
+ for (shifts = 0; shifts < 16 && !ret; shifts++)
+ ret |= do_stest_once(tv, shifts);
+
+ if (!ret)
+ printf(cGREEN "success\n" cNORM);
+ else
+ printf(cRED "fail\n" cNORM);
+ return 0;
+}
+