]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Add blake2b_set_key and blake2s_set_key, and more tests. blake2
authorNiels Möller <nisse@lysator.liu.se>
Sun, 16 Nov 2025 15:14:37 +0000 (16:14 +0100)
committerNiels Möller <nisse@lysator.liu.se>
Sun, 16 Nov 2025 15:14:37 +0000 (16:14 +0100)
blake2.h
blake2b.c
blake2s.c
testsuite/blake2b-test.c
testsuite/blake2s-test.c

index 8741f5a473b664fb16edde467230134584716774..0719a3dbc173df609fa3aa7d16032f50bd5be33b 100644 (file)
--- a/blake2.h
+++ b/blake2.h
@@ -42,16 +42,19 @@ extern "C" {
 
 /* Name mangling */
 #define blake2b_init nettle_blake2b_init
+#define blake2b_set_key nettle_blake2b_set_key
 #define blake2b_update nettle_blake2b_update
 #define blake2b_digest nettle_blake2b_digest
 #define blake2b_512_init nettle_blake2b_512_init
 #define blake2s_init nettle_blake2s_init
+#define blake2s_set_key nettle_blake2s_set_key
 #define blake2s_update nettle_blake2s_update
 #define blake2s_digest nettle_blake2s_digest
 #define blake2s_256_init nettle_blake2s_256_init
 
 #define BLAKE2B_DIGEST_SIZE 64
 #define BLAKE2B_BLOCK_SIZE 128
+#define BLAKE2B_KEY_SIZE 64
 
 struct blake2b_ctx
 {
@@ -63,7 +66,12 @@ struct blake2b_ctx
 };
 
 void
-blake2b_init (struct blake2b_ctx *ctx, unsigned digest_size);
+blake2b_init (struct blake2b_ctx *ctx, size_t digest_size);
+
+/* Alternative initialization function with key. */
+void
+blake2b_set_key(struct blake2b_ctx *ctx, size_t key_size, const uint8_t *key,
+               size_t digest_size);
 
 void
 blake2b_update (struct blake2b_ctx *ctx,
@@ -77,6 +85,7 @@ blake2b_512_init (struct blake2b_ctx *ctx);
 
 #define BLAKE2S_DIGEST_SIZE 32
 #define BLAKE2S_BLOCK_SIZE 64
+#define BLAKE2S_KEY_SIZE 32
 
 struct blake2s_ctx
 {
@@ -88,7 +97,12 @@ struct blake2s_ctx
 };
 
 void
-blake2s_init (struct blake2s_ctx *ctx, unsigned digest_size);
+blake2s_init (struct blake2s_ctx *ctx, size_t digest_size);
+
+/* Alternative initialization function with key. */
+void
+blake2s_set_key(struct blake2s_ctx *ctx, size_t key_size, const uint8_t *key,
+               size_t digest_size);
 
 void
 blake2s_update (struct blake2s_ctx *ctx,
index 153acd33b54d4ae5a6418fff7aae585acc573b96..d8fe07bb28f4d86cf8d6ef36599dbc614480cd5d 100644 (file)
--- a/blake2b.c
+++ b/blake2b.c
@@ -110,16 +110,37 @@ blake2b_compress (uint64_t *h, const uint8_t *input,
     h[i] ^= v[i] ^ v[8+i];
 }
 
-void
-blake2b_init (struct blake2b_ctx *ctx, unsigned digest_size)
+/* Initializes everything but ctx->index. */
+static void
+blake2b_init_internal (struct blake2b_ctx *ctx, size_t key_size,size_t digest_size)
 {
   assert (digest_size > 0 && digest_size <= BLAKE2B_DIGEST_SIZE);
   memcpy (ctx->state, iv, sizeof (ctx->state));
-  ctx->state[0] ^= 0x01010000 ^ digest_size;
-  ctx->count_low = ctx->count_high = ctx->index = 0;
+  ctx->state[0] ^= 0x01010000 ^ ((key_size << 8) | digest_size);
+  ctx->count_high = ctx->count_low = 0;
   ctx->digest_size = digest_size;
 }
 
+void
+blake2b_init (struct blake2b_ctx *ctx, size_t digest_size)
+{
+  ctx->index = 0;
+  blake2b_init_internal (ctx, 0, digest_size);
+}
+
+void
+blake2b_set_key(struct blake2b_ctx *ctx, size_t key_size, const uint8_t *key,
+               size_t digest_size)
+{
+  assert (key_size > 0 && key_size <= BLAKE2B_KEY_SIZE);
+
+  memcpy (ctx->block, key, key_size);
+  memset (ctx->block + key_size, 0, sizeof(ctx->block) - key_size);
+  ctx->index = sizeof(ctx->block);
+
+  blake2b_init_internal (ctx, key_size, digest_size);
+}
+
 void
 blake2b_update (struct blake2b_ctx *ctx,
                size_t length, const uint8_t *data)
index 0e585b070f7275537b583116be8d345466e26ce7..b7effbbd387c15ad9cb836fe47c283352b464e5e 100644 (file)
--- a/blake2s.c
+++ b/blake2s.c
@@ -105,16 +105,37 @@ blake2s_compress (uint32_t *h, const uint8_t *input,
     h[i] ^= v[i] ^ v[8+i];
 }
 
-void
-blake2s_init (struct blake2s_ctx *ctx, unsigned digest_size)
+/* Initializes everything but ctx->index. */
+static void
+blake2s_init_internal (struct blake2s_ctx *ctx, size_t key_size, size_t digest_size)
 {
   assert (digest_size > 0 && digest_size <= BLAKE2S_DIGEST_SIZE);
   memcpy (ctx->state, iv, sizeof (ctx->state));
-  ctx->state[0] ^= 0x01010000 ^ digest_size;
-  ctx->count = ctx->index = 0;
+  ctx->state[0] ^= 0x01010000 ^ ((key_size << 8) | digest_size);
+  ctx->count = 0;
   ctx->digest_size = digest_size;
 }
 
+void
+blake2s_init (struct blake2s_ctx *ctx, size_t digest_size)
+{
+  ctx->index = 0;
+  blake2s_init_internal (ctx, 0, digest_size);
+}
+
+void
+blake2s_set_key(struct blake2s_ctx *ctx, size_t key_size, const uint8_t *key,
+               size_t digest_size)
+{
+  assert (key_size > 0 && key_size <= BLAKE2S_KEY_SIZE);
+
+  memcpy (ctx->block, key, key_size);
+  memset (ctx->block + key_size, 0, sizeof(ctx->block) - key_size);
+  ctx->index = sizeof(ctx->block);
+
+  blake2s_init_internal (ctx, key_size, digest_size);
+}
+
 void
 blake2s_update (struct blake2s_ctx *ctx,
                size_t length, const uint8_t *data)
index 1843cc96ffd022e513ce967aa6b9952ce2bda605..110a79add8bc4eecd884bc684c355acf00403e37 100644 (file)
 #include "testutils.h"
 
+#include "blake2.h"
 #include "non-nettle.h"
 
+static void
+blake2b (size_t digest_size, uint8_t *digest,
+        size_t size, const uint8_t *data)
+{
+  struct blake2b_ctx ctx;
+  blake2b_init (&ctx, digest_size);
+  blake2b_update (&ctx, size, data);
+  blake2b_digest (&ctx, digest);
+}
+
+static void
+blake2b_key (size_t digest_size, uint8_t *digest,
+            size_t key_size, const uint8_t *key,
+            size_t size, const uint8_t *data)
+{
+  struct blake2b_ctx ctx;
+  blake2b_set_key (&ctx, key_size, key, digest_size);
+  blake2b_update (&ctx, size, data);
+  blake2b_digest (&ctx, digest);
+}
+
+static void
+test_blake2b (const struct tstring *key, const struct tstring *data,
+             const struct tstring *digest)
+{
+  uint8_t buf [BLAKE2B_DIGEST_SIZE];
+  ASSERT (digest->length <= BLAKE2B_DIGEST_SIZE);
+  if (key)
+    blake2b_key (digest->length, buf, key->length, key->data, data->length, data->data);
+  else
+    blake2b (digest->length, buf, data->length, data->data);
+  if (!MEMEQ(digest->length, buf, digest->data))
+    {
+      fprintf (stderr, "blake2b failed:\n");
+      if (key)
+       {
+         fprintf (stderr, "key:");
+         tstring_print_hex (key);
+       }
+      fprintf (stderr, "data:");
+      tstring_print_hex (data);
+      fprintf (stderr, "digest:");
+      print_hex (digest->length, buf);
+      fprintf (stderr, "expect:");
+      tstring_print_hex (digest);
+      FAIL ();
+    }
+}
+
+/* Self test from RFC7693 */
+
+// Deterministic sequences (Fibonacci generator).
+static void
+selftest_seq(uint8_t *out, size_t len, uint32_t seed)
+{
+  size_t i;
+  uint32_t t, a , b;
+
+  a = 0xDEAD4BAD * seed;              // prime
+  b = 1;
+
+  for (i = 0; i < len; i++) {         // fill the buf
+    t = a + b;
+    a = b;
+    b = t;
+    out[i] = (t >> 24) & 0xFF;
+  }
+}
+
+static void
+blake2b_selftest (void)
+{
+  // grand hash of hash results
+  static const uint8_t blake2b_res[32] = {
+    0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
+    0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
+    0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
+    0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75
+  };
+  // parameter sets
+  static const size_t b2b_md_len[4] = { 20, 32, 48, 64 };
+  static const size_t b2b_in_len[6] = { 0, 3, 128, 129, 255, 1024 };
+
+  size_t i, j, outlen, inlen;
+  uint8_t in[1024], md[64], key[64];
+  struct blake2b_ctx ctx;
+
+  // 256-bit hash for testing
+  blake2b_init(&ctx, 32);
+
+  for (i = 0; i < 4; i++) {
+    outlen = b2b_md_len[i];
+    for (j = 0; j < 6; j++) {
+      inlen = b2b_in_len[j];
+
+      selftest_seq (in, inlen, inlen);     // unkeyed hash
+      blake2b (outlen, md, inlen, in);
+      blake2b_update (&ctx, outlen, md);   // hash the hash
+
+      selftest_seq (key, outlen, outlen);  // keyed hash
+      blake2b_key (outlen, md, outlen, key, inlen, in);
+      blake2b_update (&ctx, outlen, md);   // hash the hash
+    }
+  }
+
+  // compute and compare the hash of hashes
+  blake2b_digest (&ctx, md);
+  ASSERT (MEMEQ (sizeof(blake2b_res), blake2b_res, md));
+}
+
 void
 test_main(void)
 {
-  test_hash(&nettle_blake2b_512, SDATA("abc"),
-           SHEX("BA 80 A5 3F 98 1C 4D 0D 6A 27 97 B6 9F 12 F6 E9"
-                "4C 21 2F 14 68 5A C4 B7 4B 12 BB 6F DB FF A2 D1"
-                "7D 87 C5 39 2A AB 79 2D C2 52 D5 DE 45 33 CC 95"
-                "18 D3 8A A8 DB F1 92 5A B9 23 86 ED D4 00 99 23"));
+  /* RFC 7693 */
+  test_hash (&nettle_blake2b_512, SDATA("abc"),
+            SHEX("BA 80 A5 3F 98 1C 4D 0D 6A 27 97 B6 9F 12 F6 E9"
+                 "4C 21 2F 14 68 5A C4 B7 4B 12 BB 6F DB FF A2 D1"
+                 "7D 87 C5 39 2A AB 79 2D C2 52 D5 DE 45 33 CC 95"
+                 "18 D3 8A A8 DB F1 92 5A B9 23 86 ED D4 00 99 23"));
+  /* Selected from
+     https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2b-kat.txt */
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX(""),
+               SHEX("10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786"
+                    "b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"));
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("00"),
+               SHEX("961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4"
+                    "187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd"));
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("0001"),
+               SHEX("da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b"
+                    "983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965"));
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374ab"
+                    "c942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022"));
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
+                    "40"),
+               SHEX("939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442"
+                    "da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c"));
+  test_blake2b (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
+                    "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+                    "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+                    "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
+                    "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                    "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                    "e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe"),
+               SHEX("142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e9248"
+                    "4be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461"));
+  blake2b_selftest ();
 }
