On Sun, Nov 04, 2018 at 03:05:04AM -0700, Theo Buehler wrote:
> On Thu, Oct 18, 2018 at 01:50:36PM +1000, David Gwynne wrote:
> > By BLAKE2, I actually mean just BLAKE2s and BLAKE2b. It doesn't
> > include BLAKE2sp, BLAKE2bp, or BLAKE2x.
> > 
> > Like other hashes it is exposed via it's own API, but also through the
> > EVP message digest stuff which also allows it to be used with HMAC.
> > 
> > BLAKE2 has a bit more functionality compared to other hash algorithms
> > since it allows for keys so it can be used as a MAC, and variable
> > length outputs. The BLAKE2 API allows this to be used, but the EVP
> > wrapped stuff has no way to pass that information through. Therefore
> > the EVP API gets to use unkeyed BLAKE2s and b, and with a fixed length
> > output.
> > 
> > I've tried this on sparc64 and amd64 and get consistent results between
> > them.
> > 
> > I want BLAKE2 because it's used by a protocol I would like to have
> > a go at implementing.
> > 
> > ok?
> 
> Purely code-wise I'm fine with your diff with some tweaks and one bug
> (in BLAKE2s_Init_State) fixed below.
> 
> However, it's not clear to me why we shouldn't use the reference
> implementation itself.  It's tested, has had its share of eyes and is
> acceptably licensed.  What's wrong with it that we should prefer your
> re-implementation?  The two seem to be quite close to each other.

I can't really justify it except to say it's a matter of taste, and
I've already done the work.

> > 
> > Index: Makefile
> > ===================================================================
> > RCS file: /cvs/src/lib/libcrypto/Makefile,v
> > retrieving revision 1.27
> > diff -u -p -r1.27 Makefile
> > --- Makefile        17 Mar 2018 16:20:01 -0000      1.27
> > +++ Makefile        18 Oct 2018 03:28:33 -0000
> > @@ -153,7 +153,7 @@ SRCS+= encode.c digest.c evp_enc.c evp_k
> >  SRCS+= e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c
> >  SRCS+= e_rc4.c e_aes.c names.c
> >  SRCS+= e_xcbc_d.c e_rc2.c e_cast.c
> > -SRCS+= m_null.c m_md4.c m_md5.c m_sha1.c m_wp.c
> > +SRCS+= m_null.c m_md4.c m_md5.c m_sha1.c m_blake2.c m_wp.c
> 
> move m_blake2.c after m_null.c (it's a mess already, but no need to make
> it worse)

Ok.

> 
> >  SRCS+= m_dss.c m_dss1.c m_ripemd.c m_ecdsa.c
> >  SRCS+= p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c
> >  SRCS+= bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c
> > @@ -233,6 +233,9 @@ SRCS+= rsa_pmeth.c rsa_crpt.c rsa_meth.c
> >  # sha/
> >  SRCS+= sha1dgst.c sha1_one.c sha256.c sha512.c
> >  
> > +# blake2/
> > +SRCS+= blake2.c
> > +
> 
> This should be moved before '# bn/'

OK.

> >  # stack/
> >  SRCS+= stack.c
> >  
> > @@ -312,6 +315,7 @@ SRCS+= pcy_cache.c pcy_node.c pcy_data.c
> >     ${LCRYPTO_SRC}/ripemd \
> >     ${LCRYPTO_SRC}/rsa \
> >     ${LCRYPTO_SRC}/sha \
> > +   ${LCRYPTO_SRC}/blake2 \
> 
> similarly for this

OK.
 
> >     ${LCRYPTO_SRC}/stack \
> >     ${LCRYPTO_SRC}/threads \
> >     ${LCRYPTO_SRC}/ts \
> > @@ -373,6 +377,7 @@ HDRS=\
> >     ${LCRYPTO_SRC}/ripemd/ripemd.h \
> >     ${LCRYPTO_SRC}/rsa/rsa.h \
> >     ${LCRYPTO_SRC}/sha/sha.h \
> > +   ${LCRYPTO_SRC}/blake2/blake2.h \
> 
> and this

OK.
 
> >     ${LCRYPTO_SRC}/stack/safestack.h \
> >     ${LCRYPTO_SRC}/stack/stack.h \
> >     ${LCRYPTO_SRC}/ts/ts.h \
> > Index: Symbols.list
> > ===================================================================
> > RCS file: /cvs/src/lib/libcrypto/Symbols.list,v
> > retrieving revision 1.76
> > diff -u -p -r1.76 Symbols.list
> > --- Symbols.list    12 Sep 2018 06:35:38 -0000      1.76
> > +++ Symbols.list    18 Oct 2018 03:28:33 -0000
> > @@ -368,6 +368,14 @@ BIO_vfree
> >  BIO_vprintf
> >  BIO_vsnprintf
> >  BIO_write
> > +BLAKE2b_Init
> > +BLAKE2b_Init_Key
> > +BLAKE2b_Update
> > +BLAKE2b_Final
> > +BLAKE2s_Init
> > +BLAKE2s_Init_Key
> > +BLAKE2s_Update
> > +BLAKE2s_Final
> 
> sort alphabetically

OK.
 
> > Index: shlib_version
> > ===================================================================
> > RCS file: /cvs/src/lib/libcrypto/shlib_version,v
> > retrieving revision 1.46
> > diff -u -p -r1.46 shlib_version
> > --- shlib_version   12 Sep 2018 06:35:38 -0000      1.46
> > +++ shlib_version   18 Oct 2018 03:28:33 -0000
> > @@ -1,3 +1,3 @@
> >  # Don't forget to give libssl and libtls the same type of bump!
> 
> don't forget the comment. :)

I'll ignore the bumps for now.

> 
> if this goes in the same time as sm-3, i can take care of the bumping
> and the fileset sync.
> 
> >  major=44
> > -minor=1
> > +minor=2

