ref: 4fab5fa56fb55196b8684fcd0fbbcd7a66a74d6f
parent: 0b093ef579be545e820491411b6f80aee40596a0
author: Jacob Moody <moody@posixcafe.org>
date: Mon May 19 23:32:32 EDT 2025
libsec: add blake2s-256
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -232,6 +232,7 @@
MD5dlen= 16, /* MD5 digest length */
RIPEMD160dlen= 20, /* RIPEMD-160 digest length */
Poly1305dlen= 16, /* Poly1305 digest length */
+ B2s_256dlen= 32, /* Blake2s-256 digest length */
Hmacblksz = 64, /* in bytes; from rfc2104 */
};
@@ -266,6 +267,7 @@
DigestState* sha2_256(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_384(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_512(uchar*, ulong, uchar*, DigestState*);
+DigestState* blake2s_256(uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen,
uchar *digest, DigestState *s,
DigestState*(*x)(uchar*, ulong, uchar*, DigestState*),
@@ -276,6 +278,7 @@
DigestState* hmac_sha2_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_sha2_384(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_sha2_512(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+DigestState* hmac_blake2s_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* poly1305(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
/*
--- a/sys/man/2/sechash
+++ b/sys/man/2/sechash
@@ -43,6 +43,8 @@
.Ti
DS* sha2_512(uchar *data, ulong dlen, uchar *digest, DS *state)
.Ti
+DS* blake2s_256(uchar *data, ulong dlen, uchar *digest, DS *state)
+.Ti
DS* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *s, DS*(*x)(uchar*, ulong, uchar*, DS*), int xlen)
.Ti
DS* hmac_md5(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest, DS *state)
@@ -57,6 +59,8 @@
.Ti
DS* hmac_sha2_512(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest, DS *state)
.Ti
+DS* hmac_blake2s_256(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest, DS *state)
+.Ti
DS* poly1305(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *state)
.SH DESCRIPTION
.DT
@@ -78,6 +82,7 @@
.IR sha2_256 ,
.IR sha2_384 ,
.IR sha2_512 ,
+.IR blake2s_256 ,
differ only in the length of the resulting digest
and in the security of the hash.
.I Sha2_*
@@ -107,7 +112,8 @@
.IR SHA2_224dlen ,
.IR SHA2_256dlen ,
.IR SHA2_384dlen ,
-.I SHA2_512dlen
+.IR SHA2_512dlen ,
+.I B2s_256dlen
and
.I Poly1305dlen
define the lengths of the digests.
@@ -117,7 +123,8 @@
.IR hmac_sha2_224 ,
.IR hmac_sha2_256 ,
.IR hmac_sha2_384 ,
-.I hmac_sha2_512
+.IR hmac_sha2_512 ,
+.I hmac_blake2s_256
and
.I poly1305
are used slightly differently. These hash algorithms are keyed and require
--- a/sys/src/libsec/mkfile
+++ b/sys/src/libsec/mkfile
@@ -12,6 +12,7 @@
}
clean:V:
+ @{cd test && mk $MKFLAGS clean}
for(i in $DIRS)@{
echo $i
cd $i
@@ -33,4 +34,4 @@
rm -f */*.[$OS]
test:VQ:
- # nothing
+ cd test && mk $MKFLAGS
--- /dev/null
+++ b/sys/src/libsec/port/blake2s.c
@@ -1,0 +1,135 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+
+extern void _blake2sblock(u32int h[16], uchar *b, u32int blen, u64int offset, u32int f);
+static DigestState* blake2s_512(uchar *p, ulong len, uchar *digest, DigestState *s, int dlen);
+
+static void
+encode32(uchar *output, u32int *input, ulong len)
+{
+ u32int x;
+ uchar *e;
+
+ for(e = output + len; output < e;) {
+ x = *input++;
+ *output++ = x >> 0;
+ *output++ = x >> 8;
+ *output++ = x >> 16;
+ *output++ = x >> 24;
+ }
+}
+
+DigestState*
+blake2s_256(uchar *p, ulong len, uchar *digest, DigestState *s)
+{
+ if(s == nil) {
+ s = mallocz(sizeof(*s), 1);
+ if(s == nil)
+ return nil;
+ s->malloced = 1;
+ }
+ if(s->seeded == 0){
+ s->state[0] = 0x6A09E667UL;
+ s->state[1] = 0xBB67AE85UL;
+ s->state[2] = 0x3C6EF372UL;
+ s->state[3] = 0xA54FF53AUL;
+ s->state[4] = 0x510E527FUL;
+ s->state[5] = 0x9B05688CUL;
+ s->state[6] = 0x1F83D9ABUL;
+ s->state[7] = 0x5BE0CD19UL;
+
+ s->state[0] ^= 0x01010000 ^ B2s_256dlen;
+ s->seeded = 1;
+ }
+ return blake2s_512(p, len, digest, s, B2s_256dlen);
+}
+
+enum{
+ bb = 64,
+
+ fcont = 0,
+ flast = 0xFFFFFFFF,
+};
+
+/* 64 byte input blocks */
+static DigestState*
+blake2s_512(uchar *p, ulong len, uchar *digest, DigestState *s, int dlen)
+{
+ int i;
+
+ if(s->blen){
+ i = bb - s->blen;
+ if(len < i)
+ i = len;
+ if(i > 0){
+ memmove(s->buf + s->blen, p, i);
+ len -= i;
+ s->blen += i;
+ p += i;
+ }
+ if(s->blen == bb){
+ if(len == 0){
+ if(digest != nil)
+ goto Last;
+ return s;
+ }
+ s->len += bb;
+ _blake2sblock(s->state, s->buf, bb, s->len, fcont);
+ s->blen = 0;
+ }
+ }
+
+ /*
+ * the last block must always have 'flast' set,
+ * so only go up to second to (potential) last block
+ */
+ i = len & ~(bb-1);
+ if(i > bb){
+ i -= bb;
+ _blake2sblock(s->state, p, i, s->len + bb, fcont);
+ s->len += i;
+ len -= i;
+ p += i;
+ }
+
+ /* more to come */
+ if(digest == 0){
+ if(len){
+ memmove(s->buf, p, len);
+ s->blen += len;
+ }
+ return s;
+ }
+
+ /* last block(s), might have > 1 still */
+ if(len > bb){
+ s->len += bb;
+ _blake2sblock(s->state, p, bb, s->len, fcont);
+ len -= bb;
+ p += bb;
+ }
+
+ if(s->blen){
+Last:
+ len = s->blen;
+ } else
+ memmove(s->buf, p, len);
+ p = s->buf;
+ s->len += len;
+ i = bb - len;
+ assert(i >= 0);
+ memset(p + len, 0, i);
+ _blake2sblock(s->state, p, bb, s->len, flast);
+
+ encode32(digest, s->state, dlen);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+DigestState*
+hmac_blake2s_256(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+ return hmac_x(p, len, key, klen, digest, s, blake2s_256, B2s_256dlen);
+}
--- /dev/null
+++ b/sys/src/libsec/port/blake2sblock.c
@@ -1,0 +1,91 @@
+#include "os.h"
+
+#define rotr32(w, c) (((w) >> (c)) | ((w) << ( 32 - (c))))
+
+#define load32(p) (((u32int )( (p)[0] ) << 0) | (( u32int )( (p)[1] ) << 8) | \
+ (( u32int )( (p)[2] ) << 16) | (( u32int )( (p)[3] ) << 24))
+
+static u32int IV[8] = {
+ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
+ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
+};
+
+static u8int sigma[10][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
+};
+
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[sigma[r][2*i+0]]; \
+ d = rotr32(d ^ a, 16); \
+ c = c + d; \
+ b = rotr32(b ^ c, 12); \
+ a = a + b + m[sigma[r][2*i+1]]; \
+ d = rotr32(d ^ a, 8); \
+ c = c + d; \
+ b = rotr32(b ^ c, 7); \
+ } while(0)
+
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+
+void
+_blake2sblock(u32int h[16], uchar *b, u32int blen, u64int offset, u32int f)
+{
+ u32int m[16];
+ u32int v[16];
+ int i;
+ uchar *e;
+
+ for(e = b + blen; b < e; b += 64){
+ for(i = 0; i < 16; i++)
+ m[i] = load32(b + i*sizeof h[0]);
+
+ for(i = 0; i < 8; i++)
+ v[i] = h[i];
+
+ v[ 8] = IV[0];
+ v[ 9] = IV[1];
+ v[10] = IV[2];
+ v[11] = IV[3];
+ v[12] = ((u32int)(offset>> 0)) ^ IV[4];
+ v[13] = ((u32int)(offset>>32)) ^ IV[5];
+ v[14] = f ^ IV[6];
+ v[15] = IV[7];
+
+ ROUND(0);
+ ROUND(1);
+ ROUND(2);
+ ROUND(3);
+ ROUND(4);
+ ROUND(5);
+ ROUND(6);
+ ROUND(7);
+ ROUND(8);
+ ROUND(9);
+
+ for(i = 0; i < 8; i++)
+ h[i] = h[i] ^ v[i] ^ v[i + 8];
+
+ offset += 64;
+ }
+}
--- a/sys/src/libsec/port/mkfile
+++ b/sys/src/libsec/port/mkfile
@@ -35,6 +35,7 @@
secp256r1.c\
secp384r1.c\
secp256k1.c\
+ blake2s.c blake2sblock.c\
CLEANFILES=secp256r1.c secp384r1.c secp256k1.c jacobian.c
--- /dev/null
+++ b/sys/src/libsec/test/blake2s.c
@@ -1,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+
+struct {
+ char *in, *exp;
+} tests[] = {
+ { /* empty input */
+ "",
+ "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9",
+ },
+ { /* reference hash */
+ "abc",
+ "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"
+ },
+ { /* exactly 1 block */
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "f85b88e0ac55872416d202c5f4881e7dbc9c7270542ef75074ff9b0a610b5a0e",
+ },
+ { /* exactly 2 blocks */
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "ea263e84e451e17ff77d642cd7a751757765aded33d62b96f1e998af31024e30",
+ },
+ { /* 1 block and some change */
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "c4b49a77ee46b6c166d56157131d1ec182153d0004428d6ac011edc942becd93",
+ },
+ { /* 2 blocks and some change */
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "cae0fc9b9f296425db4a4af96f83e947649e78954f4081ed72ebdfdfb29cfca4",
+ },
+ { /* 3 blocks and some change */
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "1b066f374e7e2d95a64643c5da9e1b89eab1c202cd5c17e27bc061ba3bbdc24a",
+ },
+};
+
+void
+main(int, char**)
+{
+ DigestState *s;
+ uchar digest[B2s_256dlen];
+ char buf[256];
+ int i;
+ char *p;
+
+ fmtinstall('H', encodefmt);
+ for(i = 0; i < nelem(tests); i++){
+ blake2s_256((uchar*)tests[i].in, strlen(tests[i].in), digest, nil);
+ snprint(buf, sizeof buf, "%.*lH", B2s_256dlen, digest);
+ if(strcmp(buf, tests[i].exp) != 0){
+ fprint(2, "Test: %s\nExp: %s\nGot: %s\n\n", tests[i].in, tests[i].exp, buf);
+ exits("fail");
+ }
+
+ s = nil;
+ memset(digest, 0, B2s_256dlen);
+ for(p = tests[i].in; *p != 0; p++)
+ s = blake2s_256((uchar*)p, 1, nil, s);
+
+ blake2s_256(nil, 0, digest, s);
+ snprint(buf, sizeof buf, "%.*lH", B2s_256dlen, digest);
+ if(strcmp(buf, tests[i].exp) != 0){
+ fprint(2, "Trickle Test: %s\nExp: %s\nGot: %s\n\n", tests[i].in, tests[i].exp, buf);
+ exits("fail");
+ }
+ }
+ exits(nil);
+}
--- /dev/null
+++ b/sys/src/libsec/test/mkfile
@@ -1,0 +1,8 @@
+</$objtype/mkfile
+
+TEST=\
+ blake2s\
+
+CFLAGS=$CFLAGS -I../../libmp/port
+
+</sys/src/cmd/mktest
--
⑨