index 2a4472845d0ec3a94e6a9ff0de64d20a03973416..bfdb72b72e75a82cde785fb3245975aa2e16f546 100644 (file)
 #include "testutils.h"
 
+#include "blake2.h"
 #include "non-nettle.h"
 
+// Convenience function for all-in-one computation.
+static void
+blake2s  (size_t digest_size, uint8_t *digest,
+         size_t size, const uint8_t *data)
+{
+  struct blake2s_ctx ctx;
+  blake2s_init (&ctx, digest_size);
+  blake2s_update (&ctx, size, data);
+  blake2s_digest (&ctx, digest);
+}
+
+static void
+blake2s_key (size_t digest_size, uint8_t *digest,
+            size_t key_size, const uint8_t *key,
+            size_t size, const uint8_t *data)
+{
+  struct blake2s_ctx ctx;
+  blake2s_set_key (&ctx, key_size, key, digest_size);
+  blake2s_update (&ctx, size, data);
+  blake2s_digest (&ctx, digest);
+}
+
+static void
+test_blake2s (const struct tstring *key, const struct tstring *data,
+             const struct tstring *digest)
+{
+  uint8_t buf [BLAKE2S_DIGEST_SIZE];
+  ASSERT (digest->length <= BLAKE2S_DIGEST_SIZE);
+  if (key)
+    blake2s_key (digest->length, buf, key->length, key->data, data->length, data->data);
+  else
+    blake2s (digest->length, buf, data->length, data->data);
+  if (!MEMEQ(digest->length, buf, digest->data))
+    {
+      fprintf (stderr, "blake2s failed:\n");
+      if (key)
+       {
+         fprintf (stderr, "key:");
+         tstring_print_hex (key);
+       }
+      fprintf (stderr, "data:");
+      tstring_print_hex (data);
+      fprintf (stderr, "digest:");
+      print_hex (digest->length, buf);
+      fprintf (stderr, "expect:");
+      tstring_print_hex (digest);
+      FAIL ();
+    }
+}
+
+/* Self test from RFC7693 */
+
+// Deterministic sequences (Fibonacci generator).
+static void
+selftest_seq(uint8_t *out, size_t len, uint32_t seed)
+{
+  size_t i;
+  uint32_t t, a , b;
+
+  a = 0xDEAD4BAD * seed;              // prime
+  b = 1;
+
+  for (i = 0; i < len; i++) {         // fill the buf
+    t = a + b;
+    a = b;
+    b = t;
+    out[i] = (t >> 24) & 0xFF;
+  }
+}
+
+static void
+blake2s_selftest (void)
+{
+  // Grand hash of hash results.
+  static const uint8_t blake2s_res[32] = {
+    0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD,
+    0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC,
+    0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87,
+    0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE
+  };
+  // Parameter sets.
+  static const size_t b2s_md_len[4] = { 16, 20, 28, 32 };
+  static const size_t b2s_in_len[6] = { 0,  3,  64, 65, 255, 1024 };
+
+  size_t i, j, outlen, inlen;
+  uint8_t in[1024], md[32], key[32];
+  struct blake2s_ctx ctx;
+
+  // 256-bit hash for testing.
+  blake2s_init(&ctx, 32);
+
+  for (i = 0; i < 4; i++) {
+    outlen = b2s_md_len[i];
+    for (j = 0; j < 6; j++) {
+      inlen = b2s_in_len[j];
+
+      selftest_seq (in, inlen, inlen);     // unkeyed hash
+      blake2s (outlen, md, inlen, in);
+      blake2s_update (&ctx, outlen, md);   // hash the hash
+
+      selftest_seq (key, outlen, outlen);  // keyed hash
+      blake2s_key (outlen, md, outlen, key, inlen, in);
+      blake2s_update (&ctx, outlen, md);   // hash the hash
+    }
+  }
+
+  // Compute and compare the hash of hashes.
+  blake2s_digest (&ctx, md);
+  ASSERT (MEMEQ (sizeof(blake2s_res), blake2s_res, md));
+}
+
 void
 test_main(void)
 {
   test_hash(&nettle_blake2s_256, SDATA("abc"),
            SHEX("50 8C 5E 8C 32 7C 14 E2 E1 A7 2B A3 4E EB 45 2F"
                 "37 45 8B 20 9E D6 3A 29 4D 99 9B 4C 86 67 59 82"));
+  /* Selected from
+     https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2s-kat.txt */
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX(""),
+               SHEX("48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"));
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("00"),
+               SHEX("40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1"));
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("0001"),
+               SHEX("6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803"));
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("c03bc642b20959cbe133a0303e0c1abff3e31ec8e1a328ec8565c36decff5265"));
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
+               SHEX("2c3e08176f760c6264c3a2cd66fec6c3d78de43fc192457b2a4a660a1e0eb22b"));
+  test_blake2s (SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+               SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+                    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
+                    "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+                    "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+                    "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
+                    "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                    "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                    "e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe"),
+               SHEX("3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd"));
+  blake2s_selftest ();
 }