shithub: riscv

Download patch

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
--