> > +static int
> > +BLAKE2s_Init_State(struct BLAKE2s_state *s, size_t outbytes, size_t 
> > keybytes)
> > +{
> > +   struct BLAKE2s_param p;
> > +   const uint32_t *w;
> > +   unsigned int i;
> > +
> > +   if (outbytes == 0 || outbytes > BLAKE2S_OUTBYTES)
> > +           return (0);
> > +   if (keybytes > BLAKE2S_KEYBYTES)
> > +           return (0);
> > +
> > +   p.digest_length = outbytes;
> > +   p.key_length = 0;
> 
> this should be
> 
>       p.key_length = keybytes;

fixed.

> > +int
> > +BLAKE2s_Init_Key(struct BLAKE2s_state *s, size_t outbytes,
> > +    const void *key, size_t keybytes)
> > +{
> > +   uint8_t zero[BLAKE2S_BLOCKBYTES];
> > +   int rv;
> 
> drop rv
> 
> > +
> > +   if (keybytes == 0)
> > +           return (0);
> 
> What's your reasoning for erroring out here? The reference
> implementation falls back to the un-keyed hash function, I think we
> should follow suit. I worry that this will be a trap.

Which reference implementation? The one linked off blake2.net errors
out here:

https://github.com/BLAKE2/BLAKE2/blob/master/ref/blake2s-ref.c#L121

> > +   rv = BLAKE2s_Init_State(s, outbytes, keybytes);
> > +   if (rv != 1)
> 
> openssl-style would be
> 
>       if (!BLAKE2s_Init_State(s, outbytes, keybytes))
>               return (0);
> 
> we don't lose information as _Init_state() returns 0 or 1 anyway.

OK.

> > +static inline void
> > +BLAKE2s_Count(struct BLAKE2s_state *s, uint32_t c)
> > +{
> > +   s->t[0] += c;
> > +   s->t[1] += (s->t[0] < c);
> 
> Can we do this the stupid way for the sake of readability?
> 
>       if (s->t[0] < c)
>               s->t[1]++;
> 

I'd prefer to keep it, but if you feel strongly enough about it I can
change it. The preference is due to the code generated by this. By
adding the result of the conditional you can avoid a branch on
architectures that have something like an add and carry opcode.

It is interesting you're arguing here for readability, but above for the
reference code ;)

> > +int
> > +BLAKE2b_Init_Key(struct BLAKE2b_state *s, size_t outbytes,
> > +    const void *key, size_t keybytes)
> > +{
> > +   uint8_t zero[BLAKE2B_BLOCKBYTES];
> > +   int rv;
> 
> drop rv

ok.

> 
> > +
> > +   if (keybytes == 0)
> > +           return (0);
> > +
> > +   rv = BLAKE2b_Init_State(s, outbytes, keybytes);
> > +   if (rv != 1)
> 
>       if (!BLAKE2b_Init_State(s, outbytes, keybytes))
>               return 0;


> > +static inline void
> > +BLAKE2b_Count(struct BLAKE2b_state *s, uint64_t c)
> > +{
> > +   s->t[0] += c;
> > +   s->t[1] += (s->t[0] < c);
> 
> As in BLAKE2b_Count I would prefer
> 
>       if (s->t[0] < c)
>               s->t[1]++;

Again, let me know if you feel strongly about it.

Index: Makefile
===================================================================
RCS file: /cvs/src/lib/libcrypto/Makefile,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile
--- Makefile    11 Nov 2018 06:53:31 -0000      1.30
+++ Makefile    12 Nov 2018 00:10:37 -0000
@@ -70,6 +70,9 @@ SRCS+= bf_null.c bf_buff.c b_print.c b_d
 SRCS+= b_posix.c b_sock.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c
 SRCS+= bss_dgram.c
 
+# blake2/
+SRCS+= blake2.c
+
 # bn/
 SRCS+= bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c bn_mod.c
 SRCS+= bn_print.c bn_rand.c bn_shift.c bn_word.c bn_blind.c
@@ -152,7 +155,7 @@ SRCS+= encode.c digest.c evp_enc.c evp_k
 SRCS+= e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c
 SRCS+= e_rc4.c e_aes.c names.c
 SRCS+= e_xcbc_d.c e_rc2.c e_cast.c
-SRCS+= m_null.c m_md4.c m_md5.c m_sha1.c m_sm3.c m_wp.c
+SRCS+= m_blake2.c m_null.c m_md4.c m_md5.c m_sha1.c m_sm3.c m_wp.c
 SRCS+= m_dss.c m_dss1.c m_ripemd.c m_ecdsa.c
 SRCS+= p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c
 SRCS+= bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c
@@ -273,6 +276,7 @@ SRCS+= pcy_cache.c pcy_node.c pcy_data.c
        ${LCRYPTO_SRC}/asn1 \
        ${LCRYPTO_SRC}/bf \
        ${LCRYPTO_SRC}/bio \
+       ${LCRYPTO_SRC}/blake2 \
        ${LCRYPTO_SRC}/bn \
        ${LCRYPTO_SRC}/bn/asm \
        ${LCRYPTO_SRC}/buffer \
@@ -330,6 +334,7 @@ HDRS=\
        ${LCRYPTO_SRC}/asn1/asn1t.h \
        ${LCRYPTO_SRC}/bf/blowfish.h \
        ${LCRYPTO_SRC}/bio/bio.h \
+       ${LCRYPTO_SRC}/blake2/blake2.h \
        ${LCRYPTO_SRC}/bn/bn.h \
        ${LCRYPTO_SRC}/buffer/buffer.h \
        ${LCRYPTO_SRC}/camellia/camellia.h \
Index: Symbols.list
===================================================================
RCS file: /cvs/src/lib/libcrypto/Symbols.list,v
retrieving revision 1.80
diff -u -p -r1.80 Symbols.list
--- Symbols.list        11 Nov 2018 06:53:31 -0000      1.80
+++ Symbols.list        12 Nov 2018 00:10:37 -0000
@@ -364,6 +364,14 @@ BIO_vfree
 BIO_vprintf
 BIO_vsnprintf
 BIO_write
+BLAKE2b_Final
+BLAKE2b_Init
+BLAKE2b_Init_Key
+BLAKE2b_Update
+BLAKE2s_Final
+BLAKE2s_Init
+BLAKE2s_Init_Key
+BLAKE2s_Update
 BN_BLINDING_convert
 BN_BLINDING_convert_ex
 BN_BLINDING_create_param
@@ -1511,6 +1522,8 @@ EVP_bf_cfb
 EVP_bf_cfb64
 EVP_bf_ecb
 EVP_bf_ofb
+EVP_blake2b512
+EVP_blake2s256
 EVP_camellia_128_cbc
 EVP_camellia_128_cfb1
 EVP_camellia_128_cfb128
Index: blake2/blake2.c
===================================================================
RCS file: blake2/blake2.c
diff -N blake2/blake2.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ blake2/blake2.c     12 Nov 2018 00:10:37 -0000
@@ -0,0 +1,569 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2018 David Gwynne <d...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * this code was inspired by the BLAKE2 reference implementation
+ * written by Samuel Neves
+ */
+
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_NO_BLAKE2
+
+#include <machine/endian.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef nitems
+#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+#include <openssl/blake2.h>
+
+struct BLAKE2s_param {
+       uint8_t         digest_length;
+       uint8_t         key_length;
+       uint8_t         fanout;
+       uint8_t         depth;
+       uint32_t        leaf_length;
+       uint32_t        node_offset;
+       uint16_t        xof_length;
+       uint8_t         node_depth;
+       uint8_t         inner_length;
+       uint8_t         salt[BLAKE2S_SALTBYTES];
+       uint8_t         personal[BLAKE2S_PERSONALBYTES];
+} __packed __aligned(4);
+
+struct BLAKE2b_param {
+       uint8_t         digest_length;
+       uint8_t         key_length;
+       uint8_t         fanout;
+       uint8_t         depth;
+       uint32_t        leaf_length;
+       uint32_t        node_offset;
+       uint32_t        xof_length;
+       uint8_t         node_depth;
+       uint8_t         inner_length;
+       uint8_t         reserved[14];
+       uint8_t         salt[BLAKE2B_SALTBYTES];
+       uint8_t         personal[BLAKE2B_PERSONALBYTES];
+} __packed __aligned(4);
+
+#if (_BYTE_ORDER == _LITTLE_ENDIAN)
+#define memcpyle32(_dst, _src, _len) memcpy((_dst), (_src), (_len))
+#else
+static void
+memcpyle32(void *dst, const void *src, size_t len)
+{
+       uint8_t *d = dst;
+       const uint8_t *s = src;
+
+       while (len > 0) {
+               size_t i = len;
+
+               switch (i) {
+               default:
+                       i = 4;
+               case 4:
+                       d[3] = s[0];
+               case 3:
+                       d[2] = s[1];
+               case 2:
+                       d[1] = s[2];
+               case 1:
+                       d[0] = s[3];
+               }
+
+               d += 4;
+               s += 4;
+
+               len -= i;
+       }
+}
+#endif
+
+static inline uint32_t
+ror32(uint32_t v, unsigned int r)
+{
+       return ((v >> r)|(v << (32 - r)));
+}
+
+#if (_BYTE_ORDER == _LITTLE_ENDIAN)
+#define memcpyle64(_dst, _src, _len) memcpy((_dst), (_src), (_len))
+#else
+static void
+memcpyle64(void *dst, const void *src, size_t len)
+{
+       uint8_t *d = dst;
+       const uint8_t *s = src;
+
+       while (len > 0) {
+               size_t i = len;
+
+               switch (i) {
+               default:
+                       i = 8;
+               case 8:
+                       d[7] = s[0];
+               case 7:
+                       d[6] = s[1];
+               case 6:
+                       d[5] = s[2];
+               case 5:
+                       d[4] = s[3];
+               case 4:
+                       d[3] = s[4];
+               case 3:
+                       d[2] = s[5];
+               case 2:
+                       d[1] = s[6];
+               case 1:
+                       d[0] = s[7];
+               }
+
+               d += 8;
+               s += 8;
+
+               len -= i;
+       }
+}
+#endif
+
+static inline uint64_t
+ror64(uint64_t v, unsigned int r)
+{
+       return ((v >> r)|(v << (64 - r)));
+}
+
+/*
+ * BLAKE2s
+ */
+
+static const uint32_t BLAKE2s_IV[8] = {
+       0x6a09e667U,
+       0xbb67ae85U,
+       0x3c6ef372U,
+       0xa54ff53aU,
+       0x510e527fU,
+       0x9b05688CU,
+       0x1f83d9abU,
+       0x5be0cd19U,
+};
+
+static const uint8_t BLAKE2s_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 },
+};
+
+static int
+BLAKE2s_Init_State(struct BLAKE2s_state *s, size_t outbytes, size_t keybytes)
+{
+       struct BLAKE2s_param p;
+       const uint32_t *w;
+       unsigned int i;
+
+       if (outbytes == 0 || outbytes > BLAKE2S_OUTBYTES)
+               return (0);
+       if (keybytes > BLAKE2S_KEYBYTES)
+               return (0);
+
+       p.digest_length = outbytes;
+       p.key_length = keybytes;
+       p.fanout = 1;
+       p.depth = 1;
+       p.leaf_length = htole32(0);
+       p.node_offset = htole32(0);
+       p.xof_length = htole16(0);
+       p.node_depth = 0;
+       p.inner_length = 0;
+       memset(p.salt, 0, sizeof(p.salt));
+       memset(p.personal, 0, sizeof(p.personal));
+
+       memset(s, 0, sizeof(*s));
+
+       w = (const uint32_t *)&p;
+       for (i = 0; i < nitems(s->h); i++)
+               s->h[i] = BLAKE2s_IV[i] ^ htole32(w[i]);
+
+       return (1);
+}
+
+int
+BLAKE2s_Init(struct BLAKE2s_state *s, size_t outbytes)
+{
+       return (BLAKE2s_Init_State(s, outbytes, 0));
+}
+
+int
+BLAKE2s_Init_Key(struct BLAKE2s_state *s, size_t outbytes,
+    const void *key, size_t keybytes)
+{
+       uint8_t zero[BLAKE2S_BLOCKBYTES];
+
+       if (keybytes == 0)
+               return (0);
+
+       if (!BLAKE2s_Init_State(s, outbytes, keybytes))
+               return (0);
+
+       memset(zero, 0, sizeof(zero));
+
+       BLAKE2s_Update(s, key, keybytes);
+       BLAKE2s_Update(s, zero, sizeof(zero) - keybytes);
+
+       return (1);
+}
+
+#define BLAKE2s_G(r, m, i, a, b, c, d) do {                            \
+       a = a + b + m[BLAKE2s_Sigma[r][2 * i + 0]];                     \
+       d = ror32(d ^ a, 16);                                           \
+       c = c + d;                                                      \
+       b = ror32(b ^ c, 12);                                           \
+       a = a + b + m[BLAKE2s_Sigma[r][2*i+1]];                         \
+       d = ror32(d ^ a, 8);                                            \
+       c = c + d;                                                      \
+       b = ror32(b ^ c, 7);                                            \
+} while (0)
+
+static inline void
+BLAKE2s_Round(unsigned int r, const uint32_t *m, uint32_t *v)
+{
+       BLAKE2s_G(r, m, 0, v[ 0], v[ 4], v[ 8], v[12]);
+       BLAKE2s_G(r, m, 1, v[ 1], v[ 5], v[ 9], v[13]);
+       BLAKE2s_G(r, m, 2, v[ 2], v[ 6], v[10], v[14]);
+       BLAKE2s_G(r, m, 3, v[ 3], v[ 7], v[11], v[15]);
+       BLAKE2s_G(r, m, 4, v[ 0], v[ 5], v[10], v[15]);
+       BLAKE2s_G(r, m, 5, v[ 1], v[ 6], v[11], v[12]);
+       BLAKE2s_G(r, m, 6, v[ 2], v[ 7], v[ 8], v[13]);
+       BLAKE2s_G(r, m, 7, v[ 3], v[ 4], v[ 9], v[14]);
+}
+
+static void
+BLAKE2s_Compress(struct BLAKE2s_state *s, const uint8_t *in)
+{
+       uint32_t m[16];
+       uint32_t v[16];
+       unsigned int i;
+
+       memcpyle32(m, in, sizeof(m));
+
+       for (i = 0; i < nitems(s->h); i++)
+               v[i] = s->h[i];
+
+       v[ 8] = BLAKE2s_IV[0];
+       v[ 9] = BLAKE2s_IV[1];
+       v[10] = BLAKE2s_IV[2];
+       v[11] = BLAKE2s_IV[3];
+       v[12] = BLAKE2s_IV[4] ^ s->t[0];
+       v[13] = BLAKE2s_IV[5] ^ s->t[1];
+       v[14] = BLAKE2s_IV[6] ^ s->f[0];
+       v[15] = BLAKE2s_IV[7] ^ s->f[1];
+
+       BLAKE2s_Round(0, m, v);
+       BLAKE2s_Round(1, m, v);
+       BLAKE2s_Round(2, m, v);
+       BLAKE2s_Round(3, m, v);
+       BLAKE2s_Round(4, m, v);
+       BLAKE2s_Round(5, m, v);
+       BLAKE2s_Round(6, m, v);
+       BLAKE2s_Round(7, m, v);
+       BLAKE2s_Round(8, m, v);
+       BLAKE2s_Round(9, m, v);
+
+       for (i = 0; i < nitems(s->h); ++i)
+               s->h[i] = s->h[i] ^ v[i] ^ v[i + 8];
+}
+
+static inline void
+BLAKE2s_Count(struct BLAKE2s_state *s, uint32_t c)
+{
+       s->t[0] += c;
+       s->t[1] += (s->t[0] < c);
+}
+
+void
+BLAKE2s_Update(struct BLAKE2s_state *s, const void *data, size_t len)
+{
+       const uint8_t *buf = data;
+       size_t used, free;
+
+       if (len == 0)
+               return;
+
+       used = s->buflen;
+       free = BLAKE2S_BLOCKBYTES - used;
+
+       if (len > free) {
+               memcpy(s->buf + used, buf, free);
+               BLAKE2s_Count(s, BLAKE2S_BLOCKBYTES);
+               BLAKE2s_Compress(s, s->buf);
+
+               used = 0;
+               buf += free;
+               len -= free;
+
+               while (len > BLAKE2S_BLOCKBYTES) {
+                       BLAKE2s_Count(s, BLAKE2S_BLOCKBYTES);
+                       BLAKE2s_Compress(s, buf);
+
+                       buf += BLAKE2S_BLOCKBYTES;
+                       len -= BLAKE2S_BLOCKBYTES;
+               }
+       }
+       memcpy(s->buf + used, buf, len);
+       s->buflen = used + len;
+}
+
+void
+BLAKE2s_Final(struct BLAKE2s_state *s, void *out, size_t outlen)
+{
+       size_t used, free;
+
+       s->f[0] = ~0U; /* last block */
+
+       used = s->buflen;
+       free = BLAKE2S_BLOCKBYTES - used;
+
+       memset(s->buf + used, 0, free);
+       BLAKE2s_Count(s, used);
+       BLAKE2s_Compress(s, s->buf);
+
+       memcpyle32(out, s->h, outlen);
+}
+
+/*
+ * BLAKE2b
+ */
+
+static const uint64_t BLAKE2b_IV[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL,
+};
+
+static const uint8_t BLAKE2b_Sigma[12][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 },
+       {  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 },
+};
+
+static int
+BLAKE2b_Init_State(struct BLAKE2b_state *s, size_t outbytes, size_t keybytes)
+{
+       struct BLAKE2b_param p;
+       const uint64_t *w;
+       unsigned int i;
+
+       if (outbytes == 0 || outbytes > BLAKE2B_OUTBYTES)
+               return (0);
+       if (keybytes > BLAKE2B_KEYBYTES)
+               return (0);
+
+       p.digest_length = outbytes;
+       p.key_length = keybytes;
+       p.fanout = 1;
+       p.depth = 1;
+       p.leaf_length = htole32(0);
+       p.node_offset = htole32(0);
+       p.xof_length = htole32(0);
+       p.node_depth = 0;
+       p.inner_length = 0;
+       memset(p.reserved, 0, sizeof(p.reserved));
+       memset(p.salt, 0, sizeof(p.salt));
+       memset(p.personal, 0, sizeof(p.personal));
+
+       memset(s, 0, sizeof(*s));
+
+       w = (const uint64_t *)&p;
+       for (i = 0; i < nitems(s->h); i++)
+               s->h[i] = BLAKE2b_IV[i] ^ htole64(w[i]);
+
+       return (1);
+}
+
+int
+BLAKE2b_Init(struct BLAKE2b_state *s, size_t outbytes)
+{
+       return (BLAKE2b_Init_State(s, outbytes, 0));
+}
+
+int
+BLAKE2b_Init_Key(struct BLAKE2b_state *s, size_t outbytes,
+    const void *key, size_t keybytes)
+{
+       uint8_t zero[BLAKE2B_BLOCKBYTES];
+
+       if (keybytes == 0)
+               return (0);
+
+       if (!BLAKE2b_Init_State(s, outbytes, keybytes))
+               return (0);
+
+       memset(zero, 0, sizeof(zero));
+
+       BLAKE2b_Update(s, key, keybytes);
+       BLAKE2b_Update(s, zero, sizeof(zero) - keybytes);
+
+       return (1);
+}
+
+#define BLAKE2b_G(r, m, i, a, b, c, d) do {                            \
+       a = a + b + m[BLAKE2b_Sigma[r][2 * i + 0]];                     \
+       d = ror64(d ^ a, 32);                                           \
+       c = c + d;                                                      \
+       b = ror64(b ^ c, 24);                                           \
+       a = a + b + m[BLAKE2b_Sigma[r][2 * i + 1]];                     \
+       d = ror64(d ^ a, 16);                                           \
+       c = c + d;                                                      \
+       b = ror64(b ^ c, 63);                                           \
+} while (0)
+
+static inline void
+BLAKE2b_Round(unsigned int r, const uint64_t *m, uint64_t *v)
+{
+       BLAKE2b_G(r, m, 0, v[ 0], v[ 4], v[ 8], v[12]);
+       BLAKE2b_G(r, m, 1, v[ 1] ,v[ 5] ,v[ 9] ,v[13]);
+       BLAKE2b_G(r, m, 2, v[ 2] ,v[ 6] ,v[10] ,v[14]);
+       BLAKE2b_G(r, m, 3, v[ 3] ,v[ 7] ,v[11] ,v[15]);
+       BLAKE2b_G(r, m, 4, v[ 0] ,v[ 5] ,v[10] ,v[15]);
+       BLAKE2b_G(r, m, 5, v[ 1] ,v[ 6] ,v[11] ,v[12]);
+       BLAKE2b_G(r, m, 6, v[ 2] ,v[ 7] ,v[ 8] ,v[13]);
+       BLAKE2b_G(r, m, 7, v[ 3] ,v[ 4] ,v[ 9] ,v[14]);
+}
+
+static void
+BLAKE2b_Compress(struct BLAKE2b_state *s, const uint8_t *in)
+{
+       uint64_t m[16];
+       uint64_t v[16];
+       unsigned int i;
+
+       memcpyle64(m, in, sizeof(m));
+
+       for (i = 0; i < nitems(s->h); i++)
+               v[i] = s->h[i];
+
+       v[ 8] = BLAKE2b_IV[0];
+       v[ 9] = BLAKE2b_IV[1];
+       v[10] = BLAKE2b_IV[2];
+       v[11] = BLAKE2b_IV[3];
+       v[12] = BLAKE2b_IV[4] ^ s->t[0];
+       v[13] = BLAKE2b_IV[5] ^ s->t[1];
+       v[14] = BLAKE2b_IV[6] ^ s->f[0];
+       v[15] = BLAKE2b_IV[7] ^ s->f[1];
+
+       BLAKE2b_Round(0, m, v);
+       BLAKE2b_Round(1, m, v);
+       BLAKE2b_Round(2, m, v);
+       BLAKE2b_Round(3, m, v);
+       BLAKE2b_Round(4, m, v);
+       BLAKE2b_Round(5, m, v);
+       BLAKE2b_Round(6, m, v);
+       BLAKE2b_Round(7, m, v);
+       BLAKE2b_Round(8, m, v);
+       BLAKE2b_Round(9, m, v);
+       BLAKE2b_Round(10, m, v);
+       BLAKE2b_Round(11, m, v);
+
+       for (i = 0; i < nitems(s->h); ++i)
+               s->h[i] = s->h[i] ^ v[i] ^ v[i + 8];
+}
+
+static inline void
+BLAKE2b_Count(struct BLAKE2b_state *s, uint64_t c)
+{
+       s->t[0] += c;
+       s->t[1] += (s->t[0] < c);
+}
+
+void
+BLAKE2b_Update(struct BLAKE2b_state *s, const void *data, size_t len)
+{
+       const uint8_t *buf = data;
+       size_t used, free;
+
+       if (len == 0)
+               return;
+
+       used = s->buflen;
+       free = sizeof(s->buf) - used;
+
+       if (len > free) {
+               memcpy(s->buf + used, buf, free);
+               BLAKE2b_Count(s, sizeof(s->buf));
+               BLAKE2b_Compress(s, s->buf);
+
+               used = 0;
+               buf += free;
+               len -= free;
+
+               while (len > sizeof(s->buf)) {
+                       BLAKE2b_Count(s, sizeof(s->buf));
+                       BLAKE2b_Compress(s, buf);
+
+                       buf += sizeof(s->buf);
+                       len -= sizeof(s->buf);
+               }
+       }
+
+       memcpy(s->buf + used, buf, len);
+       s->buflen = used + len;
+}
+
+void
+BLAKE2b_Final(struct BLAKE2b_state *s, void *out, size_t outlen)
+{
+       size_t used, free;
+
+       s->f[0] = ~0ULL; /* last block */
+
+       used = s->buflen;
+       free = BLAKE2B_BLOCKBYTES - used;
+
+       memset(s->buf + used, 0, free);
+       BLAKE2b_Count(s, used);
+       BLAKE2b_Compress(s, s->buf);
+
+       memcpyle64(out, s->h, outlen);
+}
+
+#endif /* OPENSSL_NO_BLAKE2 */
Index: blake2/blake2.h
===================================================================
RCS file: blake2/blake2.h
diff -N blake2/blake2.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ blake2/blake2.h     12 Nov 2018 00:10:37 -0000
@@ -0,0 +1,80 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2018 David Gwynne <d...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_BLAKE2_H
+#define HEADER_BLAKE2_H
+
+#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__OpenBSD__)
+#define __bounded__(x, y, z)
+#endif
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define BLAKE2S_BLOCKBYTES     64
+#define BLAKE2S_OUTBYTES       32
+#define BLAKE2S_KEYBYTES       32
+#define BLAKE2S_SALTBYTES      8
+#define BLAKE2S_PERSONALBYTES  8
+
+#define BLAKE2B_BLOCKBYTES     128
+#define BLAKE2B_OUTBYTES       64
+#define BLAKE2B_KEYBYTES       64
+#define BLAKE2B_SALTBYTES      16
+#define BLAKE2B_PERSONALBYTES  16
+
+struct BLAKE2s_state {
+       uint32_t        h[8];
+       uint32_t        t[2];
+       uint32_t        f[2];
+       uint8_t         buf[BLAKE2S_BLOCKBYTES];
+       size_t          buflen;
+       uint8_t         last_node;
+};
+
+typedef struct BLAKE2s_state BLAKE2S_CTX;
+
+struct BLAKE2b_state {
+       uint64_t        h[8];
+       uint64_t        t[2];
+       uint64_t        f[2];
+       uint8_t         buf[BLAKE2B_BLOCKBYTES];
+       size_t          buflen;
+       uint8_t         last_node;
+};
+
+typedef struct BLAKE2b_state BLAKE2B_CTX;
+
+int    BLAKE2s_Init(struct BLAKE2s_state *, size_t);
+int    BLAKE2s_Init_Key(struct BLAKE2s_state *, size_t, const void *, size_t);
+void   BLAKE2s_Update(struct BLAKE2s_state *, const void *, size_t);
+void   BLAKE2s_Final(struct BLAKE2s_state *, void *, size_t);
+
+int    BLAKE2b_Init(struct BLAKE2b_state *, size_t);
+int    BLAKE2b_Init_Key(struct BLAKE2b_state *, size_t, const void *, size_t);
+void   BLAKE2b_Update(struct BLAKE2b_state *, const void *, size_t);
+void   BLAKE2b_Final(struct BLAKE2b_state *, void *, size_t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* HEADER_BLAKE2_H */
Index: evp/c_all.c
===================================================================
RCS file: /cvs/src/lib/libcrypto/evp/c_all.c,v
retrieving revision 1.23
diff -u -p -r1.23 c_all.c
--- evp/c_all.c 11 Nov 2018 07:07:44 -0000      1.23
+++ evp/c_all.c 12 Nov 2018 00:10:37 -0000
@@ -292,6 +292,10 @@ OpenSSL_add_all_digests_internal(void)
 #ifndef OPENSSL_NO_WHIRLPOOL
        EVP_add_digest(EVP_whirlpool());
 #endif
+#ifndef OPENSSL_NO_BLAKE2
+       EVP_add_digest(EVP_blake2b512());
+       EVP_add_digest(EVP_blake2s256());
+#endif
 }
 
 void
Index: evp/evp.h
===================================================================
RCS file: /cvs/src/lib/libcrypto/evp/evp.h,v
retrieving revision 1.70
diff -u -p -r1.70 evp.h
--- evp/evp.h   11 Nov 2018 06:53:31 -0000      1.70
+++ evp/evp.h   12 Nov 2018 00:10:37 -0000
@@ -695,6 +695,10 @@ const EVP_MD *EVP_ripemd160(void);
 #ifndef OPENSSL_NO_WHIRLPOOL
 const EVP_MD *EVP_whirlpool(void);
 #endif
+#ifndef OPENSSL_NO_BLAKE2
+const EVP_MD *EVP_blake2b512(void);
+const EVP_MD *EVP_blake2s256(void);
+#endif
 #ifndef OPENSSL_NO_GOST
 const EVP_MD *EVP_gostr341194(void);
 const EVP_MD *EVP_gost2814789imit(void);
Index: evp/m_blake2.c
===================================================================
RCS file: evp/m_blake2.c
diff -N evp/m_blake2.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ evp/m_blake2.c      12 Nov 2018 00:10:37 -0000
@@ -0,0 +1,107 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2018 David Gwynne <d...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_NO_BLAKE2
+
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/blake2.h>
+
+static int
+BLAKE2s256_Init(EVP_MD_CTX *ctx)
+{
+       return (BLAKE2s_Init(ctx->md_data, BLAKE2S_OUTBYTES));
+}
+
+static int
+BLAKE2s256_Update(EVP_MD_CTX *ctx, const void *buf, size_t len)
+{
+       BLAKE2s_Update(ctx->md_data, buf, len);
+
+       return (1);
+}
+
+static int
+BLAKE2s256_Final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+       BLAKE2s_Final(ctx->md_data, md, BLAKE2S_OUTBYTES);
+
+       return (1);
+}
+
+static const EVP_MD BLAKE2s256_md = {
+       .type = NID_blake2s256,
+       .pkey_type = 0,
+       .md_size = BLAKE2S_OUTBYTES,
+       .flags = 0,
+       .init = BLAKE2s256_Init,
+       .update = BLAKE2s256_Update,
+       .final = BLAKE2s256_Final,
+       .block_size = BLAKE2S_BLOCKBYTES,
+       .ctx_size = sizeof(EVP_MD *) + sizeof(BLAKE2S_CTX),
+};
+
+const EVP_MD *
+EVP_blake2s256(void)
+{
+       return (&BLAKE2s256_md);
+}
+
+static int
+BLAKE2b512_Init(EVP_MD_CTX *ctx)
+{
+       return (BLAKE2b_Init(ctx->md_data, BLAKE2B_OUTBYTES));
+}
+
+static int
+BLAKE2b512_Update(EVP_MD_CTX *ctx, const void *buf, size_t len)
+{
+       BLAKE2b_Update(ctx->md_data, buf, len);
+
+       return (1);
+}
+
+static int
+BLAKE2b512_Final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+       BLAKE2b_Final(ctx->md_data, md, BLAKE2B_OUTBYTES);
+
+       return (1);
+}
+
+static const EVP_MD BLAKE2b512_md = {
+       .type = NID_blake2b512,
+       .pkey_type = 0,
+       .md_size = BLAKE2B_OUTBYTES,
+       .flags = 0,
+       .init = BLAKE2b512_Init,
+       .update = BLAKE2b512_Update,
+       .final = BLAKE2b512_Final,
+       .block_size = BLAKE2B_BLOCKBYTES,
+       .ctx_size = sizeof(EVP_MD *) + sizeof(BLAKE2B_CTX),
+};
+
+const EVP_MD *
+EVP_blake2b512(void)
+{
+       return (&BLAKE2b512_md);
+}
+
+#endif /* ifndef OPENSSL_NO_BLAKE2 */
Index: man/BLAKE2.3
===================================================================
RCS file: man/BLAKE2.3
diff -N man/BLAKE2.3
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ man/BLAKE2.3        12 Nov 2018 00:10:37 -0000
@@ -0,0 +1,160 @@
+.\"    $OpenBSD$
+.\"
+.\" Copyright (c) 2018 David Gwynne <d...@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt BLAKE2 3
+.Os
+.Sh NAME
+.Nm BLAKE2b_Init ,
+.Nm BLAKE2b_Init_Key ,
+.Nm BLAKE2b_Update ,
+.Nm BLAKE2b_Final ,
+.Nm BLAKE2s_Init ,
+.Nm BLAKE2s_Init_Key ,
+.Nm BLAKE2s_Update ,
+.Nm BLAKE2s_Final
+.Nd BLAKE2 Hash Algorithm
+.Sh SYNOPSIS
+.In openssl/blake2.h
+.Ft int
+.Fo BLAKE2b_Init
+.Fa "BLAKE2B_CTX *ctx"
+.Fa "size_t digest_length"
+.Fc
+.Ft int
+.Fo BLAKE2b_Init_Key
+.Fa "BLAKE2B_CTX *ctx"
+.Fa "size_t digest_length"
+.Fa "const void *key"
+.Fa "size_t key_length"
+.Fc
+.Ft void
+.Fo BLAKE2b_Update
+.Fa "BLAKE2B_CTX *ctx"
+.Fa "const void *data"
+.Fa "size_t length"
+.Fc
+.Ft void
+.Fo BLAKE2b_Final
+.Fa "BLAKE2B_CTX *ctx"
+.Fa "void *digest"
+.Fa "size_t digest_length"
+.Fc
+.Ft int
+.Fo BLAKE2s_Init
+.Fa "BLAKE2S_CTX *ctx"
+.Fa "size_t digest_length"
+.Fc
+.Ft int
+.Fo BLAKE2s_Init_Key
+.Fa "BLAKE2S_CTX *ctx"
+.Fa "size_t digest_length"
+.Fa "const void *key"
+.Fa "size_t key_length"
+.Fc
+.Ft void
+.Fo BLAKE2s_Update
+.Fa "BLAKE2S_CTX *ctx"
+.Fa "const void *data"
+.Fa "size_t length"
+.Fc
+.Ft void
+.Fo BLAKE2s_Final
+.Fa "BLAKE2s_CTX *ctx"
+.Fa "void *digest"
+.Fa "size_t digest_length"
+.Fc
+.Fd #define BLAKE2B_OUTBYTES 64
+.Fd #define BLAKE2B_KEYBYTES 64
+.Fd #define BLAKE2S_OUTBYTES 32
+.Fd #define BLAKE2S_KEYBYTES 32
+.Sh DESCRIPTION
+BLAKE2b and BLAKE2s are flavours of the BLAKE2 cryptographic hash
+function specified in RFC 7693.
+.Pp
+BLAKE2b is optimised for 64 bit platforms, and produces digests
+between 1 and
+.Dv BLAKE2B_OUTBYTES
+bytes in length.
+.Pp
+BLAKE2s is optimised for 8 to 32 bit platforms, and produces digests
+between 1 and
+.Dv BLAKE2S_OUTBYTES
+bytes in length.
+.Pp
+.Fn BLAKE2b_Init
+and
+.Fn BLAKE2s_Init
+initialise their respective context types referenced by
+.Fa ctx
+for generating digests of the length specified by
+.Fa digest_length .
+.Pp
+.Fn BLAKE2b_Init_Key
+and
+.Fn BLAKE2s_Init_Key
+initialise their respective context types referenced by
+.Fa ctx
+for generating keyed hashes of the length specified by
+.Fa digest_length .
+The hash is inititialised with
+.Fa key
+of length
+.Fa key_length .
+.Pp
+.Fn BLAKE2b_Update
+and
+.Fn BLAKE2s_Update
+feeds
+.Fa data
+of length
+.Fa len
+into the context
+.Fa ctx .
+Multiple updates may occur to feed multiple chunks of data into the hash.
+.Pp
+.Fn BLAKE2b_Final
+and
+.Fn BLAKE2s_Final
+generates the hash in the context
+.Fa ctx
+and places it in
+.Fa digest .
+.Fa digest_length
+must match the value used to initialize
+.Fa ctx .
+.Pp
+Applications should use the higher level functions
+.Xr EVP_DigestInit 3
+etc.  instead of calling the hash functions directly.
+.Sh RETURN VALUES
+.Fn BLAKE2b_Init ,
+.Fn BLAKE2b_Init_Key ,
+.Fn BLAKE2s_Init ,
+and
+.Fn BLAKE2s_Init_Key
+return 1 for success or 0 for failure.
+.Sh SEE ALSO
+.Xr EVP_DigestInit 3 ,
+.Xr HMAC 3
+.Sh STANDARDS
+.Rs
+.%A M-J. Saarinen
+.%A J-P. Aumasson
+.%D November 2015
+.%R RFC 7693
+.%T The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)
+.Re
Index: man/EVP_DigestInit.3
===================================================================
RCS file: /cvs/src/lib/libcrypto/man/EVP_DigestInit.3,v
retrieving revision 1.15
diff -u -p -r1.15 EVP_DigestInit.3
--- man/EVP_DigestInit.3        27 Mar 2018 17:35:50 -0000      1.15
+++ man/EVP_DigestInit.3        12 Nov 2018 00:10:37 -0000
@@ -90,6 +90,8 @@
 .Nm EVP_dss ,
 .Nm EVP_dss1 ,
 .Nm EVP_ripemd160 ,
+.Nm EVP_blake2b512 ,
+.Nm EVP_blake2s256 ,
 .Nm EVP_get_digestbyname ,
 .Nm EVP_get_digestbynid ,
 .Nm EVP_get_digestbyobj
@@ -222,6 +224,10 @@
 .Ft const EVP_MD *
 .Fn EVP_ripemd160 void
 .Ft const EVP_MD *
+.Fn EVP_blake2b512 void
+.Ft const EVP_MD *
+.Fn EVP_blake2s256 void
+.Ft const EVP_MD *
 .Fo EVP_get_digestbyname
 .Fa "const char *name"
 .Fc
@@ -420,12 +426,14 @@ function is only retained for compatibil
 .Fn EVP_sha256 ,
 .Fn EVP_sha384 ,
 .Fn EVP_sha512 ,
+.Fn EVP_ripemd160 ,
+.Fn EVP_blake2b512 ,
 and
-.Fn EVP_ripemd160
+.Fn EVP_blake2s256
 return
 .Vt EVP_MD
-structures for the MD5, SHA1, SHA224, SHA256, SHA384, SHA512 and
-RIPEMD160 digest algorithms respectively.
+structures for the MD5, SHA1, SHA224, SHA256, SHA384, SHA512,
+RIPEMD160, BLAKE2b512, and BLAKE2s256 digest algorithms respectively.
 .Pp
 .Fn EVP_md5_sha1
 returns an
@@ -556,8 +564,10 @@ is
 .Fn EVP_sha1 ,
 .Fn EVP_dss ,
 .Fn EVP_dss1 ,
+.Fn EVP_ripemd160 ,
+.Fn EVP_blake2b512 ,
 and
-.Fn EVP_ripemd160
+.Fn EVP_blake2s256 ,
 return pointers to the corresponding
 .Vt EVP_MD
 structures.
Index: man/Makefile
===================================================================
RCS file: /cvs/src/lib/libcrypto/man/Makefile,v
retrieving revision 1.142
diff -u -p -r1.142 Makefile
--- man/Makefile        8 Jul 2018 23:00:17 -0000       1.142
+++ man/Makefile        12 Nov 2018 00:10:37 -0000
@@ -43,6 +43,7 @@ MAN=  \
        BIO_s_socket.3 \
        BIO_set_callback.3 \
        BIO_should_retry.3 \
+       BLAKE2.3 \
        BN_BLINDING_new.3 \
        BN_CTX_new.3 \
        BN_CTX_start.3 \
Index: objects/objects.txt
===================================================================
RCS file: /cvs/src/lib/libcrypto/objects/objects.txt,v
retrieving revision 1.22
diff -u -p -r1.22 objects.txt
--- objects/objects.txt 11 Nov 2018 06:53:31 -0000      1.22
+++ objects/objects.txt 12 Nov 2018 00:10:37 -0000
@@ -657,6 +657,9 @@ algorithm 29                : RSA-SHA1-2            : 
sha1WithRS
 1 3 36 3 2 1           : RIPEMD160             : ripemd160
 1 3 36 3 3 1 2         : RSA-RIPEMD160         : ripemd160WithRSA
 
+1 3 6 1 4 1 1722 12 2 1 16 : BLAKE2b512                : blake2b512
+1 3 6 1 4 1 1722 12 2 2 8  : BLAKE2s256                : blake2s256
+
 !Cname sxnet
 1 3 101 1 4 1          : SXNetID               : Strong Extranet ID
 

Reply via email to