ChaCha20-Poly1305 support.
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 8fb78f1..d25581e 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -74,6 +74,8 @@
 add_subdirectory(des)
 add_subdirectory(rc4)
 add_subdirectory(conf)
+add_subdirectory(chacha)
+add_subdirectory(poly1305)
 
 # Level 1, depends only on 0.*
 add_subdirectory(digest)
@@ -134,6 +136,8 @@
 	$<TARGET_OBJECTS:des>
 	$<TARGET_OBJECTS:rc4>
 	$<TARGET_OBJECTS:conf>
+	$<TARGET_OBJECTS:chacha>
+	$<TARGET_OBJECTS:poly1305>
 	$<TARGET_OBJECTS:buf>
 	$<TARGET_OBJECTS:bn>
 	$<TARGET_OBJECTS:bio>
diff --git a/crypto/chacha/CMakeLists.txt b/crypto/chacha/CMakeLists.txt
new file mode 100644
index 0000000..d23ecb1
--- /dev/null
+++ b/crypto/chacha/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "arm")
+	set(
+		CHACHA_ARCH_SOURCES
+
+		chacha_vec_arm.S
+	)
+endif()
+
+add_library(
+	chacha
+
+	OBJECT
+
+	chacha_generic.c
+	chacha_vec.c
+
+	${CHACHA_ARCH_SOURCES}
+)
diff --git a/crypto/chacha/chacha.h b/crypto/chacha/chacha.h
new file mode 100644
index 0000000..ce53d49
--- /dev/null
+++ b/crypto/chacha/chacha.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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 OPENSSL_HEADER_CHACHA_H
+#define OPENSSL_HEADER_CHACHA_H
+
+#include <openssl/base.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and
+ * nonce and writes the result to |out|, which may be equal to |in|. The
+ * initial block counter is specified by |counter|. */
+void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in,
+                      size_t in_len, const uint8_t key[32],
+                      const uint8_t nonce[8], size_t counter);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_CHACHA_H */
diff --git a/crypto/chacha/chacha_generic.c b/crypto/chacha/chacha_generic.c
new file mode 100644
index 0000000..1e5b70d
--- /dev/null
+++ b/crypto/chacha/chacha_generic.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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. */
+
+/* Adapted from the public domain, estream code by D. Bernstein. */
+
+#include <openssl/chacha.h>
+
+#include <openssl/cpu.h>
+
+#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)
+
+/* sigma contains the ChaCha constants, which happen to be an ASCII string. */
+static const char sigma[16] = "expand 32-byte k";
+
+#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
+#define XOR(v, w) ((v) ^ (w))
+#define PLUS(x, y) ((x) + (y))
+#define PLUSONE(v) (PLUS((v), 1))
+
+#define U32TO8_LITTLE(p, v)    \
+  {                            \
+    (p)[0] = (v >> 0) & 0xff;  \
+    (p)[1] = (v >> 8) & 0xff;  \
+    (p)[2] = (v >> 16) & 0xff; \
+    (p)[3] = (v >> 24) & 0xff; \
+  }
+
+#define U8TO32_LITTLE(p)                              \
+  (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
+   ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
+
+/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
+#define QUARTERROUND(a,b,c,d) \
+  x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
+  x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
+  x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
+  x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
+
+#if defined(OPENSSL_ARM)
+/* Defined in chacha_vec.c */
+void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len,
+                           const uint8_t key[32], const uint8_t nonce[8],
+                           size_t counter);
+#endif
+
+/* chacha_core performs |num_rounds| rounds of ChaCha20 on the input words in
+ * |input| and writes the 64 output bytes to |output|. */
+static void chacha_core(uint8_t output[64], const uint32_t input[16],
+                        int num_rounds) {
+  uint32_t x[16];
+  int i;
+
+  memcpy(x, input, sizeof(uint32_t) * 16);
+  for (i = 20; i > 0; i -= 2) {
+    QUARTERROUND(0, 4, 8, 12)
+    QUARTERROUND(1, 5, 9, 13)
+    QUARTERROUND(2, 6, 10, 14)
+    QUARTERROUND(3, 7, 11, 15)
+    QUARTERROUND(0, 5, 10, 15)
+    QUARTERROUND(1, 6, 11, 12)
+    QUARTERROUND(2, 7, 8, 13)
+    QUARTERROUND(3, 4, 9, 14)
+  }
+
+  for (i = 0; i < 16; ++i) {
+    x[i] = PLUS(x[i], input[i]);
+  }
+  for (i = 0; i < 16; ++i) {
+    U32TO8_LITTLE(output + 4 * i, x[i]);
+  }
+}
+
+void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
+                      const uint8_t key[32], const uint8_t nonce[8],
+                      size_t counter) {
+  uint32_t input[16];
+  uint8_t buf[64];
+  size_t todo, i;
+
+#if defined(OPENSSL_ARM)
+  if (CRYPTO_is_NEON_capable() && ((intptr_t)in & 15) == 0 &&
+      ((intptr_t)out & 15) == 0) {
+    CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter);
+    return;
+  }
+#endif
+
+  input[0] = U8TO32_LITTLE(sigma + 0);
+  input[1] = U8TO32_LITTLE(sigma + 4);
+  input[2] = U8TO32_LITTLE(sigma + 8);
+  input[3] = U8TO32_LITTLE(sigma + 12);
+
+  input[4] = U8TO32_LITTLE(key + 0);
+  input[5] = U8TO32_LITTLE(key + 4);
+  input[6] = U8TO32_LITTLE(key + 8);
+  input[7] = U8TO32_LITTLE(key + 12);
+
+  input[8] = U8TO32_LITTLE(key + 16);
+  input[9] = U8TO32_LITTLE(key + 20);
+  input[10] = U8TO32_LITTLE(key + 24);
+  input[11] = U8TO32_LITTLE(key + 28);
+
+  input[12] = counter;
+  input[13] = ((uint64_t)counter) >> 32;
+  input[14] = U8TO32_LITTLE(nonce + 0);
+  input[15] = U8TO32_LITTLE(nonce + 4);
+
+  while (in_len > 0) {
+    todo = sizeof(buf);
+    if (in_len < todo) {
+      todo = in_len;
+    }
+
+    chacha_core(buf, input, 20);
+    for (i = 0; i < todo; i++) {
+      out[i] = in[i] ^ buf[i];
+    }
+
+    out += todo;
+    in += todo;
+    in_len -= todo;
+
+    input[12]++;
+    if (input[12] == 0) {
+      input[13]++;
+    }
+  }
+}
+
+#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 && !OPENSSL_ARM */
diff --git a/crypto/chacha/chacha_vec.c b/crypto/chacha/chacha_vec.c
new file mode 100644
index 0000000..d06d1dd
--- /dev/null
+++ b/crypto/chacha/chacha_vec.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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. */
+
+/* ====================================================================
+ *
+ * When updating this file, also update chacha_vec_arm.S
+ *
+ * ==================================================================== */
+
+
+/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and
+ * marked as public domain. It was been altered to allow for non-aligned inputs
+ * and to allow the block counter to be passed in specifically. */
+
+#include <openssl/chacha.h>
+
+#if !defined(OPENSSL_WINDOWS) && (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+
+#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */
+
+/* Architecture-neutral way to specify 16-byte vector of ints              */
+typedef unsigned vec __attribute__((vector_size(16)));
+
+/* This implementation is designed for Neon, SSE and AltiVec machines. The
+ * following specify how to do certain vector operations efficiently on
+ * each architecture, using intrinsics.
+ * This implementation supports parallel processing of multiple blocks,
+ * including potentially using general-purpose registers. */
+#if __ARM_NEON__
+#include <arm_neon.h>
+#define GPR_TOO 1
+#define VBPI 2
+#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0)
+#define LOAD(m) (vec)(*((vec *)(m)))
+#define STORE(m, r) (*((vec *)(m))) = (r)
+#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1)
+#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2)
+#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3)
+#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x)
+#if __clang__
+#define ROTW7(x) (x << ((vec) {7, 7, 7, 7})) ^ (x >> ((vec) {25, 25, 25, 25}))
+#define ROTW8(x) (x << ((vec) {8, 8, 8, 8})) ^ (x >> ((vec) {24, 24, 24, 24}))
+#define ROTW12(x) \
+  (x << ((vec) {12, 12, 12, 12})) ^ (x >> ((vec) {20, 20, 20, 20}))
+#else
+#define ROTW7(x) \
+  (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25)
+#define ROTW8(x) \
+  (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24)
+#define ROTW12(x) \
+  (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20)
+#endif
+#elif __SSE2__
+#include <emmintrin.h>
+#define GPR_TOO 0
+#if __clang__
+#define VBPI 4
+#else
+#define VBPI 3
+#endif
+#define ONE (vec) _mm_set_epi32(0, 0, 0, 1)
+#define LOAD(m) (vec) _mm_loadu_si128((__m128i *)(m))
+#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r))
+#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1))
+#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2))
+#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3))
+#define ROTW7(x) \
+  (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25))
+#define ROTW12(x) \
+  (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20))
+#if __SSSE3__
+#include <tmmintrin.h>
+#define ROTW8(x)                                                            \
+  (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, \
+                                                  11, 6, 5, 4, 7, 2, 1, 0, 3))
+#define ROTW16(x)                                                           \
+  (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, \
+                                                  10, 5, 4, 7, 6, 1, 0, 3, 2))
+#else
+#define ROTW8(x) \
+  (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24))
+#define ROTW16(x) \
+  (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16))
+#endif
+#else
+#error-- Implementation supports only machines with neon or SSE2
+#endif
+
+#ifndef REVV_BE
+#define REVV_BE(x)  (x)
+#endif
+
+#ifndef REVW_BE
+#define REVW_BE(x)  (x)
+#endif
+
+#define BPI      (VBPI + GPR_TOO)  /* Blocks computed per loop iteration   */
+
+#define DQROUND_VECTORS(a,b,c,d)                \
+    a += b; d ^= a; d = ROTW16(d);              \
+    c += d; b ^= c; b = ROTW12(b);              \
+    a += b; d ^= a; d = ROTW8(d);               \
+    c += d; b ^= c; b = ROTW7(b);               \
+    b = ROTV1(b); c = ROTV2(c);  d = ROTV3(d);  \
+    a += b; d ^= a; d = ROTW16(d);              \
+    c += d; b ^= c; b = ROTW12(b);              \
+    a += b; d ^= a; d = ROTW8(d);               \
+    c += d; b ^= c; b = ROTW7(b);               \
+    b = ROTV3(b); c = ROTV2(c); d = ROTV1(d);
+
+#define QROUND_WORDS(a,b,c,d) \
+  a = a+b; d ^= a; d = d<<16 | d>>16; \
+  c = c+d; b ^= c; b = b<<12 | b>>20; \
+  a = a+b; d ^= a; d = d<< 8 | d>>24; \
+  c = c+d; b ^= c; b = b<< 7 | b>>25;
+
+#define WRITE_XOR(in, op, d, v0, v1, v2, v3)                   \
+	STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0));      \
+	STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1));      \
+	STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2));      \
+	STORE(op + d +12, LOAD(in + d +12) ^ REVV_BE(v3));
+
+#if __ARM_NEON__
+/* For ARM, we can't depend on NEON support, so this function is compiled with
+ * a different name, along with the generic code, and can be enabled at
+ * run-time. */
+void CRYPTO_chacha_20_neon(
+#else
+void CRYPTO_chacha_20(
+#endif
+	uint8_t *out,
+	const uint8_t *in,
+	size_t inlen,
+	const uint8_t key[32],
+	const uint8_t nonce[8],
+	size_t counter)
+	{
+	unsigned iters, i, *op=(unsigned *)out, *ip=(unsigned *)in, *kp;
+#if defined(__ARM_NEON__)
+	unsigned *np;
+#endif
+	vec s0, s1, s2, s3;
+#if !defined(__ARM_NEON__) && !defined(__SSE2__)
+	__attribute__ ((aligned (16))) unsigned key[8], nonce[4];
+#endif
+	__attribute__ ((aligned (16))) unsigned chacha_const[] =
+		{0x61707865,0x3320646E,0x79622D32,0x6B206574};
+#if defined(__ARM_NEON__) || defined(__SSE2__)
+	kp = (unsigned *)key;
+#else
+	((vec *)key)[0] = REVV_BE(((vec *)key)[0]);
+	((vec *)key)[1] = REVV_BE(((vec *)key)[1]);
+	nonce[0] = REVW_BE(((unsigned *)nonce)[0]);
+	nonce[1] = REVW_BE(((unsigned *)nonce)[1]);
+	nonce[2] = REVW_BE(((unsigned *)nonce)[2]);
+	nonce[3] = REVW_BE(((unsigned *)nonce)[3]);
+	kp = (unsigned *)key;
+	np = (unsigned *)nonce;
+#endif
+#if defined(__ARM_NEON__)
+	np = (unsigned*) nonce;
+#endif
+	s0 = LOAD(chacha_const);
+	s1 = LOAD(&((vec*)kp)[0]);
+	s2 = LOAD(&((vec*)kp)[1]);
+	s3 = (vec){
+		counter & 0xffffffff,
+#if __ARM_NEON__ || defined(OPENSSL_X86)
+		0,  /* can't right-shift 32 bits on a 32-bit system. */
+#else
+		counter >> 32,
+#endif
+		((uint32_t*)nonce)[0],
+		((uint32_t*)nonce)[1]
+	};
+
+	for (iters = 0; iters < inlen/(BPI*64); iters++)
+		{
+#if GPR_TOO
+		register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8,
+				  x9, x10, x11, x12, x13, x14, x15;
+#endif
+#if VBPI > 2
+		vec v8,v9,v10,v11;
+#endif
+#if VBPI > 3
+		vec v12,v13,v14,v15;
+#endif
+
+		vec v0,v1,v2,v3,v4,v5,v6,v7;
+		v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3;
+		v7 = v3 + ONE;
+#if VBPI > 2
+		v8 = v4; v9 = v5; v10 = v6;
+		v11 =  v7 + ONE;
+#endif
+#if VBPI > 3
+		v12 = v8; v13 = v9; v14 = v10;
+		v15 = v11 + ONE;
+#endif
+#if GPR_TOO
+		x0 = chacha_const[0]; x1 = chacha_const[1];
+		x2 = chacha_const[2]; x3 = chacha_const[3];
+		x4 = kp[0]; x5 = kp[1]; x6  = kp[2]; x7  = kp[3];
+		x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7];
+		x12 = counter+BPI*iters+(BPI-1); x13 = 0;
+		x14 = np[0]; x15 = np[1];
+#endif
+		for (i = CHACHA_RNDS/2; i; i--)
+			{
+			DQROUND_VECTORS(v0,v1,v2,v3)
+			DQROUND_VECTORS(v4,v5,v6,v7)
+#if VBPI > 2
+			DQROUND_VECTORS(v8,v9,v10,v11)
+#endif
+#if VBPI > 3
+			DQROUND_VECTORS(v12,v13,v14,v15)
+#endif
+#if GPR_TOO
+			QROUND_WORDS( x0, x4, x8,x12)
+			QROUND_WORDS( x1, x5, x9,x13)
+			QROUND_WORDS( x2, x6,x10,x14)
+			QROUND_WORDS( x3, x7,x11,x15)
+			QROUND_WORDS( x0, x5,x10,x15)
+			QROUND_WORDS( x1, x6,x11,x12)
+			QROUND_WORDS( x2, x7, x8,x13)
+			QROUND_WORDS( x3, x4, x9,x14)
+#endif
+			}
+
+		WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3)
+		s3 += ONE;
+		WRITE_XOR(ip, op, 16, v4+s0, v5+s1, v6+s2, v7+s3)
+		s3 += ONE;
+#if VBPI > 2
+		WRITE_XOR(ip, op, 32, v8+s0, v9+s1, v10+s2, v11+s3)
+		s3 += ONE;
+#endif
+#if VBPI > 3
+		WRITE_XOR(ip, op, 48, v12+s0, v13+s1, v14+s2, v15+s3)
+		s3 += ONE;
+#endif
+		ip += VBPI*16;
+		op += VBPI*16;
+#if GPR_TOO
+		op[0]  = REVW_BE(REVW_BE(ip[0])  ^ (x0  + chacha_const[0]));
+		op[1]  = REVW_BE(REVW_BE(ip[1])  ^ (x1  + chacha_const[1]));
+		op[2]  = REVW_BE(REVW_BE(ip[2])  ^ (x2  + chacha_const[2]));
+		op[3]  = REVW_BE(REVW_BE(ip[3])  ^ (x3  + chacha_const[3]));
+		op[4]  = REVW_BE(REVW_BE(ip[4])  ^ (x4  + kp[0]));
+		op[5]  = REVW_BE(REVW_BE(ip[5])  ^ (x5  + kp[1]));
+		op[6]  = REVW_BE(REVW_BE(ip[6])  ^ (x6  + kp[2]));
+		op[7]  = REVW_BE(REVW_BE(ip[7])  ^ (x7  + kp[3]));
+		op[8]  = REVW_BE(REVW_BE(ip[8])  ^ (x8  + kp[4]));
+		op[9]  = REVW_BE(REVW_BE(ip[9])  ^ (x9  + kp[5]));
+		op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6]));
+		op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7]));
+		op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter+BPI*iters+(BPI-1)));
+		op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13));
+		op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[0]));
+		op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[1]));
+		s3 += ONE;
+		ip += 16;
+		op += 16;
+#endif
+		}
+
+	for (iters = inlen%(BPI*64)/64; iters != 0; iters--)
+		{
+		vec v0 = s0, v1 = s1, v2 = s2, v3 = s3;
+		for (i = CHACHA_RNDS/2; i; i--)
+			{
+			DQROUND_VECTORS(v0,v1,v2,v3);
+			}
+		WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3)
+		s3 += ONE;
+		ip += 16;
+		op += 16;
+		}
+
+	inlen = inlen % 64;
+	if (inlen)
+		{
+		__attribute__ ((aligned (16))) vec buf[4];
+		vec v0,v1,v2,v3;
+		v0 = s0; v1 = s1; v2 = s2; v3 = s3;
+		for (i = CHACHA_RNDS/2; i; i--)
+			{
+			DQROUND_VECTORS(v0,v1,v2,v3);
+			}
+
+		if (inlen >= 16)
+			{
+			STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0));
+			if (inlen >= 32)
+				{
+				STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1));
+				if (inlen >= 48)
+					{
+					STORE(op + 8, LOAD(ip +  8) ^
+						      REVV_BE(v2 + s2));
+					buf[3] = REVV_BE(v3 + s3);
+					}
+				else
+					buf[2] = REVV_BE(v2 + s2);
+				}
+			else
+				buf[1] = REVV_BE(v1 + s1);
+			}
+		else
+			buf[0] = REVV_BE(v0 + s0);
+
+		for (i=inlen & ~15; i<inlen; i++)
+			((char *)op)[i] = ((char *)ip)[i] ^ ((char *)buf)[i];
+		}
+	}
+
+#endif /* !OPENSSL_WINDOWS && (OPENSSL_X86_64 || OPENSSL_X86) */
diff --git a/crypto/chacha/chacha_vec_arm.S b/crypto/chacha/chacha_vec_arm.S
new file mode 100644
index 0000000..d82e6ee
--- /dev/null
+++ b/crypto/chacha/chacha_vec_arm.S
@@ -0,0 +1,885 @@
+# Copyright (c) 2014, Google Inc.
+#
+# Permission to use, copy, modify, and/or 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 file contains a pre-compiled version of chacha_vec.c for ARM. This is
+# needed to support switching on NEON code at runtime. If the whole of OpenSSL
+# were to be compiled with the needed flags to build chacha_vec.c, then it
+# wouldn't be possible to run on non-NEON systems.
+#
+# This file was generated by:
+#
+#     /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2012.10-20121022_linux/bin/arm-linux-gnueabihf-gcc -O3 -mcpu=cortex-a8 -mfpu=neon -S chacha_vec.c -I ../../include -fpic -o chacha_vec_arm.S
+
+	.syntax unified
+	.cpu cortex-a8
+	.eabi_attribute 27, 3
+
+# EABI attribute 28 sets whether VFP register arguments were used to build this
+# file. If object files are inconsistent on this point, the linker will refuse
+# to link them. Thus we report whatever the compiler expects since we don't use
+# VFP arguments.
+
+#if defined(__ARM_PCS_VFP)
+	.eabi_attribute 28, 1
+#else
+	.eabi_attribute 28, 0
+#endif
+
+	.fpu neon
+	.eabi_attribute 20, 1
+	.eabi_attribute 21, 1
+	.eabi_attribute 23, 3
+	.eabi_attribute 24, 1
+	.eabi_attribute 25, 1
+	.eabi_attribute 26, 2
+	.eabi_attribute 30, 2
+	.eabi_attribute 34, 1
+	.eabi_attribute 18, 4
+	.thumb
+	.file	"chacha_vec.c"
+	.text
+	.align	2
+	.global	CRYPTO_chacha_20_neon
+	.thumb
+	.thumb_func
+	.type	CRYPTO_chacha_20_neon, %function
+CRYPTO_chacha_20_neon:
+	@ args = 8, pretend = 0, frame = 304
+	@ frame_needed = 1, uses_anonymous_args = 0
+	@ link register save eliminated.
+	push	{r4, r5, r6, r7, r8, r9, sl, fp}
+	fstmfdd	sp!, {d8, d9, d10, d11, d12, d13, d14, d15}
+	sub	sp, sp, #304
+	add	r7, sp, #0
+	movw	ip, #43691
+	movt	ip, 43690
+	str	r2, [r7, #196]
+	sub	sp, sp, #96
+	ldr	r4, [r7, #196]
+	ldr	r6, [r7, #400]
+	ldr	r2, .L38+16
+	umull	r4, ip, ip, r4
+	ldr	r6, [r6, #0]
+	ldr	r8, [r7, #400]
+.LPIC24:
+	add	r2, pc
+	add	r4, sp, #15
+	str	r3, [r7, #244]
+	str	r6, [r7, #176]
+	bic	r4, r4, #15
+	str	r0, [r7, #188]
+	str	r4, [r7, #200]
+	lsrs	ip, ip, #7
+	str	r1, [r7, #184]
+	ldmia	r2, {r0, r1, r2, r3}
+	ldr	r4, [r8, #4]
+	ldr	r5, [r7, #244]
+	vld1.64	{d24-d25}, [r5:64]
+	vldr	d26, [r5, #16]
+	vldr	d27, [r5, #24]
+	ldr	r9, [r7, #200]
+	ldr	r8, [r7, #404]
+	ldr	r5, [r7, #176]
+	add	r6, r9, #64
+	str	r4, [r7, #300]
+	mov	r4, #0
+	str	r8, [r7, #288]
+	str	r5, [r7, #296]
+	str	r4, [r7, #292]
+	stmia	r6, {r0, r1, r2, r3}
+	vldr	d22, [r9, #64]
+	vldr	d23, [r9, #72]
+	vldr	d20, [r7, #288]
+	vldr	d21, [r7, #296]
+	str	ip, [r7, #192]
+	beq	.L20
+	lsl	r6, ip, #1
+	ldr	r1, [r9, #68]
+	add	r3, r6, ip
+	str	r6, [r7, #180]
+	ldr	r2, [r9, #72]
+	add	r8, r8, #2
+	ldr	r5, [r9, #76]
+	vldr	d18, .L38
+	vldr	d19, .L38+8
+	str	r4, [r7, #240]
+	ldr	r6, [r7, #184]
+	ldr	r4, [r7, #188]
+	str	r0, [r7, #224]
+	str	r1, [r7, #220]
+	str	r8, [r7, #208]
+	str	r2, [r7, #216]
+	str	r3, [r7, #204]
+	str	r5, [r7, #212]
+	str	r6, [r7, #252]
+	str	r4, [r7, #248]
+.L4:
+	ldr	r2, [r7, #244]
+	add	r9, r7, #216
+	ldr	r3, [r7, #244]
+	vadd.i32	q8, q10, q9
+	ldr	r6, [r7, #208]
+	vmov	q15, q13  @ v4si
+	ldr	r5, [r7, #240]
+	vmov	q3, q12  @ v4si
+	ldr	r4, [r7, #244]
+	vmov	q2, q11  @ v4si
+	adds	r5, r5, r6
+	ldr	r2, [r2, #8]
+	ldr	r6, [r7, #400]
+	vmov	q5, q10  @ v4si
+	ldr	r3, [r3, #12]
+	vmov	q1, q13  @ v4si
+	ldr	r0, [r7, #244]
+	vmov	q0, q12  @ v4si
+	ldr	r1, [r7, #244]
+	vmov	q4, q11  @ v4si
+	ldmia	r9, {r9, sl, fp}
+	str	r5, [r7, #228]
+	ldr	r5, [r4, #24]
+	ldr	r0, [r0, #0]
+	ldr	r1, [r1, #4]
+	str	r2, [r7, #264]
+	str	r3, [r7, #236]
+	ldr	r2, [r6, #4]
+	ldr	r3, [r4, #28]
+	str	r5, [r7, #280]
+	ldr	r5, [r6, #0]
+	movs	r6, #0
+	ldr	ip, [r7, #228]
+	ldr	r8, [r7, #212]
+	str	r0, [r7, #232]
+	str	r1, [r7, #268]
+	ldr	r0, [r4, #16]
+	ldr	r1, [r4, #20]
+	movs	r4, #10
+	str	r2, [r7, #24]
+	str	r3, [r7, #284]
+	str	r4, [r7, #256]
+	ldr	r2, [r7, #264]
+	str	r9, [r7, #276]
+	mov	r9, r6
+	ldr	r6, [r7, #280]
+	str	r8, [r7, #260]
+	mov	r8, sl
+	str	r1, [r7, #272]
+	mov	sl, ip
+	str	r6, [r7, #264]
+	mov	r6, r5
+	ldr	r3, [r7, #236]
+	mov	r5, r0
+	ldr	ip, [r7, #24]
+	ldr	r1, [r7, #268]
+	ldr	r0, [r7, #232]
+	b	.L39
+.L40:
+	.align	3
+.L38:
+	.word	1
+	.word	0
+	.word	0
+	.word	0
+	.word	.LANCHOR0-(.LPIC24+4)
+.L39:
+.L3:
+	vadd.i32	q4, q4, q0
+	add	r8, r8, r1
+	vadd.i32	q2, q2, q3
+	str	r8, [r7, #268]
+	veor	q5, q5, q4
+	ldr	r8, [r7, #276]
+	veor	q8, q8, q2
+	add	fp, fp, r0
+	str	fp, [r7, #280]
+	add	r8, r8, r2
+	vrev32.16	q5, q5
+	str	r8, [r7, #276]
+	vrev32.16	q8, q8
+	vadd.i32	q1, q1, q5
+	vadd.i32	q15, q15, q8
+	ldr	r8, [r7, #280]
+	veor	q0, q1, q0
+	ldr	r4, [r7, #260]
+	veor	q3, q15, q3
+	eor	sl, sl, r8
+	ldr	r8, [r7, #276]
+	add	fp, r4, r3
+	vshl.i32	q7, q0, #12
+	ldr	r4, [r7, #268]
+	vshl.i32	q6, q3, #12
+	eor	r6, r6, r8
+	eor	r9, r9, r4
+	ldr	r4, [r7, #272]
+	vsri.32	q7, q0, #20
+	ror	r8, r6, #16
+	ldr	r6, [r7, #264]
+	eor	ip, ip, fp
+	vsri.32	q6, q3, #20
+	ror	sl, sl, #16
+	ror	r9, r9, #16
+	add	r5, r5, sl
+	vadd.i32	q4, q4, q7
+	str	r5, [r7, #236]
+	vadd.i32	q2, q2, q6
+	add	r5, r4, r9
+	add	r4, r6, r8
+	ldr	r6, [r7, #284]
+	ror	ip, ip, #16
+	veor	q5, q4, q5
+	veor	q8, q2, q8
+	add	r6, r6, ip
+	str	r6, [r7, #264]
+	eors	r1, r1, r5
+	ldr	r6, [r7, #236]
+	vshl.i32	q3, q5, #8
+	vshl.i32	q14, q8, #8
+	eors	r2, r2, r4
+	eors	r0, r0, r6
+	ldr	r6, [r7, #264]
+	vsri.32	q3, q5, #24
+	ror	r1, r1, #20
+	eors	r3, r3, r6
+	ldr	r6, [r7, #280]
+	ror	r0, r0, #20
+	vsri.32	q14, q8, #24
+	adds	r6, r0, r6
+	str	r6, [r7, #284]
+	ldr	r6, [r7, #268]
+	vadd.i32	q1, q1, q3
+	vadd.i32	q15, q15, q14
+	ror	r2, r2, #20
+	adds	r6, r1, r6
+	str	r6, [r7, #260]
+	ldr	r6, [r7, #276]
+	veor	q6, q15, q6
+	veor	q7, q1, q7
+	ror	r3, r3, #20
+	adds	r6, r2, r6
+	str	r6, [r7, #280]
+	ldr	r6, [r7, #284]
+	vshl.i32	q0, q6, #7
+	vshl.i32	q5, q7, #7
+	add	fp, r3, fp
+	eor	sl, r6, sl
+	ldr	r6, [r7, #260]
+	eor	ip, fp, ip
+	vsri.32	q0, q6, #25
+	eor	r9, r6, r9
+	ldr	r6, [r7, #280]
+	ror	sl, sl, #24
+	vsri.32	q5, q7, #25
+	eor	r8, r6, r8
+	ldr	r6, [r7, #236]
+	ror	r9, r9, #24
+	ror	ip, ip, #24
+	add	r6, sl, r6
+	str	r6, [r7, #276]
+	ldr	r6, [r7, #264]
+	add	r5, r9, r5
+	str	r5, [r7, #272]
+	vext.32	q5, q5, q5, #1
+	add	r5, ip, r6
+	ldr	r6, [r7, #276]
+	vext.32	q0, q0, q0, #1
+	vadd.i32	q4, q4, q5
+	eors	r0, r0, r6
+	ldr	r6, [r7, #272]
+	vadd.i32	q2, q2, q0
+	vext.32	q3, q3, q3, #3
+	ror	r8, r8, #24
+	eors	r1, r1, r6
+	vext.32	q14, q14, q14, #3
+	add	r4, r8, r4
+	ldr	r6, [r7, #284]
+	veor	q3, q4, q3
+	veor	q14, q2, q14
+	eors	r2, r2, r4
+	ror	r1, r1, #25
+	vext.32	q1, q1, q1, #2
+	adds	r6, r1, r6
+	str	r6, [r7, #284]
+	vext.32	q15, q15, q15, #2
+	ldr	r6, [r7, #260]
+	eors	r3, r3, r5
+	ror	r2, r2, #25
+	vrev32.16	q8, q14
+	adds	r6, r2, r6
+	vrev32.16	q3, q3
+	str	r6, [r7, #268]
+	vadd.i32	q1, q1, q3
+	ldr	r6, [r7, #280]
+	vadd.i32	q15, q15, q8
+	ror	r3, r3, #25
+	veor	q5, q1, q5
+	adds	r6, r3, r6
+	veor	q0, q15, q0
+	str	r6, [r7, #264]
+	ldr	r6, [r7, #268]
+	ror	r0, r0, #25
+	add	fp, r0, fp
+	vshl.i32	q6, q5, #12
+	eor	sl, r6, sl
+	ldr	r6, [r7, #284]
+	vshl.i32	q14, q0, #12
+	eor	r8, fp, r8
+	eor	ip, r6, ip
+	ldr	r6, [r7, #264]
+	vsri.32	q6, q5, #20
+	ror	sl, sl, #16
+	eor	r9, r6, r9
+	ror	r6, r8, #16
+	vsri.32	q14, q0, #20
+	ldr	r8, [r7, #272]
+	ror	ip, ip, #16
+	add	r5, sl, r5
+	add	r8, r6, r8
+	add	r4, ip, r4
+	str	r4, [r7, #236]
+	eor	r0, r8, r0
+	str	r5, [r7, #280]
+	vadd.i32	q4, q4, q6
+	ldr	r5, [r7, #236]
+	vadd.i32	q2, q2, q14
+	ldr	r4, [r7, #276]
+	ror	r0, r0, #20
+	veor	q3, q4, q3
+	eors	r1, r1, r5
+	veor	q0, q2, q8
+	str	r8, [r7, #272]
+	str	r0, [r7, #24]
+	add	fp, r0, fp
+	ldr	r8, [r7, #280]
+	ror	r9, r9, #16
+	ldr	r0, [r7, #284]
+	add	r4, r9, r4
+	str	fp, [r7, #260]
+	ror	r1, r1, #20
+	add	fp, r1, r0
+	eor	r2, r8, r2
+	ldr	r0, [r7, #260]
+	eors	r3, r3, r4
+	vshl.i32	q5, q3, #8
+	str	r4, [r7, #232]
+	vshl.i32	q8, q0, #8
+	ldr	r4, [r7, #268]
+	ldr	r5, [r7, #264]
+	ror	r2, r2, #20
+	ror	r3, r3, #20
+	eors	r6, r6, r0
+	adds	r5, r3, r5
+	add	r8, r2, r4
+	vsri.32	q5, q3, #24
+	ldr	r4, [r7, #272]
+	eor	r9, r5, r9
+	eor	ip, fp, ip
+	vsri.32	q8, q0, #24
+	eor	sl, r8, sl
+	ror	r6, r6, #24
+	ldr	r0, [r7, #280]
+	str	r5, [r7, #276]
+	adds	r4, r6, r4
+	ldr	r5, [r7, #236]
+	vadd.i32	q1, q1, q5
+	str	r4, [r7, #272]
+	vadd.i32	q15, q15, q8
+	ldr	r4, [r7, #232]
+	ror	ip, ip, #24
+	ror	sl, sl, #24
+	ror	r9, r9, #24
+	add	r5, ip, r5
+	add	r0, sl, r0
+	str	r5, [r7, #264]
+	add	r5, r9, r4
+	str	r0, [r7, #284]
+	veor	q6, q1, q6
+	ldr	r4, [r7, #24]
+	veor	q14, q15, q14
+	ldr	r0, [r7, #272]
+	eors	r3, r3, r5
+	vshl.i32	q0, q6, #7
+	vext.32	q1, q1, q1, #2
+	eors	r0, r0, r4
+	ldr	r4, [r7, #284]
+	str	r0, [r7, #280]
+	vshl.i32	q3, q14, #7
+	eors	r2, r2, r4
+	ldr	r4, [r7, #280]
+	ldr	r0, [r7, #264]
+	vsri.32	q0, q6, #25
+	ror	r2, r2, #25
+	ror	r3, r3, #25
+	eors	r1, r1, r0
+	vsri.32	q3, q14, #25
+	ror	r0, r4, #25
+	ldr	r4, [r7, #256]
+	ror	r1, r1, #25
+	vext.32	q5, q5, q5, #1
+	subs	r4, r4, #1
+	str	r4, [r7, #256]
+	vext.32	q15, q15, q15, #2
+	vext.32	q8, q8, q8, #1
+	vext.32	q0, q0, q0, #3
+	vext.32	q3, q3, q3, #3
+	bne	.L3
+	ldr	r4, [r7, #264]
+	vadd.i32	q14, q10, q9
+	str	r2, [r7, #264]
+	vadd.i32	q10, q10, q5
+	ldr	r2, [r7, #252]
+	vld1.64	{d12-d13}, [r2:64]
+	ldr	r2, [r7, #220]
+	vadd.i32	q4, q11, q4
+	str	ip, [r7, #24]
+	mov	ip, sl
+	mov	sl, r8
+	ldr	r8, [r7, #260]
+	add	sl, sl, r2
+	ldr	r2, [r7, #212]
+	str	r4, [r7, #280]
+	vadd.i32	q0, q12, q0
+	ldr	r4, [r7, #224]
+	add	r8, r8, r2
+	ldr	r2, [r7, #240]
+	vadd.i32	q1, q13, q1
+	str	r0, [r7, #232]
+	add	fp, fp, r4
+	mov	r0, r5
+	ldr	r4, [r7, #216]
+	mov	r5, r6
+	mov	r6, r9
+	ldr	r9, [r7, #276]
+	adds	r2, r2, #3
+	str	r2, [r7, #240]
+	vadd.i32	q2, q11, q2
+	ldr	r2, [r7, #252]
+	add	r9, r9, r4
+	vadd.i32	q3, q12, q3
+	ldr	r4, [r7, #228]
+	vadd.i32	q15, q13, q15
+	str	r1, [r7, #268]
+	vadd.i32	q8, q14, q8
+	str	r3, [r7, #236]
+	veor	q4, q4, q6
+	ldr	r3, [r7, #284]
+	ldr	r1, [r7, #272]
+	add	ip, r4, ip
+	ldr	r4, [r7, #248]
+	vst1.64	{d8-d9}, [r4:64]
+	vldr	d8, [r2, #16]
+	vldr	d9, [r2, #24]
+	veor	q0, q0, q4
+	vstr	d0, [r4, #16]
+	vstr	d1, [r4, #24]
+	vldr	d0, [r2, #32]
+	vldr	d1, [r2, #40]
+	veor	q1, q1, q0
+	vstr	d2, [r4, #32]
+	vstr	d3, [r4, #40]
+	vldr	d2, [r2, #48]
+	vldr	d3, [r2, #56]
+	veor	q10, q10, q1
+	vstr	d20, [r4, #48]
+	vstr	d21, [r4, #56]
+	vldr	d8, [r2, #64]
+	vldr	d9, [r2, #72]
+	veor	q2, q2, q4
+	vstr	d4, [r4, #64]
+	vstr	d5, [r4, #72]
+	vldr	d10, [r2, #80]
+	vldr	d11, [r2, #88]
+	veor	q3, q3, q5
+	vstr	d6, [r4, #80]
+	vstr	d7, [r4, #88]
+	vldr	d12, [r2, #96]
+	vldr	d13, [r2, #104]
+	veor	q15, q15, q6
+	vstr	d30, [r4, #96]
+	vstr	d31, [r4, #104]
+	vldr	d20, [r2, #112]
+	vldr	d21, [r2, #120]
+	veor	q8, q8, q10
+	vstr	d16, [r4, #112]
+	vstr	d17, [r4, #120]
+	ldr	r4, [r2, #128]
+	ldr	r2, [r7, #248]
+	vadd.i32	q10, q14, q9
+	eor	r4, fp, r4
+	vadd.i32	q10, q10, q9
+	str	r4, [r2, #128]
+	ldr	r4, [r7, #252]
+	ldr	r2, [r4, #132]
+	eor	r2, sl, r2
+	ldr	sl, [r7, #248]
+	str	r2, [sl, #132]
+	ldr	r2, [r4, #136]
+	eor	r2, r9, r2
+	str	r2, [sl, #136]
+	ldr	r2, [r4, #140]
+	eor	r2, r8, r2
+	str	r2, [sl, #140]
+	ldr	r2, [r7, #244]
+	ldr	r4, [r4, #144]
+	ldr	r2, [r2, #0]
+	str	r4, [r7, #44]
+	ldr	r4, [r7, #232]
+	add	r8, r4, r2
+	ldr	r2, [r7, #44]
+	ldr	r4, [r7, #244]
+	eor	r8, r8, r2
+	ldr	r2, [r7, #252]
+	str	r8, [sl, #144]
+	ldr	r4, [r4, #4]
+	ldr	r2, [r2, #148]
+	str	r2, [r7, #40]
+	ldr	r2, [r7, #268]
+	add	r8, r2, r4
+	ldr	r4, [r7, #40]
+	ldr	r2, [r7, #244]
+	eor	r8, r8, r4
+	ldr	r4, [r7, #252]
+	str	r8, [sl, #148]
+	ldr	r2, [r2, #8]
+	ldr	r4, [r4, #152]
+	str	r4, [r7, #36]
+	ldr	r4, [r7, #264]
+	add	r8, r4, r2
+	ldr	r2, [r7, #36]
+	eor	r8, r8, r2
+	str	r8, [sl, #152]
+	ldr	r2, [r7, #252]
+	ldr	r4, [r7, #244]
+	ldr	r2, [r2, #156]
+	ldr	r4, [r4, #12]
+	str	r2, [r7, #32]
+	ldr	r2, [r7, #236]
+	add	r8, r2, r4
+	ldr	r4, [r7, #32]
+	ldr	r2, [r7, #252]
+	eor	r8, r8, r4
+	str	r8, [sl, #156]
+	ldr	r8, [r7, #244]
+	ldr	r2, [r2, #160]
+	ldr	r4, [r8, #16]
+	adds	r0, r0, r4
+	ldr	r4, [r7, #252]
+	eors	r0, r0, r2
+	str	r0, [sl, #160]
+	ldr	r0, [r8, #20]
+	ldr	r2, [r4, #164]
+	adds	r1, r1, r0
+	ldr	r0, [r7, #280]
+	eors	r1, r1, r2
+	str	r1, [sl, #164]
+	ldr	r2, [r8, #24]
+	ldr	r1, [r4, #168]
+	adds	r2, r0, r2
+	eors	r2, r2, r1
+	str	r2, [sl, #168]
+	ldr	r1, [r8, #28]
+	ldr	r2, [r4, #172]
+	adds	r3, r3, r1
+	eors	r3, r3, r2
+	str	r3, [sl, #172]
+	ldr	r3, [r4, #176]
+	eor	r3, ip, r3
+	str	r3, [sl, #176]
+	ldr	r3, [r4, #180]
+	ldr	r4, [r7, #400]
+	eors	r6, r6, r3
+	str	r6, [sl, #180]
+	ldr	r6, [r7, #252]
+	ldr	r2, [r4, #0]
+	ldr	r3, [r6, #184]
+	adds	r5, r5, r2
+	eors	r5, r5, r3
+	str	r5, [sl, #184]
+	ldr	r2, [r6, #188]
+	adds	r6, r6, #192
+	ldr	r3, [r4, #4]
+	str	r6, [r7, #252]
+	ldr	r0, [r7, #24]
+	ldr	r1, [r7, #240]
+	adds	r4, r0, r3
+	eors	r4, r4, r2
+	ldr	r2, [r7, #204]
+	str	r4, [sl, #188]
+	add	sl, sl, #192
+	cmp	r1, r2
+	str	sl, [r7, #248]
+	bne	.L4
+	ldr	r4, [r7, #192]
+	ldr	r3, [r7, #180]
+	ldr	r6, [r7, #188]
+	adds	r5, r3, r4
+	ldr	r8, [r7, #184]
+	lsls	r5, r5, #6
+	adds	r4, r6, r5
+	add	r5, r8, r5
+.L2:
+	ldr	r9, [r7, #196]
+	movw	r3, #43691
+	movt	r3, 43690
+	ldr	sl, [r7, #196]
+	umull	r9, r3, r3, r9
+	lsrs	r3, r3, #7
+	add	r3, r3, r3, lsl #1
+	sub	r3, sl, r3, lsl #6
+	lsrs	r6, r3, #6
+	beq	.L5
+	add	r1, r5, #16
+	add	r2, r4, #16
+	mov	r0, r6
+	vldr	d30, .L41
+	vldr	d31, .L41+8
+.L6:
+	vmov	q8, q10  @ v4si
+	movs	r3, #10
+	vmov	q1, q13  @ v4si
+	vmov	q14, q12  @ v4si
+	vmov	q3, q11  @ v4si
+.L7:
+	vadd.i32	q3, q3, q14
+	subs	r3, r3, #1
+	veor	q2, q8, q3
+	vrev32.16	q2, q2
+	vadd.i32	q8, q1, q2
+	veor	q9, q8, q14
+	vshl.i32	q14, q9, #12
+	vsri.32	q14, q9, #20
+	vadd.i32	q3, q3, q14
+	veor	q2, q3, q2
+	vshl.i32	q9, q2, #8
+	vsri.32	q9, q2, #24
+	vadd.i32	q8, q8, q9
+	vext.32	q9, q9, q9, #3
+	veor	q14, q8, q14
+	vext.32	q1, q8, q8, #2
+	vshl.i32	q8, q14, #7
+	vsri.32	q8, q14, #25
+	vext.32	q8, q8, q8, #1
+	vadd.i32	q3, q3, q8
+	veor	q2, q3, q9
+	vrev32.16	q2, q2
+	vadd.i32	q9, q1, q2
+	veor	q8, q9, q8
+	vshl.i32	q14, q8, #12
+	vsri.32	q14, q8, #20
+	vadd.i32	q3, q3, q14
+	veor	q2, q3, q2
+	vshl.i32	q8, q2, #8
+	vsri.32	q8, q2, #24
+	vadd.i32	q9, q9, q8
+	vext.32	q8, q8, q8, #1
+	veor	q14, q9, q14
+	vext.32	q1, q9, q9, #2
+	vshl.i32	q9, q14, #7
+	vsri.32	q9, q14, #25
+	vext.32	q14, q9, q9, #3
+	bne	.L7
+	vadd.i32	q8, q10, q8
+	subs	r0, r0, #1
+	vadd.i32	q3, q11, q3
+	vldr	d0, [r1, #-16]
+	vldr	d1, [r1, #-8]
+	vadd.i32	q14, q12, q14
+	vadd.i32	q1, q13, q1
+	veor	q3, q3, q0
+	vstr	d6, [r2, #-16]
+	vstr	d7, [r2, #-8]
+	vadd.i32	q10, q10, q15
+	vld1.64	{d8-d9}, [r1:64]
+	veor	q14, q14, q4
+	vst1.64	{d28-d29}, [r2:64]
+	vldr	d10, [r1, #16]
+	vldr	d11, [r1, #24]
+	veor	q1, q1, q5
+	vstr	d2, [r2, #16]
+	vstr	d3, [r2, #24]
+	vldr	d18, [r1, #32]
+	vldr	d19, [r1, #40]
+	add	r1, r1, #64
+	veor	q8, q8, q9
+	vstr	d16, [r2, #32]
+	vstr	d17, [r2, #40]
+	add	r2, r2, #64
+	bne	.L6
+	lsls	r6, r6, #6
+	adds	r4, r4, r6
+	adds	r5, r5, r6
+.L5:
+	ldr	r6, [r7, #196]
+	ands	ip, r6, #63
+	beq	.L1
+	vmov	q8, q10  @ v4si
+	movs	r3, #10
+	vmov	q14, q13  @ v4si
+	vmov	q9, q12  @ v4si
+	vmov	q15, q11  @ v4si
+.L10:
+	vadd.i32	q15, q15, q9
+	subs	r3, r3, #1
+	veor	q8, q8, q15
+	vrev32.16	q8, q8
+	vadd.i32	q3, q14, q8
+	veor	q9, q3, q9
+	vshl.i32	q14, q9, #12
+	vsri.32	q14, q9, #20
+	vadd.i32	q15, q15, q14
+	veor	q9, q15, q8
+	vshl.i32	q8, q9, #8
+	vsri.32	q8, q9, #24
+	vadd.i32	q9, q3, q8
+	vext.32	q8, q8, q8, #3
+	veor	q2, q9, q14
+	vext.32	q14, q9, q9, #2
+	vshl.i32	q9, q2, #7
+	vsri.32	q9, q2, #25
+	vext.32	q9, q9, q9, #1
+	vadd.i32	q15, q15, q9
+	veor	q3, q15, q8
+	vrev32.16	q3, q3
+	vadd.i32	q14, q14, q3
+	veor	q8, q14, q9
+	vshl.i32	q9, q8, #12
+	vsri.32	q9, q8, #20
+	vadd.i32	q15, q15, q9
+	veor	q3, q15, q3
+	vshl.i32	q8, q3, #8
+	vsri.32	q8, q3, #24
+	vadd.i32	q14, q14, q8
+	vext.32	q8, q8, q8, #1
+	veor	q3, q14, q9
+	vext.32	q14, q14, q14, #2
+	vshl.i32	q9, q3, #7
+	vsri.32	q9, q3, #25
+	vext.32	q9, q9, q9, #3
+	bne	.L10
+	cmp	ip, #15
+	vadd.i32	q11, q11, q15
+	bhi	.L37
+	ldr	r9, [r7, #200]
+	vst1.64	{d22-d23}, [r9:128]
+.L14:
+	ldr	sl, [r7, #196]
+	and	r3, sl, #48
+	cmp	ip, r3
+	bls	.L1
+	adds	r0, r5, r3
+	adds	r1, r4, r3
+	add	r2, r0, #16
+	add	r6, r1, #16
+	cmp	r1, r2
+	it	cc
+	cmpcc	r0, r6
+	rsb	r9, r3, ip
+	ite	cc
+	movcc	r2, #0
+	movcs	r2, #1
+	cmp	r9, #15
+	ite	ls
+	movls	r2, #0
+	andhi	r2, r2, #1
+	lsr	r8, r9, #4
+	eor	r2, r2, #1
+	cmp	r8, #0
+	it	eq
+	orreq	r2, r2, #1
+	lsl	sl, r8, #4
+	cbnz	r2, .L35
+	ldr	fp, [r7, #200]
+	add	r6, fp, r3
+.L17:
+	vld1.8	{q8}, [r0]!
+	adds	r2, r2, #1
+	cmp	r8, r2
+	vld1.8	{q9}, [r6]!
+	veor	q8, q9, q8
+	vst1.8	{q8}, [r1]!
+	bhi	.L17
+	cmp	r9, sl
+	add	r3, r3, sl
+	beq	.L1
+.L35:
+	ldr	r0, [r7, #200]
+.L25:
+	ldrb	r2, [r5, r3]	@ zero_extendqisi2
+	ldrb	r1, [r3, r0]	@ zero_extendqisi2
+	eors	r2, r2, r1
+	strb	r2, [r4, r3]
+	adds	r3, r3, #1
+	cmp	ip, r3
+	bhi	.L25
+.L1:
+	add	r7, r7, #304
+	mov	sp, r7
+	fldmfdd	sp!, {d8, d9, d10, d11, d12, d13, d14, d15}
+	pop	{r4, r5, r6, r7, r8, r9, sl, fp}
+	bx	lr
+.L37:
+	cmp	ip, #31
+	vld1.64	{d0-d1}, [r5:64]
+	vadd.i32	q9, q12, q9
+	veor	q11, q11, q0
+	vst1.64	{d22-d23}, [r4:64]
+	bls	.L12
+	cmp	ip, #47
+	vldr	d2, [r5, #16]
+	vldr	d3, [r5, #24]
+	vadd.i32	q13, q13, q14
+	veor	q9, q9, q1
+	vstr	d18, [r4, #16]
+	vstr	d19, [r4, #24]
+	bls	.L13
+	vadd.i32	q8, q8, q10
+	vldr	d0, [r5, #32]
+	vldr	d1, [r5, #40]
+	ldr	r6, [r7, #200]
+	vstr	d16, [r6, #48]
+	vstr	d17, [r6, #56]
+	veor	q8, q13, q0
+	vstr	d16, [r4, #32]
+	vstr	d17, [r4, #40]
+	b	.L14
+.L12:
+	ldr	r8, [r7, #200]
+	vstr	d18, [r8, #16]
+	vstr	d19, [r8, #24]
+	b	.L14
+.L20:
+	ldr	r5, [r7, #184]
+	ldr	r4, [r7, #188]
+	b	.L2
+.L13:
+	ldr	r6, [r7, #200]
+	vstr	d26, [r6, #32]
+	vstr	d27, [r6, #40]
+	b	.L14
+.L42:
+	.align	3
+.L41:
+	.word	1
+	.word	0
+	.word	0
+	.word	0
+	.size	CRYPTO_chacha_20_neon, .-CRYPTO_chacha_20_neon
+	.section	.rodata
+	.align	3
+.LANCHOR0 = . + 0
+.LC0:
+	.word	1634760805
+	.word	857760878
+	.word	2036477234
+	.word	1797285236
+	.ident	"GCC: (crosstool-NG linaro-1.13.1-4.7-2012.10-20121022 - Linaro GCC 2012.10) 4.7.3 20121001 (prerelease)"
+	.section	.note.GNU-stack,"",%progbits
diff --git a/crypto/cipher/CMakeLists.txt b/crypto/cipher/CMakeLists.txt
index 66e625e..cf2a4e2 100644
--- a/crypto/cipher/CMakeLists.txt
+++ b/crypto/cipher/CMakeLists.txt
@@ -14,6 +14,7 @@
 	e_rc4.c
 	e_des.c
 	e_aes.c
+	e_chacha20poly1305.c
 )
 
 add_executable(
diff --git a/crypto/cipher/aead.h b/crypto/cipher/aead.h
index f51fed1..24e8564 100644
--- a/crypto/cipher/aead.h
+++ b/crypto/cipher/aead.h
@@ -98,6 +98,9 @@
 /* EVP_aes_256_gcm is AES-256 in Galois Counter Mode. */
 const EVP_AEAD *EVP_aead_aes_256_gcm(void);
 
+/* EVP_aead_chacha20_poly1305 is an AEAD built from ChaCha20 and Poly1305. */
+const EVP_AEAD *EVP_aead_chacha20_poly1305();
+
 
 /* Utility functions. */
 
diff --git a/crypto/cipher/aead_test.c b/crypto/cipher/aead_test.c
index 1ae0162..0e934cd 100644
--- a/crypto/cipher/aead_test.c
+++ b/crypto/cipher/aead_test.c
@@ -146,6 +146,8 @@
     aead = EVP_aead_aes_128_gcm();
   } else if (strcmp(argv[1], "aes-256-gcm") == 0) {
     aead = EVP_aead_aes_256_gcm();
+  } else if (strcmp(argv[1], "chacha20-poly1305") == 0) {
+    aead = EVP_aead_chacha20_poly1305();
   } else {
     fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
     return 2;
diff --git a/crypto/cipher/chacha20_poly1305_tests.txt b/crypto/cipher/chacha20_poly1305_tests.txt
new file mode 100644
index 0000000..b7f1cc6
--- /dev/null
+++ b/crypto/cipher/chacha20_poly1305_tests.txt
@@ -0,0 +1,524 @@
+KEY: 9a97f65b9b4c721b960a672145fca8d4e32e67f9111ea979ce9c4826806aeee6
+NONCE: 3de9c0da2bd7f91e
+IN:
+AD:
+CT:
+TAG: 5a6e21f4ba6dbee57380e79e79c30def
+
+KEY: bcb2639bf989c6251b29bf38d39a9bdce7c55f4b2ac12a39c8a37b5d0a5cc2b5
+NONCE: 1e8b4c510f5ca083
+IN: 8c8419bc27
+AD: 34ab88c265
+CT: 1a7c2f33f5
+TAG: 2875c659d0f2808de3a40027feff91a4
+
+KEY: 4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd1100a1007
+NONCE: cd7cf67be39c794a
+IN: 86d09974840bded2a5ca
+AD: 87e229d4500845a079c0
+CT: e3e446f7ede9a19b62a4
+TAG: 677dabf4e3d24b876bb284753896e1d6
+
+KEY: 422a5355b56dcf2b436aa8152858106a88d9ba23cdfe087b5e74e817a52388b3
+NONCE: 1d12d6d91848f2ea
+IN: 537a645387f22d6f6dbbea568d3feb
+AD: bef267c99aec8af56bc238612bfea6
+CT: 281a366705c5a24b94e56146681e44
+TAG: 38f2b8ee3be44abba3c010d9cab6e042
+
+KEY: ec7b864a078c3d05d970b6ea3ba6d33d6bb73dfa64c622a4727a96ede876f685
+NONCE: 2bca0e59e39508d3
+IN: b76733895c871edd728a45ed1a21f15a9597d49d
+AD: cc1243ea54272db602fb0853c8e7027c56338b6c
+CT: 1fb9b2958fce47a5cada9d895fbb0c00d3569858
+TAG: 042ad5042c89ebc1aad57d3fb703d314
+
+KEY: 2c4c0fdb611df2d4d5e7898c6af0022795364adb8749155e2c68776a090e7d5c
+NONCE: 13ce7382734c4a71
+IN: 0dc6ff21a346e1337dd0db81d8f7d9f6fd1864418b98aadcdb
+AD: 0115edcb176ab8bfa947d1f7c3a86a845d310bf6706c59a8f9
+CT: dad65e4244a1a17ce59d88b00af4f7434bd7830ffdd4c5558f
+TAG: ac1437b45d8eacf9c0fe547c84fb82a2
+
+KEY: c66e89fbab01208f6a60847f4f34b38d27b554c119cf8d9e0b118aa7266ab865
+NONCE: 5d9856060c54ab06
+IN: f9e3e9b5ed07b2080db8c1ffc37e4a6cb3cd544608921e18610d00b17c6e
+AD: 85c112a1efe0a20ef3a550526a7afbc98f6367ebbede4e703099abd78f51
+CT: b5cc754f6dd19ef2d66f90e6bc9a322ddf216ef248cbe76b5ab6dd53bc36
+TAG: 6dd98710d8a889dceea0d0a936f98617
+
+KEY: a8b9766f404dea8cf7d7dfaf5822f53df9ccd092e332a57f007b301b507d5e14
+NONCE: c7f2f7a233104a2d
+IN: 4d6faeaee39179a7c892faae3719656cc614c7e6ecd8fcb570a3b82c4dace969090338
+AD: c6d83b6a56408a356e68d0494d4eff150530b09551d008373d6dee2b8d6b5619d67fdb
+CT: a15443f083316eef627a371f4c9ac654d0dd75255d8a303125e9f51af4233ff4ceb7fe
+TAG: 52504e880f6792a60708cc6db72eae42
+
+KEY: 5e8d0e5f1467f7a750c55144d0c670f7d91075f386795b230c9bf1c04ba250bc
+NONCE: 88049f44ba61b88f
+IN: 51a1eebcc348e0582196a0bce16ed1f8ac2e91c3e8a690e04a9f4b5cf63313d7ad08d1efbff85c89
+AD: 5d09bf0be90026f9fc51f73418d6d864b6d197ea030b3de072bd2c2f5cab5860a342abbd29dba9dc
+CT: 35aa4bd4537aa611fd7578fc227df50ebcb00c692a1cf6f02e50ed9270bd93af3bc68f4c75b96638
+TAG: ccea1cbbc83944cc66df4dbf6fb7fc46
+
+KEY: 21a9f07ec891d488805e9b92bb1b2286f3f0410c323b07fee1dc6f7379e22e48
+NONCE: 066215be6567377a
+IN: c1b0affaf2b8d7ef51cca9aacf7969f92f928c2e3cc7db2e15f47ee1f65023910d09f209d007b7436ee898133d
+AD: dfdfdf4d3a68b47ad0d48828dc17b2585da9c81c3a8d71d826b5fa8020fee002397e91fc9658e9d61d728b93eb
+CT: 8ff4ceb600e7d45696d02467f8e30df0d33864a040a41ffb9e4c2da09b92e88b6f6b850e9f7258d827b9aaf346
+TAG: 4eeddc99784011f0758ba5ebfba61827
+
+KEY: 54c93db9aa0e00d10b45041c7a7e41ee9f90ab78ae4c1bba18d673c3b370abde
+NONCE: 3f2d44e7b352360f
+IN: 1241e7d6fbe5eef5d8af9c2fb8b516e0f1dd49aa4ebe5491205194fe5aea3704efaf30d392f44cc99e0925b84460d4873344
+AD: f1d1b08dd6fe96c46578c1d1ad38881840b10cb5eae41e5f05fe5287223fa72242aea48cb374a80be937b541f9381efa66bb
+CT: 027b86865b80b4c4da823a7d3dbcf5845bf57d58ee334eb357e82369cc628979e2947830d9d4817efd3d0bc4779f0b388943
+TAG: 4303fa0174ac2b9916bf89c593baee37
+
+KEY: 808e0e73e9bcd274d4c6f65df2fe957822a602f039d4752616ba29a28926ef4a
+NONCE: 1b9cd73d2fc3cb8e
+IN: 3436c7b5be2394af7e88320c82326a6db37887ff9de41961c7d654dd22dd1f7d40444d48f5c663b86ff41f3e15b5c8ca1337f97635858f
+AD: d57cfbe5f2538044282e53b2f0bb4e86ea2233041fb36adb8338ded092148f8c2e894ef8766a7ec2dd02c6ac5dbab0c3703c5e9119e37c
+CT: 9b950b3caf7d25eaf5fca6fa3fe12ed077d80dcd5579851233c766bb8bb613ec91d925a939bb52fb88d5eda803cfe2a8cda2e055b962fd
+TAG: 6bf5b718f5bbe1395a5fdfcbbef752f5
+
+KEY: 4adfe1a26c5636536cd7cb72aa5bded0b1aa64487ad0e4078f311e8782768e97
+NONCE: d69e54badec11560
+IN: 19b3f9411ce875fcb684cbdc07938c4c1347e164f9640d37b22f975b4b9a373c4302ae0e7dfdeba1e0d00ced446e338f4c5bc01b4becef5115825276
+AD: bda1b0f6c2f4eb8121dcbd2eebd91a03ae1d6e0523b9b6f34b6f16ceca0d086654fb0552bfd5c8e1887730e1449ea02d7f647ae835bc2dab4bbc65b9
+CT: ea765a829d961e08bacaed801237ef4067df38ad3737b7c6de4db587a102a86fc4abbaabea0ee97c95ca7f571c7bab6f38cbae60cd6e6a4ce3c7a320
+TAG: b425cdf10cd0123a7e64b347c6b4b1f0
+
+KEY: eb3db86c14b7cc2e494345d0dfb4841bbd3aa1e2bc640cca0c6c405520685639
+NONCE: 88b54b28d6da8c81
+IN: f75c0a357271430b1ecff07a307b6c29325c6e66935046704a19845e629f87a9e3b8aa6c1df55dd426a487d533bb333e46f0d3418464ac1bef059231f8e87e6284
+AD: 34b08bb0df821c573dcb56f5b8b4a9920465067f3b5bf3e3254ea1da1a7fc9847fd38bdfe6b30927945263a91fa288c7cf1bee0fddb0fadf5948c5d83eb4623575
+CT: 146ec84f5dc1c9fe9de3307a9182dbaa75965bf85f5e64563e68d039a5b659aa8863b89228edb93ff3d8c3323ab0d03300476aa4aca206d4626a6b269b2078912d
+TAG: 0058a8dff32c29935c62210c359bd281
+
+KEY: dd5b49b5953e04d926d664da3b65ebcffbbf06abbe93a3819dfc1abbecbaab13
+NONCE: c5c8009459b9e31a
+IN: f21f6706a4dc33a361362c214defd56d353bcb29811e5819ab3c5c2c13950c7aa0000b9d1fe69bb46454514dcce88a4a5eda097c281b81e51d6a4dba47c80326ba6cea8e2bab
+AD: fe6f4cbb00794adea59e9de8b03c7fdf482e46f6c47a35f96997669c735ed5e729a49416b42468777e6a8d7aa173c18b8177418ded600124a98cbb65489f9c24a04f1e7127ce
+CT: 911ead61b2aa81d00c5eff53aeea3ab713709ed571765890d558fb59d3993b45f598a39e5eff4be844c4d4bd1ef9622e60412b21140007d54dcf31b2c0e3e98cf33a00fd27f0
+TAG: d38d672665e2c8c4a07954b10ecff7d9
+
+KEY: 3b319e40148a67dc0bb19271d9272b327bc5eee087173d3d134ad56c8c7dc020
+NONCE: ce5cf6fef84d0010
+IN: 27b5627b17a2de31ad00fc2ecb347da0a399bb75cc6eadd4d6ee02de8fbd6a2168d4763ba9368ba982e97a2db8126df0343cdad06d2bc7d7e12eec731d130f8b8745c1954bfd1d717b4ea2
+AD: a026b6638f2939ec9cc28d935fb7113157f3b5b7e26c12f8f25b36412b0cd560b7f11b62788a76bd171342e2ae858bcecb8266ff8482bbaed593afe818b9829e05e8e2b281ae7799580142
+CT: 368fb69892447b75778f1c5236e1e9d5d89255c3d68d565a5bba4f524d6ad27de13087f301e2ef4c08f5e2c6128b1d3e26de845c4ac4869e4c8bd8858ad0d26dec3b5d61a9e3666a3911ba
+TAG: 2e70564c3999c448d92cc6df29d095c4
+
+KEY: 43bf97407a82d0f684bb85342380d66b85fcc81c3e22f1c0d972cd5bfdf407f4
+NONCE: 8b6ba494c540fba4
+IN: 4b4c7e292a357f56fdf567c32fc0f33608110d7ce5c69112987d7b5a0bd46d8627a721b0aed070b54ea9726084188c518cba829f3920365afc9382c6a5eb0dd332b84612366735be2479b63c9efc7ff5
+AD: 1e0acf4070e8d6758b60d81b6d289a4ecdc30e3de4f9090c13691d5b93d5bbcef984f90956de53c5cf44be6c70440661fa58e65dec2734ff51d6d03f57bddda1f47807247e3194e2f7ddd5f3cafd250f
+CT: d0076c88ad4bc12d77eb8ae8d9b5bf3a2c5888a8d4c15297b38ece5d64f673191dc81547240a0cbe066c9c563f5c3424809971b5a07dcc70b107305561ce85aecb0b0ea0e8b4ff4d1e4f84836955a945
+TAG: 75c9347425b459af6d99b17345c61ff7
+
+KEY: 12fc0bc94104ed8150bde1e56856ce3c57cd1cf633954d22552140e1f4e7c65d
+NONCE: d3875d1b6c808353
+IN: 24592082d6e73eb65c409b26ceae032e57f6877514947fc45eb007b8a6034494dde5563ac586ea081dc12fa6cda32266be858e4748be40bb20f71320711bf84c3f0e2783a63ad6e25a63b44c373a99af845cdf452c
+AD: b8be08463e84a909d071f5ff87213391b7da889dc56fd2f1e3cf86a0a03e2c8eaa2f539bf73f90f5298c26f27ef4a673a12784833acb4d0861562142c974ee37b09ae7708a19f14d1ad8c402bd1ecf5ea280fab280
+CT: 9d9ae6328711fb897a88462d20b8aa1b278134cdf7b23e1f1c809fa408b68a7bfc2be61a790008edaa98823381f45ae65f71042689d88acfa5f63332f0fba737c4772c972eba266640056452903d6522cefd3f264e
+TAG: e9c982d4ade7397bcfaa1e4c5a6cd578
+
+KEY: 7b6300f7dc21c9fddeaa71f439d53b553a7bf3e69ff515b5cb6495d652a0f99c
+NONCE: 40b32e3fdc646453
+IN: 572f60d98c8becc8ba80dd6b8d2d0f7b7bbfd7e4abc235f374abd44d9035c7650a79d1dd545fa2f6fb0b5eba271779913e5c5eb450528e4128909a96d11a652bf3f7ae9d0d17adbf612ec9ca32e73ef6e87d7f4e21fe3412ce14
+AD: 9ff377545a35cf1bfb77c734ad900c703aee6c3174fdb3736664863036a3a9d09163c2992f093e2408911b8751f001e493decc41e4eeeed04f698b6daed48452a7e1a74ec3b4f3dcf2151ca249fa568aa084c8428a41f20be5fd
+CT: 229da76844426639e2fd3ef253a195e0a93f08452ba37219b6773f103134f3f87b1345f9b4bf8cfc11277c311780a2b6e19a363b6ac2efe6c4cc54a39b144e29c94b9ebbde6fd094c30f59d1b770ebf9fcad2a5c695dc003bf51
+TAG: b72acab50131a29558d56ae7b9d48e4e
+
+KEY: 4aeb62f024e187606ee7cc9f5865c391c43df1963f459c87ba00e44bb163a866
+NONCE: 9559bd08718b75af
+IN: c5d586ceece6f41812c969bcf1e727fe6ff8d1ae8c8c52367c612caa7cdf50e0662f5dffc5ea7d3cc39400dfe3dc1897905f6490fd7747b5f5f9842739c67d07ce7c339a5b3997a7fb4cd0d8e4817ff8916b251c11ef919167f858e41504b9
+AD: 51f5b503b73a5de8b96534c2a3f2d859ece0bd063ea6dfa486a7eec99f6c020983f7148cccb86202cf9685cc1cc266930f04e536ad8bc26094252baa4606d883bd2aeed6b430152202e9b6cc797ff24fc365315ed67391374c1357c9a845f2
+CT: 252ea42b6e5740306816974a4fe67b66e793ebe0914778ef485d55288eb6c9c45fa34ac853dc7a39252520514c3cb34c72b973b14b32bc257687d398f36f64cc2a668faffa7305ab240171343b5f9f49b6c2197e4fbe187b10540d7cdcfa37
+TAG: 711ff33ef8d2b067a1b85c64f32f1814
+
+KEY: 9a19e72f005cae1ae78b8e350d7aabe59fc8845999e8c52fad545b942c225eaf
+NONCE: d9dae2ea8d2ffc31
+IN: 2110378d856ded07eb2be8e8f43308e0c75bc8a3fcc7b1773b0725b7de49f6a166c4528e64120bdf7c9776615d3ce6feeb03de964a7b919206a77392f80437faceb6745845cafc166e1c13b68e70ca2a1d00c71737b8fcbbbd50902565c32159e05fcd23
+AD: 1cd73b72c4e103afbefd7c777e0480f3f5e68c60b85bd2e71ef5caebb175d7fc6535d39f38f92c24f2eb0fe97d878ed3d5967c0bb4394a5d41f7d34cda6e1523d3848f049cde554a7d31e1afeab5d3e6150f85858335cbd28c8a7f87d528058df50eea06
+CT: 5f009fbce4ec8e4ca9d8d42258b1a3e4e920b2fbad33d5e9f07557d9595e841025193b521ba440110dd83958e8ee30219d952b418e98a6c624894aa248aedc0678f2d263e7bfaf54ca379fef6c5d2f7ac422ea4b4369408b82d6225a7a2cf9a9f46fd4ef
+TAG: aa0a5fa7d3cf717a4704a59973b1cd15
+
+KEY: ba1d0b3329ecc009f1da0fab4c854b00ad944870fdca561838e38bad364da507
+NONCE: 8a81c92b37221f2f
+IN: 6289944ffa3ccea4bf25cd601b271f64e6deb0eba77d65efb4d69ca93e01996e4727168b6f74f3ccf17bd44715f23ceb8fc030c0e035e77f53263db025021fd2d04b87a1b54b12229c5e860481452a80a125cb0693a2ba1b47e28ee7cbaf9e683c178232c7f6d34f97
+AD: e57883961b8d041d9b9eeaddcfd61fa9f59213f66571fadffffdd1498b9b014f1ef2e7e56c3044d7f9fa7a1403a1169e86430a2a782137093f5456e142aad03a5f7a66d38009dd01b7fc02c9cf61642dedaf7cc8d46066c281ee17780674c3a36eae66c58d2d765075
+CT: 9c44d9135db0dbf81c862c1f69bec55a279794cdd29a58e61909aa29ec4c120c9c5a508d856b9e56138095714a4bb58402a1ad06774cf4ecdf2273839c0007cb88b5444b25c76f6d2424281101d043fc6369ebb3b2ff63cdb0f11a6ea1b8a7dafc80cdaef2813fa661
+TAG: 65c746f659bcbdcd054e768c57c848c9
+
+KEY: 0cf8c73a6cffc1b8b2f5d320da1d859d314374e4a9468db7fd42c8d270b7613a
+NONCE: 3c4c6f0281841aff
+IN: 4434728d234603c916e2faa06b25d83bad3348990ecde2344368d1a7af1309bd04251bb2e0b72044948f8dea33cce2618283b6af742073a9586b26c1089335fe735141e099785a1235810a3a67ff309e2f0ce68220ba0077ad1a5dc1a4aef898a3b9ff8f5ad7fe60149bd0bd6d83
+AD: a38d09a4f1c9241623c639b7688d8d35345ea5824080c9d74e4352919db63c74d318f19e1cbb9b14eebd7c74b0ad0119247651911f3551583e749ea50ff648858dcaaa789b7419d9e93a5bf6c8167188dbac2f36804380db325201982b8b06597efeb7684546b272642941591e92
+CT: bdfbfea261b1f4c134445321db9e6e40476e2dd2f4e4dbe86e31d6a116d25830762e065b07b11a3799aab93a94b4f98c31c0faeb77ec52c02048e9579257e67f5a6bae9bc65210c25b37fc16ee93bda88fd5f30a533e470b6188c6ce5739fa3e90f77120b490fc1027964f277f40
+TAG: 4993ee9582f58eabdb26b98c4d56a244
+
+KEY: 69f4e5788d486a75adf9207df1bd262dd2fe3dd3a0236420390d16e2a3040466
+NONCE: 6255bf5c71bb27d1
+IN: c15048ca2941ef9600e767a5045aa98ac615225b805a9fbda3ac6301cd5a66aef611400fa3bc04838ead9924d382bef8251a47f1e487d2f3ca4bccd3476a6ca7f13e94fd639a259ef23cc2f8b8d248a471d30ac9219631c3e6985100dc45e0b59b8fc62046309165ddb6f092da3a4f067c8a44
+AD: 0c83039504c8464b49d63b7f944802f0d39c85e9f3745e250f10119fa2c960490f75ae4dced8503b156d072a69f20400e9494ab2fa58446c255d82ff0be4b7e43046580bc1cf34060c6f076c72ea455c3687381a3b908e152b10c95c7b94155b0b4b303b7764a8a27d1db0a885f1040d5dbcc3
+CT: f0bb2b73d94f2a7cef70fe77e054f206998eacf2b86c05c4fa3f40f2b8cebf034fe17bcbee4dea821f51c18c0aa85b160f8508bd1dc455cc7f49668b1fb25557cdae147bf2399e07fcacaca18eccded741e026ef25365a6b0f44a6b3dd975ee6bb580f5fccd040b73c18b0fbf8f63199ba10fe
+TAG: 4236a8750f0cafee3c4a06a577a85cb3
+
+KEY: ad7b9409147a896648a2a2fe2128f79022a70d96dc482730cd85c70db492b638
+NONCE: a28a6dedf3f2b01a
+IN: 791d293ff0a3b8510b4d494b30f50b38a01638bf130e58c7601904f12cb8900871e8cf3d50abd4d34fda122c76dfee5b7f82cd6e8590647535c915ae08714e427da52f80aef09f40040036034ca52718ea68313c534e7a045cd51745ec52f2e1b59463db07de7ca401c6f6453841d247f370341b2dbc1212
+AD: 9a6defddb9b8d5c24a26dd8096f5b8c3af7a89e1f7d886f560fabbe64f14db838d6eb9d6879f4f0b769fe1f9eebf67fcd47b6f9ceb4840b2dba7587e98dc5cae186ef2a0f8601060e8058d9dda812d91387c583da701d2ba3347f285c5d44385a2b0bf07150cbc95e7fcfa8ae07132849a023c98817c03d2
+CT: c2f109d6d94f77a7289c8a2ab33bc6a98d976554721b0c726cbf4121069473e62ba36e7090e02414f3edc25c5d83ac80b49ad528cda1e3ad815b5a8c8ae9ad0753de725319df236983abd3f69ab4465d9b806c075b1896d40bdba72d73ba84c4a530896eb94ffccf5fb67eb59119e66a1861872218f928cf
+TAG: e48dc0153d5b0f7edb76fc97a0224987
+
+KEY: 48470da98228c9b53f58747673504f74ca1737d7d4bb6dbf7c0cba6ca42f80b9
+NONCE: 56fb4923a97e9320
+IN: bc6626d651e2b237f22ee51608ddcffeba5f31c26df72f443f701f2b085d6f34f806e29673584cb21522179edb62a82427d946acabce065b88b2878e9eb87ed1004e55ef58f51ec46375ac542c5782725ff013136cb506fcf99496e13fcd224b8a74a971cc8ddb8b393ccc6ac910bd1906ea9f2ed8a5d066dc639c20cd
+AD: df8ab634d3dca14e2e091b15ecc78f91e229a1a13cba5edd6526d182525ec575aa45bc70fb6193ffcd59bad3c347159099c4f139c323c30a230753d070018786b2e59b758dd4a97d1a88e8f672092bef780b451fd66ba7431cbb5660ea7816cdf26e19a6ebb9aadc3088e6923f29f53f877a6758068f79a6f2a182b4bf
+CT: a62e313ecf258cc9087cbb94fcc12643eb722d255c3f98c39f130e10058a375f0809662442c7b18044feb1602d89be40facae8e89ca967015f0b7f8c2e4e4a3855dbb46a066e49abf9cef67e6036400c8ff46b241fc99ba1974ba3ba6ea20dc52ec6753f6fc7697adbccd02b0bbea1df8352629b03b43cc3d632576787
+TAG: 675287f8143b9b976e50a80f8531bd39
+
+KEY: b62fb85c1decd0faf242ce662140ad1b82975e99a3fa01666cac2385ab91da54
+NONCE: 2f4a5ca096a4faf8
+IN: 03b14f13c0065e4a4421de62ab1d842bffb80f3da30bf47d115c09857f5bdd5756fd7c9ac3d9af1c9fb94f2640f7f4386cfba74db468e5288dbe4dd78bfe4f69e41480ca6138e8beacc6eaa3374157c713cfa900c07dd836eaecc8827fa3e70e052ae09e8473e2ae1a10b1bb669ef60a8dd957f6553daa8114918e17371f2ac327bd
+AD: cfe3b7ab7550b0e8e2e8235fa0dcef95647ce6814abd3dc3f5a3bd7d6d282504660c34ad8341e4d11402c7d46c83a494d7ddb105e1002979023e0e3dc2978c9ae53e10eb8567e7a02b60e51e945c7040d832ca900d132b4205a35034fed939a1b7965183c25654931a9b744401c4649c945710b0d9733b87451348b32ba81de30ea7
+CT: 8965db3d3ae4fb483208f147276e7d81b71a86e7202ffc9b1eaade009bc016838dc09ca4bcf30887b2f4243fbd652cd90ebed1ceef8151ff17ea70518d03b0f2a24960aa7de9b30fa65c2e2d57360061aae6d9376e984e9fcd5e5dd0911a4bc8deca832ffb76f252bd7da523076593ba6b174f7d9fb0377e066ecbb6638036241e86
+TAG: 3d0fc53e9058c2be32aa0850e0fab5a6
+
+KEY: de9c657258774d4ebc09d109a0fc79d66493ae578797cac4eb8830a6a4b547e0
+NONCE: b5e35fe3398efa34
+IN: 4d68fb683aa4f4c7a16ba1114fc0b1b8d8898610fa2763e435ded8771b3651078bef73d4dfd14e76a34cd5eb9ef4db4ead4da9e83f4ce50fe059977b2d17d687c29335a04d87389d211f8215449749969f7652dc1935a0f9a94538dc81dc9a39af63446a6517609076987920547d0098a9c6766cf5e704883ea32feaea1889b1554b5eb0ce5ecc
+AD: 436ea5a5fee8293b93e4e8488116c94d3269c19f1d5050def23d280515457b931bbed64a542b317cc5023d648330a4b7adca14dd6f3783207b94f86ccaa0a0ac39b7db00ac87a99e3cd8a764ed9c75da8454479636ab2b29e770b166a5b75cacc425c919bf1ce9ac34afe6b4425c3d9fd2e48bc81e7d15516d60e592bfcc2ebefb660f0995f2b5
+CT: 97a97b8f0f5420845ae8d57567f9bba693d30e6db916fad0b971f553ad7d993f806f27ab8b458d8046062ced4778c004b4f958a4436141637c6039963308dea2f54008b7feab79650295ed41bf9e65e1a2d75ab1c7b2a70ebb9e9f38d07a9a672d3e95ea78afe9ac02f2566b48b0251aef6eeeca8bd15bd8d43b559426aa9d15d960ee35cb3edf
+TAG: e55dbb21851e8a5b365f86d02518331c
+
+KEY: 6885bd333c336c7672db8ebdf24c1a1b605c5a4ae279f0f698162f47e6c73401
+NONCE: f0c4a213a6168aab
+IN: fa905a2bfa5b5bad767239fb070a7bc0b303d1503ecd2b429418cc8feba843e5444ed89022fdb379c3b155a0f9ceab2979000a0f60292a631771f2fde4ef065aa746426609082969530a9c70ad145308c30ba389ea122fd766081511a031ce3a0bd9f9f583c7000b333b79ac004fbde6ec3eb2d905977ff95dcff77858e3c424fe8932a6a12139e6ec8d5e98
+AD: 8ded368f919efb522bb6a9ad009e02ffbc6a16536e34d95cdb34f1153d7cb7b0f3c2b13dd05cedae27cfe68ec3aca8047e0930a29c9d0770c1b83c234dcb0385deae7ae85da73a5f8de3dfb28612a001f4e552c4f67ae0e2ec53853289b7017a58591fd6f70b0e954876bb2f7ec33001e298856a64bb16181017ba924648c09fc63c62eff262c80d614679bd
+CT: 0cb3d6c31e0f4029eca5524f951244df042fc637c4162511fea512a52d3f7581af097eb642e79e48666cb1086edbd38c4777c535a20945fabc23e7c9277e2b960aac46865f1026eb6da82759108b9baece5da930ccfc1052b1656b0eadaa120ed0c45ad04b24ae8cdb22ceab76c5f180b46a392ab45b1b99c612546e6b947f4d5c06ad5abee92ff96345ad43
+TAG: d3b541ac446c84626daf800c0172eec6
+
+KEY: fbc978abb1240a6937ccc16735b8d6ed5411cdbc1897214165a174e16f4e699b
+NONCE: 7968379a8ce88117
+IN: 1a8196cd4a1389ec916ef8b7da5078a2afa8e9f1081223fa72f6524ac0a1a8019e44a09563a953615587429295052cc904b89f778ef446ed341430d7d8f747cf2db4308478524639f44457253ae5a4451c7efca8ae0b6c5c051aaa781e9c505489b381a6dcba87b157edc7f820a8fbaf2a52e484dc121f33d9d8b9ac59d4901d6ed8996ed4f62d9d4d82274c449cd74efa
+AD: 3913cd01299b8a4e507f067d887d7e9a6ded16dd9f9bb3115c5779aa14239fd33ee9f25756d45262dc3011069356425b5c81a4729594e17c9747119f81463e85625d5603d05e00f568b0c800bb181eb717be8d7a93166a504ce1bc817e15530c5bd2b3df1d4222245ea78a38bc10f66c5cf68d661503131f11af885c8a910b6dce70bc3a7448dfae00595beb707fe054d3
+CT: d152bcb4c24c3711b0fad28548dc4db605bbc89237cdbea7dbf956b8855d1161a0781f27bd56d798141e2ace339955efb98fe05d9b44cd011e645106bf47726183958cb6df34ce5766695f60bc70b6fe0fabb9afa009a8ef043dbf75f861881368fa07726625448fe608d578cdc48277f2dc53eaaf1bdc075269a42f9302a57cad387a82c6969608acacda20e1cac4596c
+TAG: 945dca73cf2f007ae243991c4fbe0479
+
+KEY: 77d1a857fbadfe01aba7974eea2dfb3dc7bf41de73686aece403993e5016c714
+NONCE: fdd913a321c40eb0
+IN: db8915bfe651e2ecb3ce0b27d99a6bfa7a7c507cfcb2987293018636c365a459c6a138b4428be538413db15bda69e697cbb92b154b7f4d2cbb07965225aa6865d7dcd1ba2c17c484b00b1986fed63e889f25a4966dc3ed4273f1577768f665362d7d3e824484f0dded7f82b8be8797ad951719719365e45abbf76324bc7d657799d4d4f4bb1dba67d96ab1c88519a5bee704f7214814
+AD: 3cb2c06c20cb0832bbacebfc205d77393ca1816346ea2681de4d3ab1fadb774ad273e4713290454496f5281ebc65e04cfe84ed37cd0aedc4bbe3decbd8d79d04a4e434876650e0d64309e336bfb10e924066a64acb92260b2dbd96735d03af03909aa6a80a6e89fda81037257aec21fe9be7e91a64e88e0a58fa38ecba4c4c4cffb61958f3c486cbb0b1d0b0014a2d1d3df248eec1ca
+CT: acb825e6023b44b03b2efc265603e887954e8612b2ee134bdcb61501cfb9492952bf67be597c3a005b09af74d9e421a576d2c65e98104780feab838d8cb1bd135452ea39dc8907a4c1a6a9161805e4fa3e16989e6a418a7eea2582bf895da967028eab7c95d846a6de4b9980785814cf00484baa2f6de609912fff689bce6e854261ffe866bd8e63274605c7c5ad677bd7897ade543e
+TAG: 938478a41a3223a2199f9276d116210f
+
+KEY: b7e9b90dc02b5cd6df5df7283ef293ed4dc07513d9e67331b606f4d42dec7d29
+NONCE: a6c191f6d1818f8e
+IN: 2ada0e3c7ca6db1f780ce8c79472af4e8e951ddc828e0d6e8a67df520638ff5f14a2f95a5e5931749ae2c4e9946ae4d5eb5de42fb5b77d2236e2e2bd817df51be40b1b8a6c21015a7c79fe06dba4a08b34013dfa02747b5f03930268404c455dc54a74d9c6e35485e10026da573cb41cd50b64cfafe4cfcdf3c9684ef877e45d84e22bd5e15fa6c8fd5be921366ff0dc6fe2df45f7252972c9b303
+AD: 0f4269ed5ef0bfff7be39946a4e86e8bf79f84b70cd0b14fecb7be3c071316ce86de3d99d6871e0ba5667d9d7bba7dcaba10cb2a36668b6c3e2fb6c102938b75008bb9c213ebf9b85b5e91a802df0d31d7f11d764b2289f6225212694ab6b7c0e3ff36e84245d9f4f43fc5f98e654dea7ba9bd918658879c5bb4a1642af0d83113e3cf935d3c0d5208318f66f654eb17d8c28a602543e77ad3e815
+CT: 22586fe7338e99cdaad9f85bd724ba4cfe6249b8a71399f9a3707b5c4323b8d96679568dfc8d230aefb453df596e13eb3e8a439249bd64bc93a58f95089a62b94f6562b821c83d91f56c55147381e9de4beb4ae81bd6fe7caef7e7e9a2078f2fba8f3e70d4910da9accc92b8e81a61b0fefbece4bd89443e66e8ddda8e47a66a62f17fd0e7d0a4852ce1a4d43d72a0b5e8914bbec698f060f2b092
+TAG: c082470297da8c5f682a169d28bc0239
+
+KEY: 6b2cb2678d1102f2fbbd028794a79f14585c223d405e1ae904c0361e9b241e99
+NONCE: 7b3ae31f8f938251
+IN: b3cb745930e05f3ab8c926c0a343a6eb14809fd21b8390a6fcc58adb5579e5432021765b2d249a0ecf6ba678634c4f53f71495865f031ee97aa159f9ead3a3fcb823ee5238bdf12706a9c6137d236e2e7110ce650c321e41daf0afd62bab2a8fe55d7018de49a14efe6d83a15b2f256d595e998d25309f23633360f5745c50c4e5af8ccc9a8a2cb47064105a023e919c7795d2dc331d3f2afb8c42e5c0bcc26d
+AD: 1c32fd3df22b3e440e2a3c7a7624990194cb16a5f74af36f87fd6ca7d410ce9064316a2d091945deef7d9b35ceec8396069307caced2b80afd7d53ec479c35cedf2dfd4c95c3dd8400f71ad34028c6e4f8681d93d0774064ba38f3fb9b0c1dfa1f5f0c7d20676a5911d999fb6a1d41367a8e99d852bf3d3b7b3f4c233249ed1ca135389a674ff48232ded3f6800a97b6d409c40e6cd70d09bf9d2ad25d9b9485
+CT: ef70c7de98ab1d4ad817024a970be463443640eb0cd7ff234bdd00e653074a77a1d5749e698bd526dc709f82df06f4c0e64046b3dc5f3c7044aef53aebb807d32239d0652dd990362c44ec25bf5aeae641e27bf716e0c4a1c9fbd37bbf602bb0d0c35b0638be20dd5d5891d446137e842f92c0ee075c68225e4dbacb63cc6fb32442b4bcda5e62cb500a4df2741a4059034d2ccb71b0b8b0112bf1c4ca6eec74
+TAG: 393ae233848034248c191ac0e36b6123
+
+KEY: 4dbc80a402c9fceaa755e1105dc49ef6489016776883e06fcf3aed93bf7f6af7
+NONCE: 2358ae0ce3fb8e9f
+IN: 197c06403eb896d2fa6465e4d64426d24cc7476aa1ae4127cd2bd8a48ce2c99c16b1cbf3064856e84073b6cf12e7406698ef3dd1240c026cbd1ab04ee603e1e6e735c9b7551fd0d355202b4f64b482dd4a7c7d82c4fe2eb494d0d5e17788982d704c1356c41a94655530deda23118cba281d0f717e149fbeb2c59b22d0c0574c1a2e640afad1a6ceb92e1bf1dde71752a1c991e9a5517fe98688a16b073dbf6884cfde61ac
+AD: cf6ce7b899fb700a90d2a5466d54d31358ecf0562e02b330a27ba0138006b342b7ed6349d73c4c5c6d29bde75a25089b11dac5b27adea7e7640ca1a7ceb050e3aae84a47e11640a6e485bd54ae9fdb547edc7313d24a0328429fcffd8b18f39880edd616447344ebeec9eadb2dcb1fa7e67179e7f913c194ebd8f5a58aea73b0c5d1133561245b6d9c5cfd8bb0c25b38ffb37db5e2de5cdded6b57355e9d215cb095b8731f
+CT: aa87f9a83048b6919c8f2b050315db4e2adae4a9c2ca0109b81961b520e63299dcb028cec0b9d3249a945ee67dd029b40f361245c740f004f8cf0d2214fcfa65e6124a3e74b78aa94345c46fdc158d34823ed249ee550431eaae9218367321cdd6e6a477650469bb3cc137a8f48d9cf27934b16703608b383d2145659922fb83bb2e7ee2ef938a90f2ff846a4a949129b1fb74dde55c5ae013c2f285de84f7dac7d1662f23
+TAG: 06b4318ac7f65d556f781428a0514ffe
+
+KEY: 9e4a62016dae4b3223fed1d01d0787e31d30694f79e8142224fe4c4735248a83
+NONCE: 263a2fc06a2872e7
+IN: 5a46946601f93a0cee5993c69575e599cc24f51aafa2d7c28d816a5b9b4decda2e59c111075fb60a903d701ad2680bb14aeda14af2ae9c07a759d8388b30446f28b85f0a05cd150050bd2e715ff550ebbd24da3ebb1eac15aba23d448659de34be962ab3ab31cb1758db76c468b5bb8ce44b06c4e4db9bd2f0615b1e727f053f6b4ffb6358d248f022bcad6ca973044bed23d3920906a89a9a9c5d8024ec67d7f061f64529a955ce16b3
+AD: 4cd65f68f9f88c0516231f2a425c8f8a287de47d409d5ecde3ad151e906b3839fb01bb91a456f20ea9d394d4b06604ab1f9009ef29019af7968d965d1643161ab33a5354cda2fdc9f1d21ec9cb71c325c65964a14f9b26eb16560beb9792075a1597394000fd5f331bd8b7d20d88e5f89cf8d0b33e4e78e4904bb59c9c8d5d31ac86b893e4a0667af1be85fdb77f7ec3e2594a68048d20c2fb9422f5879078772ee26a1c560cbcbb2113
+CT: e944bb2ab06d138ad633c16ce82706ecf0ef5d119be1f3460c9ce101d9c4e04ef1677707fca40d1f8ca181e07273707b06624d6d7063c3b7b0bb0151b757b3e5237fb8004c161233d8bc7e5f28ea1c18da1874b3d54c5ad6ff0835eed35c8853704585cf83996e5e7cec68180af414e04f08134d3b0384ebdf0393c9310b55d8698fe10cb362defc0995e9a13b48b42cff61ffd9fe4c3c8c6dab355713b88f6e98a02e7231a0c6644ec4
+TAG: 27de0d4ca7648f6396d5419a7b1243b7
+
+KEY: 18ca3ea3e8baeed1b341189297d33cef7f4e0a2fab40ec3b6bb67385d0969cfe
+NONCE: b6aef34c75818e7c
+IN: ef6d1bb4094782f602fcf41561cba4970679661c63befe35ff2ca7ad1a280bf6b1e7f153fa848edfeffe25153f540b71253e8baba9aeb719a02752cda60ea5938aab339eead5aabf81b19b0fc5c1ed556be6ad8970ea43c303d3046205b12c419dea71c4245cfedd0a31b0f4150b5a9fe80052790188529ab32f5e61d8ccde5973ed30bdf290cbfbd5f073c0c6a020eac0332fced17a9a08cef6f9217bd6bef68c1505d6eed40953e15508d87f08fc
+AD: f40f03beaa023db6311bad9b4d5d0d66a58d978e0bcbbf78acebde1f4eb9a284095628955a0b15afc454152f962ec3ea2b9a3b089b99658e68ede4dee5acd56672025eb7323bcbc6ba5d91c94310f18c918e3914bbbf869e1b8721476f9def31b9d32c471a54132481aa89f6c735ab193369496d8dbeb49b130d85fbff3f9cb7dccea4c1da7a2846eef5e6929d9009a9149e39c6c8ec150c9ab49a09c18c4749a0a9fcba77057cdea6efd4d142256c
+CT: c531633c0c98230dcf059c1081d1d69c96bab71c3143ae60f9fc2b9cd18762314496ab6e90bf6796252cb9f667a1f08da47fc2b0eecda813228cae00d4c0d71f5e01b6ce762fa636efffe55d0e89fdc89ba42521cc019ab9d408fcd79c14914e8bbf0ea44d8a1d35743ad628327e432fdcfeb0b6679ddca8c92b998473732abd55dba54eefff83c78488eee5f92b145a74b6866531476fc46279d4fde24d049c1ce2b42358ff3ab2ba3a8866e547af
+TAG: a0a5242759a6d9b1aa5baf9a4ef895a2
+
+KEY: 95fdd2d3d4296069055b6b79e5d1387628254a7be647baafdf99dd8af354d817
+NONCE: cd7ed9e70f608613
+IN: 0248284acffa4b2c46636bdf8cc70028dd151a6d8e7a5a5bc2d39acc1020e736885031b252bfe9f96490921f41d1e174bf1ac03707bc2ae5088a1208a7c664583835e8bb93c787b96dea9fc4b884930c57799e7b7a6649c61340376d042b9f5faee8956c70a63cf1cff4fc2c7cb8535c10214e73cec6b79669d824f23ff8c8a2ca1c05974dd6189cfee484d0906df487b6bd85671ce2b23825052e44b84803e2839a96391abc25945cb867b527cdd9b373fbfb83
+AD: 24a45a3a0076a5bcfd5afe1c54f7b77496117d29f4c0909f1e6940b81dde3abacb71ec71f0f4db8a7e540bd4c2c60faee21dd3ce72963855be1b0ce54fb20ad82dbc45be20cd6c171e2bebb79e65e7d01567ad0eeb869883e4e814c93688607a12b3b732c1703b09566c308d29ce676a5c762a85700639b70d82aaef408cf98821a372c6a0614a73ba9918a7951ea8b2bb77cd9896d26988086d8586d72edc92af2042ff5e5f1429a22f61065e03cfcd7edc2a93
+CT: 40c6318d9e383e107cdd3e1c8951562193c3ef64ee442432a63e2edefc78f32ab07772aeac172cb67ecf4d21f8b448423527bbeb9d8ddd0b46bdb27f74096ceb24e41963b4cdca176676a75bdbe3abc270b349ac0c6cbd9c3a5cd5bce20202fc5cc0c1bdd4fd25e121e0a24bd7bbeb9b19b1912467bf5338ee2ce88aa383c082b42cc399c9654ca325f35523e81438beb3f8926be79c378822d7c8f785614408a5f7cac49e4543188725643e6c1a70b46d0ec400
+TAG: 5801e84192c7267f66b0e04607a39a3e
+
+KEY: 6ae1102f84ed4dc114bb9d63f4dc78d7dbb1ab63f1659dd95f47940a7b7a811f
+NONCE: c965d578ba91d227
+IN: b82a8a9209618f1f5be9c2c32aba3dc45b4947007b14c851cd694456b303ad59a465662803006705673d6c3e29f1d3510dfc0405463c03414e0e07e359f1f1816c68b2434a19d3eee0464873e23c43f3ab60a3f606a0e5be81e3ab4aa27fb7707a57b949f00d6cd3a11ae4827d4889dd455a0b6d39e99012fd40db23fb50e79e11f8a6451669beb2fbd913effd49ad1b43926311f6e13a6e7a09cf4bebb1c0bf63ce59cd5a08e4b8d8dbf9d002e8a3d9e80c7995bb0b485280
+AD: dfd4ac3e80b2904623ff79ea8ee87862268939decf5306c07a175b6b9da0eb13ac209b4d164755929e03240a0fe26599f136fb2afdffd12bb20354aa1d20e5799839abb68ae46d50c8974e13e361d87ef550fe6d82e8b5b172cf5cd08482efdef793ede3530d24667faf3a1e96348867c2942641f4c036981b83f50236b8e8a10b83ebf6909aad0076302f1083f72de4cf4a1a3183fe6ec6bfe2e73e2af8e1e8c9d85079083fd179ccc2ee9ff002f213dbd7333053a46c5e43
+CT: a9aeb8f0a2b3ca141ac71a808dcc0c9798ac117c5d2bd09b3cfe622693a9f8ca62e841b58bddb2042f888e3099b53638b88dfc930b7a6ee4272d77e4b1d7e442bab6afbde96ab0b432f0092d9ca50eef42f63c60c09e7b8de019b32ebe4030c37b8183cc1e3b913b0ce4ee4d744398fa03f9af1c070bed8cdafd65b3a84140cb4deadc70184de757332ce3780af84353f540755227e886a8d7ad980f3dd6fd68263d82e93f883381dec888bc9f4f48349aa2b4c342cb9f48c6
+TAG: f26b3af8a45c416291ce66330733b2f8
+
+KEY: 405bb7b94715b875df068655f00513cb1ae23ffaac977ce273e57d3f83b43663
+NONCE: 5c6da1259451119a
+IN: f9f143c0c52c94b4ba7b0608b144156a49e7b5d27c97315743d171911e3645ab7957c80924e3c6b9c22ab7a1cac4b7e9c0de84e49fd5e4a2d1ab51d764fc5670318688ec942f7ab34c331dce8f90fea6972e07f0dadec29d8eb3b7b6521ddd678a6527a962f4d8af78c077e27f7a0b2ef7eabd19e92b7f8c1e8fb166d4763ce9c40c888cf49aa9cdfc3e997c8fe1cce3fe802441bbd698de269ff316f31c196e62d12c6bb5cd93fb3c79ca6369f8c1ac9102daf818975ea7f513bb38576a
+AD: 6fe6446505677bf08b385e2f6d83ef70e1547712208d9cebc010cba8c16ea4ece058d73c72273eed650afdc9f954f35aa1bdf90f1118b1173368acbc8d38d93ebf85bd30d6dc6d1b90913790c3efa55f34d31531f70c958759b2ba6f956c6fcdd289b58cb4c26e9515bf550f0fd71ab8527f062c9505cbb16e8e037d34de1756bef02a133dbf4a9c00ac03befc3fb7f137af04e12595ce9560f98b612480fcdba3b8be01db56ebec40f9deae532c3b0370b5c23a2a6b02a4de69efa8900c
+CT: 1a4b073881922c6366680cc9c2a127b26f264148651b29abb0c388cf6c9b1865dba5a991e1f8309efbdb91bce44b278772c58fd41273526c33fec84beb53d1689b9da8483f71be6db73a73417069bb4cd3f195236e8d0a00d124eed3a6b6f89415b19a27fbe35774f6a1a6ee4bd4350b252b975f0db2d2eea82f4836350850d6290901e726e8af13644e2d98bc1d569c20800521e6affe976bd407049a2e6d9dd23f88d52e651391ecd2fc45b864310824aaadfa203762a77c1d64562dae
+TAG: 0060026d3efc120f11c0739959ae0066
+
+KEY: 8c602bd94c630cd00c7a9c508067a5a9f133d12f06d9f6fe2a7b68dce4786d8a
+NONCE: 760de0f7b7cb67e2
+IN: c3ff559cf1d6ba6c0cc793ca09a0ba573a28359386a6ec93e1bacd8e630209e0b477a20aedec3c9cbf513ee6a1e3887112218d6155b9875f7e6c4bbba2c31972e905d19f529f4f0f9502996199f94f8728ba8d6424bb15f87fcacd88bb42c63fcc513759712bd0172b1e87c9da122f1993ffb7efd3a5c34b240dd3db89dddea36dbeb2836d9f8648f8e7cd428c0f948097af753b35f9876059e7702027bb00dc69071206e785f48fcbf81b39cc0343974ac70784a2e60c0df93b40379bea4ad8cac625
+AD: 9e14907c3a8e96c2636db1f3d78eb1f673d6ef043cbbb349467f1fe29bf60f23d5d5d1c3b133a8ad72065d822347541c13d1574baf737eb3cc3382fb479e6d5193b9c8e7d2444c66971ef099dc7f37f6cd97b9f7959d46e2cf25e8a5b3111b4d9e2ef906d905f0ee2d17587f7082d7c8e9a51509bde03d3d64338e1838d71700f1b4fcb100b5e0402969da462f26f974b4f9e766121f8fd54be99fc10beb9a606e13fbb1f960062815d19e67f80093360324013095719273c65542b0e31b1a2a3d928f
+CT: 2794e6e133f6892f23837fff60cf7c28ee9942f8982ef8089db117903d0143293fdf12ea1cc014bcd8806fb83c19570eed7af522db0de489bbc87133a13434518bcfb9cda4d9f6d832a69209657a447abf8afd816ae15f313c7ea95ec4bc694efc2386cdd8d915dc475e8fadf3421fbb0319a3c0b3b6dfa80ca3bb22c7aab07fe14a3fea5f0aee17ab1302338eeac010a04e505e20096a95f3347dc2b4510f62d6a4c1fae6b36939503a6ac22780a62d72f2fc3849d4ef21267fffdef23196d88fbb9b
+TAG: 457cce6e075ffdb180765ab2e105c707
+
+KEY: bd68ff5eb296c71cfe6bc903c14907f7726bcb1331f0c75f7801cd1b7948f3a1
+NONCE: 65a748004b352ba6
+IN: 52bf78c00f6e5dca2fc60e2e9a52e827df97808e9cf727773860cafc89f4b64178a19b30b46ed813fe00c8f09b25a6a1b6e350d5b005122934a59bfbd5e6e0c635c84a5226c3f2f7dcf951560f18ac220453d583015fdb2e446c69c6e6fdecf2e595e04fab1b0c506e3c6bd5e4414a35f15021e97f447aa334f54a8f1ef942dec6273511b5668b696fca97188ff15ed84b2f46145cce031c1a7f00bd88bb83d90797edc46161b3fda7a2299173496d73b812139556e8b4eb318078b9eb2ae5046e83b79dd3d45950
+AD: 5557b08a5010cbc9f46bb140c2505f68684eb24889324bff44b27234fd7a95a99cfb4ff90a8f9982085b725f78ac42eca6ce7f3314e457dc41f404008681a9d29ba765660de2e05bb679d65b81f5e797d8417b94eb9aabbd0576b5c57f86eae25f6050a7918e4c8021a85b47f7a83b4c8446898441c5cc4e0229776ef3e809cb085d71f3c75ec03378730cb066150f07e60f96aec983c0e7e72bf6bf87ae42228dfda195f97855fcdf4e6d1c4479d978abcfa276d16ed60ecbfbfc664041335ce65a40a2ca3424df
+CT: a5c8cf42287d4760fca755e2111817b981c47e85b0047de270ec301ca5f7b3679f4749210892b6ea6568f3a6a4344734a0efc0120ffedecf212d55cbcbb67815ac964875af45f735b70092a8f8435f52fc01b981ae971d486026fb69a9c3927acfe1f2eab0340ae95f8dbee41b2548e400805ece191db5fd1f0804053f1dbfaf7f8d6fded3874cb92d99a2729d3faaa60522060cf0b8101b463b3eb35b380fcddb6406c027d73fe701a5090c8dd531c203ce979e26b9ced3431e2b726a7244a20d9377bd62951bf5
+TAG: 4579fa1fdb4c674cc3cd232b8da52a97
+
+KEY: 934fd043c32d16a88fad01c3506469b077cb79d258b5664fa55ad8521afdcaa2
+NONCE: c7091f6afbbeb360
+IN: 2bdd1fc4f011ef97ea52ec643819941c7e0fb39023c2f3c7683804a0ddee14a5d1784a5246966d533b3538edc7d8742d27061c3cab88df0318ab242102de3a54d03632eeb871b72c7e8f8065b49f4a91e95e15f3f46b29fd76b8fcea0d23570c5530e3bbb8a6aafa9ae32c1b3eac653c5ed5fdb2da5a986075808f6385870c85b1913e26042a9d8e78f5bc2ea6de5a64f8aeafa22adcffc7f6932d543c29bb3a04614783f948680e433a71573568d2ce984d249fb4fc06a9f358c76aa3e64a357f4eae924c1356bd5baccf7e0f
+AD: f737dd85638eb324dd3891219c5eef7c2dd053cfd055d447a411eba304a4b27dce981d112c4540590933c153d603022c91ebd2b4a58069d27e6ca17a462ef822ca41bffa80b43a68b1b564644cb3c5a7f0fddf7a13a30ff24437fddd8ef93c6f6f205d054f81890d982bd4d4ece0b1563677e843fe48c1f54e9a57ed4da66061482712e710a401073be5080d5b8b96525bffa67de5af31d50385fbbf1a87c21bf0e0a1fdff69ec32c7b7103e0b8ee6c844245e0fc84b9f89fcce62966cea68e2871d3b82e8df424c76309fc88d
+CT: dd13fbf22c8d18354d774bcd18f7eb814e9b528e9e424abc4e3f2463195e8018576565d16ab48845d11c9277f2865ebb4dc412fd5b27078f8325eadf971e6944c66542e34d9dda971e2aba70dbd3e94a1e638d521477a027776b52acf90520ca229ebc760b73128879475d1cbe1f70fc598b549cd92d8a9ac6833e500c138c56474db84cb3d70b7aa4f293a4c2b4d818b0ff9fd85918dc590a12a8c0e375c4d98b7fc87596547eb960676aad5559834588f00f251a9d53f95c47af4df3c4299175d5211779c148cfc988a5e9d9
+TAG: 476616ea15190c1093fdc4a087643cae
+
+KEY: f9f6eb9ad736a8f66e7459fef5ec2890188dc26baf34a95f6f0384e79f5c6559
+NONCE: 7858dfc084fe4b0f
+IN: a644ca6e7cc076e87eb2929fd257693fce0f6fb64fd632f7f07c648ebd03696c8e262e6a810d7b7c4e5eef8c65b5323c99dbba50a70b4a9e5c2a9e7315973cd67f35d8052ce9a85a206416dd3031929f4f929b13d0a5fb10cb73c65f6c0ace019da146b51c5274a099f44e3669d26add6f2ff081e886f3cf952fe0dbbe6b0534c23e307574bd35fbd657f5fcbd5dc19fb382a1dc0a2dc8285a0350f71554e4c601497749e35567dd4a273cddc9a48ce53a5f1d297fd8baf8d1b9feb35d9151114345abada4d90db947bb9a743c175f5653d1
+AD: 2048d1c2ddfb5ec385b201832c7a993f229ba72ec16d6ebf723ef0c5032b9966209a9e8a63151b40412e96b82f86728ea6588c7e8e11ac71cc8eabab8c4b54de866658d9c5011def61fb3dbe4e630158a45ea41a2ed55ebd1efb1abeda7637de6fa5fd2f151c6d2f385bf6cd002ca8b4a2896e0d65944ee913e3c784669dd201b1985ef3577f7f123a5f9bcffa176c8f557c4f729133cac518642f27d9b22ca9b97faaafe5b669a10b79ace4a7d5727df146c77ce681357d69f9c2d65b4401bd73cd113387e3b3a05d897adad7a24c485e7b
+CT: 4146faffd7313f5d9f625370d20413cc62ab65f4acfa3c7ee1125b937dd7a39f638fc46c8ed004fb525698de5d8620ec153435571817c3de257b0d0e648ebb92940c86a98262d54e764f28cbdd4f7d9bea970291f2110414f62064d7229c6332236c507b3dac742e651d85a2a22fb243c0cc7cc2d016e5bea38f33f9a9ce048944a5fe8b078d71d23168e12dfe5a0f0b829771edc7073fb96032b7be471337a37aca0cf7c0cdd543eed686cd34934717fd79a3f18492eef72f9f450b880aa7e2e1b65e3b04c22e72301338b43aa32ceec2e6
+TAG: 10ffaf2be316676da02d7473a9df87b9
+
+KEY: 29b19636cdd32507fd98ec4ee26caab1a917646fb8f05b0dc01728a9f4a127f0
+NONCE: 06699d245916686d
+IN: 5fdf913aceab1d6dbaf7d9a29352fa8a3eb22718043a79cffa2fe8c35c820aec7c07644b8785dcf7a433b4189abb257fb12b06fae0662641011a069873c3e3c5ccc78e7358184a62c2005c44b8a92254958eb5ff460d73cd80284d6daba22c3faba046c5426fe8b7cacec64b235a8f8d3e2641e5bc378830594bcfb27c177aea745951ee5780a63705727ef42c4ad3abf556d88e3830f3db6b09e93edd09485cbf907f79de61f8dc5cb5fb7665ffa0ef53cb48702f6a81d8ad421cef20c1dbdf402b8fafed56a5361b2f93f914a2380fdd0557faf1f4de
+AD: 39116c49cc13adb065b92cb7635f73d5f6bf6b5ccbf72a3f65a5df6bd4a661105015358d9e69f42e98aed795e8161282bc113058b7ef3b9e23fcd8eeab34a392e03f4d6329c112cb968385ec52a7afc98bb8695785af6b27b700973cc952630b7247ce226b4fbb99b8a486370bf6345d4516c52c64e33f407c4f2d1ba90545c88732d98bbd97972ac5e94c694624a9b3782b0099824651cb7567914d25b3e13181a791dbcd40e76e836b3350d310a52151bf835d3c357c9871482c2928e8404c6e533406d4d6fa8f63366f2c4ed828141f1ff00f01a536
+CT: 01e237220b619054a1f3670928fe67d40484b5af40fbd04d032500aac5acaa3b4584dd99a58c390627636a50de5d744f76a56a33205f9e3b00e16162eb47ff3333e1e208ca200f1a5338a86e17bd92dd2d16af8bb022a7dc05b923d019e05247f1a0d0b4bfcfce58dd6d83830705707676d55739abee89fcd5cb94b8fde006a5da02df64b00a467f45970b5ca440f22319b9735a55d454b9fba0588fef0c59d3d83823eba6e0601a96e10233826c5adeea6b2a51d386a07a9e047ad405b23d4c3d89f30c31e3199f0c8f927bfac43ceea1f969de0a8c0f
+TAG: 092f9f3c5d4f2570c9946c87967f4579
+
+KEY: bae06b9b5456707551c7b0e207aae02a19b4848ad8ca4ce40705bf8c856a6e52
+NONCE: 9c27065c3ef2d522
+IN: 50cdd88137ff428a88e87b5845be4924f6387537bb5c0b654c80107ab5698db75b2e131848e7aec156d31aed0766d31c379fece4095d38264c6d5945974d25f729c3b0ba11ea853e9cebdb6f03bb670fce08adff74d0a8f02d633fb34e0fb7337a8e66e1c12084d914fb6173b8105684db822752c6751a372bb16690284d661b8b8bc6a6dfbddf45ebc2219596f9f2f878c118df69030de38b4d99dde43b9b9e20a3dab691645dd518342f49b06a0fe0a397adf261e99f07af5b0b3798b1022ba0939c42a54d3b93641cffa3c2e174bce9ab7ad7e7c7924308d1a77a
+AD: 5d5590db1bd316eb7a0e30e4c7a6dfdbef9d3287fdb8d824389599c3c2ee262b2192eb5b9708e66e22dbc7eca83fa1a995da3ce64c86fe5aa08b826d476dc439497e2d12e2702c63c8d27aa7f09fedee816dc8bffe1351d53271a34d4292b613b7efcedb7e3cf3e6ad389eef12471e9e20e38e7ae22a323abbadfe8f2e84271bffb1819feb4f77b82843cb8757cfae293631bc6d39669107e7015c85d7343ffa6fc1bbe6f5ab4de30cd752a281e03061ea89de2a3f5e90e20da22fd6e8525c100738667f42212b2cf45fcb23bbb54b21c117484b22c6e514685314df
+CT: 66b7f69ac49fab4e5975aeb6fa9287d8eac02ac312c4de78f77f59da16cbcf87274e66801c4b862c33ea79cdc76528862bb2956c06db8b8acfac4794ebf39e35ac03cc73a4351a4ff762f681a48d6f25cad36e2814c9b5c40b9ae92509e58429106847789454d376836936bebc7a80e6c66e7aa52936d6b361378a41f849ad4e48f9ee2d3e92217a908fa8eb35736ac8ada7d32ae05391f2d807be3512543c36138a5fe660dd4cd4cd184bb43b6ba6bc0bae634e2fa9669304cd510ed5103f630068ff76d3375738de60a381842b421477e25a490cdd6894b2704125
+TAG: c9998a677dfb0e91924aec9de0afd585
+
+KEY: 2cb374cb048c168f2e43597f028d9e73cade1b458284ffc260d4fc6b9011c414
+NONCE: 9fb909169bc9f4e9
+IN: 39eb929482784b463546f5d84f80510f2019923d465b99d194246d68c7ae343f91971d8f7059cebb86aa5dd099289aa648248b8c5ca04e66ac5e9bf06776e3883495397618a0227f035666806e636836b47d3d2d255a49db79866cf00d9ddabda259c4f968a1e01e651c7811cebbee2ee71803ea1d9d23487eb221f2d9555756800aba5e6abbefd6fb72b3151cc99ced599cd86df2a9b1ce94f89f347eeb124d9e7f0d9cc48d3dedd819e6d3dbac57ecee199547b266116a2035c9acc4c8ca3271ac74952372897c4a5f2cb84e2d81817fec9d6774f6d8a5b2021684132db4fca3
+AD: 0c7bd4f3a30ee944ccf9489181e6911684dcffad4593a9b65a67dfc80718c69b35897d01281016b7731e12c15cad8482e79458e08a755622e3f3f22a23ef6c8487a36ad1771ba06c641f06f85de0db3776cc6df06ad8fe3b4d60d58508de943083f17cbb9dc0d390ac94d8429e8c6fcfe063f424fbde0f62f6a7f91a626d195dc498a6e69bd93109c4e9ba13e7330aba456d710a4b0cc279d4045660406e26d61dff70d4a33c4f1052869f9248024e7a0f85f1effb32f6f7ccb1f860f3ef04e8f7b29096e6bcf9d4b3e0ce703e9bf228fdf515c2ff9cbabd16987be0f9babd3d8a
+CT: 91ddadb86b7ebef798ddaa59da51d71316fcf6c9678143178227d778750dc9827fc6cc21e605c505023e6db25849df7fb6fc1ca4d223aa215f8c85b724643c83bf8218815a9f9e2952384e0ca6a80a3760b39daf91a3c6154c4728c2371fd181fa3764753d0b0c23808a82cd8f0497246e3a0f17f8906a07c725d2891ce968a9d432c2b102d85c05510b28e715bb60d0403a77490e7f18be81218bc4f39287b9bb09f50227dd2f55e4fb70c4438da8ba3c8ffbced87d90155913faa9979fc57e6cbeddfaba3d3ab4163c0eebc7d94279c27d3ed56338893dba542eaefba30f8c3b
+TAG: 728e60f8124effbac234f70da925881c
+
+KEY: f0f16b6f12b3840bbd1c4a6a0811eef237f1521b45de9986daec9f28fca6485c
+NONCE: 7ac93e754e290323
+IN: 0530556424d823f90a7f1c524c4baa706aad2807e289e9479301e3e7a71f2a5e14e6232ea785f339c669af2e6d25f1d5a261096a548d23864945c3a589b67b09b0304a784d61b42b2419139485242e0d51fcbe9e8fed996d214de8717e6a71f8987ccad65eb92e66707034a5ae38e6486e26eb4374c565aad5df949dab209f7f7bcd8eb6fc52761a26cfe5d01fd349e59f4042e6dbe6b232f9301b971dee121d8aa1e62d40f043a42f3aa859d867eb809b1ced5ae1ec62cacf94a69fafd0631a8b5dfd66d855900fb295eec90ae5fcbf77beae267a79d24081bb322d8c4e0630fed252541b36
+AD: 13bfcc17b810099cda31ca53a1323db9b07633ceb2088a42263a4cbd6a4d47978776005c9a20203319c3a3ae434e9a26fb541047dc9df38dc36c095267272e203d0b24d119a70a7e96041b6d82b7c4d5570e1e4a1cf2f6e44ae63fe005a1f5b900778c482f7bd89e2e02305e35b8f61b7bb2c78a13aebfce0145d1c5aa0bf1d10d23616d5a3a446de550302f56f81dc56fe4f3700f14242688d9b92d8a427979b403c8de8c493a2cde510eaf6b285e6675b173aa0314a386b635c7577d5aff0d868a0cb3f73c8d2005f8c7c9dab5a060ef80102c9d4a4af988838afe87aff04c0689e8c3c7f9
+CT: 2c14c3931e98e84507c4c165c2ed47ad4a178f0e216cd7ac2453bbbf9f85dd06bd8ef54a9ff1fd3dd8e0cafb635d8f2de861a0db5b14d03f17aaea8c89b3010797c71c13a0e666899d7ff6e53c4f08be8ddb3e37688b5afa088079b6c7519b833e16560073e699530302028a3496e05edddec01a23a4c7983956250e8d9e616f7b940856955cde81c1efabf6b7b92f153d03f4cd17e7f7d2907670cfc84d45c1d7936775a3fce47968504278ffaecacea0871b227f250e2979516f6fa310fec0d8df1af7872e5a534e82870aa05f43ef0a455846b93ce938064fa33e92de262e4156dae56775
+TAG: d95d73bf9aeb71eba9042396f3725424
+
+KEY: 3792943c0396f1840496917ce8ad89608385007e796febeea3805f3f4cbeccf7
+NONCE: 23b2f9068b2c4c85
+IN: be6b67eb943ee7b5c785cd882f653e73a8f75b4a41a2a7c56ae5a10f729caf39948fe48ad0e51240e2e7aa43193c7ec6ce7f4909fc94c9f99e38e6a0ad7e98eb29c5c2e61c99e9cbe890f154185cec213a74725d23c1a4e4d0cb9b1a36b78c87e5eee20d2aa29aae80d4759eb0c51c5dc3a95bdbbf7e14eb434419a6c88a954ac03d0c98739f4211b8732acd71c297f578b8cb64ccac45f7235ddc7f2a3f5f997525c1ed39dc550126cdf9cedaf55425489085e91b170be6205a5a395f2dd4084a3e8dbc4fd8b13252f7effae067b571cb94a1e54aba45b1b9841308db0cc75b03cfce4ddafe89ce20f2d1
+AD: 7eb6d7b7bbaaa3c202a4f0f1de2263767169eb4a64853240d48c0f8d5d31b08d5baf42977614a57aad99426cde76d242cb37d2956d8c77dc4fd62a3abf30e8ac6cd58c8ef35e67497022960138c57787818892460f3bfc16e37ff388b1edc6ce2bc53c22717edc7a03d4c78b0dbbe9121c7fd8a3e3993b87a4fe389bff13bdae3b349de0b6db561602c53f746022aeb4483c723b67825042f4af20b7dd1e6031cf54215266295c524ac8e1370424c5c5e607fb3e23e97c8eebe64656775edf616422a8b974e1acf13ab45c9a367a7dd9b2d62f48bbc05819b65eccb813ca813f57b22ee4c280dbb5a9d8d5
+CT: 0b316ab2bcf5359900fa4082d5d253b49ad94b70e3fab544f98bd111cbcef6766cf953deec08cae1f489fe12f7acc0032db8a6b0c0eee0c206ea5fb973feaebf90f690e840094db5e13fdd7157ba127368c995b426529435a1bcdd1f14ce9125b8a0e4c96b6ec09e3c36a180adf81941c002d19c19d53c2009be803b987504606b7d43bdee5e0b32ff23c466b6cccfcd0d4e88fd1332e73712b5ab725c1a383e584f34f80daff29d285ae5e43cf1d0cc7a828e75c25daced3a581a93d7a50f313b33f38dddfaa23cd5b9914797db820ee2400d52bf5fa982277fe9b5881ac42981633b3957b0e935051828
+TAG: 01973ee2e81cef22751a6a8831d752ef
+
+KEY: fe4be6054773f634356ac328591fbc6f833b0d1beeb38dd5b6feb7481b4489d4
+NONCE: 0b3f16f898a5a7d5
+IN: 76ced1ade6d1ef4069afddb32e7432d4ff2fd06685121f7b16464e7a72d365744f547d2ccf53486310e38b42d8bacaf711e54c5458d2d68c4dbcc8de31ab6732f4430e88a64565f5b287640775aaa2af1cc461d3e415bb275c6246b1b58517aa72667eae291a2982eda175d1b22c5a58e6fec2b3743d55712f201ca24ba5c0ae8c25724871b2ec2fb914a8da5a52670ab9b43a83b8568ce74db5c634061cb80530c8070c38b8f48c33ba136cb9f2158ee7eda8b65f2192fc94d1291f182f101795b7190c74b319d2d3e02a97c824d9c9471a83797e4936310b207e3a1e0bcf75f7c3e3ee48a747641cdc4377f2d55082
+AD: 834cd775cbefe4b33a3ca53a00c06a3c4a666983e4115a029f15729460daa45d1505e95172d3695625a186b28b8be173a925af04665f209267b3c5123e8be13da447ee1ae856bb0925f35aaa76e04a7bca8460f76c2024de2149f38a8cfba81694b854885d72568105571b6b213a0bc188a44cc7fe13153cbf261401b238cf12a95e23cb56f240114f16e2f1e3a514615aab4449c0c49e4d900b0e17d1a8dabb53d43dca32fa052d576b73dd9b40856b515d6d7efc2a5c17e0ebcb17bd59dc86f22ce909301a2652f134e82ef0e4519487ed12d51536024f2ae8f75d937c42d003076e5dea8de0c684cda1f34253d8fc
+CT: f8defb6fe95dfec499b909996a1f75a198a90e4d6c6464d00a357a555311c42fe92dbbc4b79c935e4f0b1a95e44fdbc1380bebabca28db4dd0d2870daaafc38ef27908c3509e945714801cc51f1a07b2430c74fa64f2a7c2f7fd1551d258c9c3be020873fc1bf19f33ab6c660911dcf2317195d0efee82d20ec26d22611f9cf86c51a64e28b3a1f344500018e0855c88dae3c07acaeaa10b60388484dce93e16e6e1a6e69e899806648a92568c8780e9f4baacd98cbb353ac2f908e775d92303cfab843f15be0e0c322a958802fb1a60fcc7631f151f4c2b8cb965d2d296acef250275a2fecc0cea803ce7c058b12dd2
+TAG: ade515091930dd7861b27f78a87ef60c
+
+KEY: a288b11ce5382ec724ce4ab2d7efa8e777e91ebd04367935e15f9dac483e9596
+NONCE: 874144dbf648b325
+IN: 4c9195280a79a509919af4947e9e07231695fd7c5088539f23936ce88770ce07d9ad3ae4a463b3a57d0634d3a77ceaadf347a334682b04be8e58b8e86fb94a1f93255132b8cdb0df86f5bea354eea4e8315fea83e3fdf6e58aa9f26e93caa08e5e2551a94bd916a51fed29ec16f66800cda6a0aa24ec308bf5fb885afba272685de27c1edcdd3668048ef07b06e90d464a8aa28664903cac45e154e8e1e39c257e1ff506b9d95cef4f300bb73b899e7828602c3c1d290b8cf55ee5fd72ecce9e6efc9293aebf674a70e2a7673e75629c12950622dff71d3ec0992e57776c788c6927d30b4e24b749191c3ce8017f0ada6276e43720
+AD: 04abe8588c8c8c39a182092e5e7840442bd1c1149da102c4ee412bd8b82baa5087ef7291b5cd077c177c42770b0023e0e462b06e7553f191bcb0315a34918dcdbffe2b99c3e011b4220cc1775debcc0db55fa60df9b52234f3d3fa9606508badc26f30b47cdb4f1c0f4708d417b6853e66c2f1f67f6200daf760ceb64ffc43db27f057ad3ee973e31d7e5d5deb050315c1c687980c0c148ee1a492d47acfcd6132334176c11258c89b19ba02e6acc55d852f87b6a2169ed34a6147caa60906ac8c0813c0f05522af7b7f0faddb4bc297405e28ecf5a0f6aac6258422d29cfe250d61402840f3c27d0ce39b3e2d5f1e520541d2965e
+CT: 0afce770a12f15d67ac104ba0640aab95922390607473cbda71321156a5559906be933fb0980da56f27e89796eaa1054f5aacf1668d9f273cc69071b9e8e22af6a205a6a88f7ad918e22f616bddbb07c78913c7e056e769e6fcf91c7600c2740212e3a176e4110cac9e361a59a773457064d2dc652dd115d04f1c3756c0e1d39f6737a16b4508663e310934c49c58058b3c7b9af7bb2334c8a163608c42499658986927cda365e2aead3ac29de16e47e954383ea566f8fb245a4e5a934c767bb3bf7e0eb8a477fd0e1f61bcb238462a0d19c5cea9293ca58ade76829413216a7882cd2846323046694f78cd8b0347792ebb75abdc1
+TAG: 973e58b1b8adb176a6f1e5c963bfdc5c
+
+KEY: 65b63ed53750c88c508c44881ae59e6fff69c66288f3c14cfec503391262cafc
+NONCE: 7f5e560a1de434ba
+IN: 845ef27b6615fb699d37971db6b597930a7ef1e6f90054791eb04ddfe7252b5f88fd60eba5af469bc09661c0987a496fa540621afeec51bebda786826800943d977039dee76235248112ff8b743f25ed5f3cb0d3307f5e118d84fdbb9c3f5531bc177fb84549c994ea4496c65e5249da987dd755d46dc1788f582410266a10f291c1474f732183a2a39afe603771bb9c423fe3e8906f2be44a0c9a7c3f0ceb09d1d0f92d942383a875c0567c7869f045e56dd1a4d6e90c58d44fe0c5760bb4fd01de55439db52b56831e5a26a47de14249453a4f8e7da3cb3282c6622916197ebfaad85dd65c61e7d2d3ba626276366746f396394c1bf75f51ce
+AD: 51a3588398808e1d6a98505c6e5601ae2a2766f1f28f8f69d1ccbcad18038c157b41525be58ae4527a073748b7a04809e52a5df0c7988417607738e63d7ead47db795a346b04e740186e73ccad79f725b58ee22dc6e30d1f0a218eda1791e2229b253d4ab2b963a43e12318c8b0785c20fca3abcf220c08745d9f9602f0ece544a05736d76b12d249699c9e3e99f3f13cf4e5dc13a04125c949a5b30d034b23cb364c8781964bc6c30e5e5ca9673d517ef5f35965d8a8cf1be017e343df97b6bee37b30638b154286d1f36d2f9a0eaa23cc484eac5a05b15d9efc537d989dbc8b3106c0dc1a56e97e6aec2eff54a82cf7ae9df2af46b4c860f83
+CT: 027b14197b4012256b133b78ddc94e72fb4d724fefa4ae329f5a5fa3fa784fe6d7e1e805e3f7a75557de64de506d38237b467fa577efb59e7cfe2356bed6655c5aa4e238dcfeb75c16549a0917268768a96acb5e20546a1fb7e3a7cff887f49f2cd7a135f72a98a779150f3207bf733e88861fd79eadbf77fa3bfe97bfe8b6a991cb3bcc2cde8287f7e89384846561934b0f3e05e0646e0e1907770df67a7594161a4d0763faa6fa844080932159999d528ee0558710058ce16f97d13ac9fd9bf5044191188bbfb598d0fafbdf790b61ce0781ecc04218a30ded45efd498cc9ba03562ed2b4a993ee98876b3ab7a9bc07829f1c4ca6ead98c06b
+TAG: e4d18a701b8308697b5e79141ed783c1
+
+KEY: 4986fd62d6cb86b2eaf219174bec681bebcdef86c8be291f27d3e5dc69e2feba
+NONCE: d08d486620ed2e84
+IN: 3a22ad5de387db4fdd5d62a1b728c23a8dddc50b1e89f54f6198b90499f9da3122ebeb38ebf5fdfe30309734f79aff01e3de1e196b35bffa33bae451f31f74b8aec03763f9e0861a34fe5db0b40c76e57c7fc582bfa19c94ee25b5e168270f379bf9f8a0a18bed05de256f8f0dd7c23ba2ff1c7f721409462f04cc611ad9bd4c3c9acf30742acfb9518a6375cbb15d65a1bc6993ea434894f93d4f6e05996ebc1bd56579296309a2c6b8fde95072168b5fd31927c4c0abaa056bcd16221d5f220be47591f43255013a262dce439817f534830ba82155347e5fe3101f8011b89365a6568214ed0661914e8cb3431d6c8f2347dfc1209a3eca4aaf0a111f47fe
+AD: 7dd3f656a03c001b45ca0680bc3ac9d68c6e96b591d3c69eb8c65e489009d845cb331c98b82e627e06d5bf01e74c573df268c2386f12628c019951d42f55991ff20d72a7b2c45f41d0be7af428c92f324aaab8df70d900301cdf09a3d93eb711c919d34a86fff9cb078322ee2e0ad48dbdf3b7884f0f2dc5c36262c59bcfd75ac6200f59c6fcd0ce10ff5005fef5df8f0432377dfbfc1db8f559e27e1aeef3380ea3864867d36a25a18654779a751586cad3b8a46b90864ee697b08605673b8d2123433c020a21c4db243dde2420c12fd4d54a2704a0c8c376454a1b5e80fd6db89aabd56d9b421f29649e474824dfa56cb5c673c504d10be52b53751709fe
+CT: c40180afd53001663ff4834110f56e6b0f178cd3c0e7f7de5d0089ee41d8403ffb98e84922706544a344d7e2625b12cf66b9c966f9f57d7b94e3e4b34e6f0aaed1763ce012782e2f5e1682e6c343fc7961fedddd0919d0b910e9923c17e36406979b256b85aec24ee352f03b48c1302eab419c83dccc5372cc059e9de596224fa70098eb32fc9579e97917b923914fa2efc30ab29b457bf14e45583b3771486bdc0876f3ea6e1a646746c4f8c5cb2641a1557c8473e6ea67d4811a67485ae9a678ff3a2408ca845c3b51957e189eef47dfc1d46bde4b9d754d7df13f828ddadb06e4ebddb5f0dafbdb28de4c5e6078926f20cdf9e97ecd58e309e640f74f06
+TAG: fd5e29332832a14a31a9ce2ca8568498
+
+KEY: 7d28a60810e43d3dfa32e97c07957ec069fc80cc6a50061830aa29b3aa777dfc
+NONCE: 47738ac8f10f2c3a
+IN: b50278ae0f0fa2f918bb9a5ed3a0797c328e452974d33cbf26a1e213aa20c03d0d89490869754abf84dbbe231d7bccdced77d53fd4527356d8e02b681fc89a535ae87308bf7fbc26197a5ea85bdb3aa033b8da5cd197ea6d72f96f63b03f4ecc7adedf399a5043776cdb32c08f30b77f34df85f8adb8e02649a04b020b03e17d445ca63e4ed73ae432c481392e031eba2f9d2f7f981d1e50917822bd6ff71c239d33444ada3523a59dfbce5457eadec1ab926c9e6c5299c7521e3f204b96901a712504fcc782e8cea80ba12a7f7e71cec3d0871899b6ca059061da037715f7d13fed01c9cade1e687b4fbb1f4ac4b040db3b43800f112fb900e4f772d61b921cbce4da6f
+AD: 324292813b7df15bc070cc5d8a4bf74ead036430be63abc43304cf653959a24a91c7de5a671c50fa8a87e21bb82b069999aadfb6895d8bda4c3083d17b8ca55b9ab1511ed8c4b39d8c28c11a22ef90c08a983e3fe2d988df9e02b16a20b24f39ddb28429625f511db08298c4dc321f6c268fc836a6191df6232f51c463a397a8d8b33374abe94e62c0f5c322387e1fc4a1c1980a04a1a3c2c31b32f183a11c3268c6dca521149dc16af120a78be6627210e8ddbc44472bc24d66ce3681c7579b3d9a425212a704a4f5105cb80f0d18ee860953d10b59c114826779bbc368d7a0eece9f223e47cd8e5fd453607d101d9d9c2bd9a658d6520b87d7b4263f6d845a524a36e4
+CT: 2c217e969c04740a1acfa30117eb5b32dc573df3354f4cc3bf8f696ff905f1e640f3b2c250473b376622e0c9bda13b94640521be1ef0fc660b4c10dbe2bfc093030753e04f6aaecf813b43b61f960455974b8bb8a9b461d1e8fd3802315e863c00448f24dd38deb90e135493274eb14ccbde15c50dcad734ed815a806be6622492a84cd062e3ba567b909a205a1d0d2bedd40169697d261c7b6c2e0b1f069853fd470e8f364a142c386c439a6dbe192ded5a3d0fbf73799f588c59e58c60249d980ddcf0d9693631cd9b3f972509c3a77123d38d9e267ecad06e1208e3f1c0a69fbca7c3bb1a48fda19493d0f8f48398820057b94120f3ef97d87e9e8a1b301a2534c68f
+TAG: 1fdd2dcd935f55822bf7231a516ca841
+
+KEY: a76e9b916f5a67b78a5949651c8c3a9741a1bc3c41cdf85fd2c8f3e9a0616098
+NONCE: 0808da8292dc14e0
+IN: 9c149eeb09345c3c22462b03e49eb4dba6bc98b269b1086d752bcd8eea53b8977b238a04a994baf915591686baab90b79a3bf7d9adb2c6c2e31acd3e72f0813fb745aa5fb2e3da408f78001c9c09bd26a1a2646011b6120aaa2bbacc4a16c39fb5257b9b2ea2ad8bf70bcc9855cf11841116c2767310cf3cd49d1aa44cd505f079761e064d5bc7cea4a7173b086882a77d3fc179efc86fc4db8a373491d2ed81eabc63c950e832db17d09f474d4ec46bde47830caf26fabaa0372b81fccc449c0e19ccd630caf693a7b43bb1c408a54e03f50c44280a05ad89fb6e8f01d8ac278edf556e5d86ceb4b614fb2ef133819c6e1ff6abb86c54a135256204b5cd400b93624d3932e7c2b046
+AD: 6aeb7031e4a2e23eea93f05fdc562aa2bf43b8998bea7344377aaddc60fbdb7bcb1491d379ed0cb613ee757cfb66490db61bb431d2fad34b38ddd55bc5b22aa6c4773b9992f34b878c5663f6e8cdb5f80a17f4d312bf342492e48d1ce4c6d754076a634fece61500acf8168d47381af4faf980c6cac2bfd5da8c09b6edb0f543bf0fe02643e38d73fa37d8ae87fb66193f22e57faf4393c007d48c8631a685d520578f8f89db684fb371ea02f3a58b1e2168f0216321139472e0d03b6d90ba8aab65402e1c1ac4f9172a60e27e3d997b9b05e2f672120d6c87bcafa6d4c9b4cf8ba8a82932d92840368fc53dc5b48526103dcab5f1531038aabe89171327ac559b98a3cf4ea70bf051
+CT: 9c3faab9261a63cea9477b3269007283995b06ba77ef83d9e693f7e4ee9855550eef94855be39a7a435b6a3584b202973777c7b2482376ba47b49311947a64983b60236756ee4455d4cfada8c36af8eb06b06ba2f6b79ffb1185c89f2b2a831cfaa3855fc1841d8910908be5078352011168a67d36372d851a3217cabf593ea462dcd325cf9a4f67e85418fd5c924e9b92ab026cbee4e7ab1067066cb5949dfc699a68fe539e1abb13cec33904e5207e6963d24f5a0b770613b8b00014e791bfff88f9c25ca126127a2f8d1d1e9794efd28dce98b53e228073faae8d5047530d502184fc341321c3f55fcbf41187fc31262c325b97f519959b6a29b36c71f76f60196bb1457b77c8bb
+TAG: b45df119043d29008fcef36a169ef886
+
+KEY: 98cd2477a7a072c69f375b88d09ed9d7b9c3df3f87e36ce621726f76e3b41a1d
+NONCE: 77d185aaf715aa48
+IN: 42b31eefdacab0f03ef6060156000c8195adb0976cabbe1a42bfcc09f85659c60b98638401f2d2e2facfb9a97a62926bb0cecaf3af0180a01bfb6e576babf7fc43331937a92abd30cddfa3e450f895e9dd914dea3fafd759c136d685310ebce28ac0613ccdbf30115946c9634b67510b77d0e37f07714b2ddac9d7095b8d4bd887c132c4a9127eb01c8dedb4c39c87b98a741316656f9a8d5a5b0c0ac84789aa2347a5f99ca5ad55cd1bcf98f703eb4b00badb8a8555f38b3b368db8ba7ceea94e8b219f51edce75d84166b5602156ed5962a93a51db73c59d87e906179d7a74a2a2a69d8ad99f323225c87e475d3f771b4a203a2e2b03b458401044649fa6536dfab24d7037807dcbf6518e6578
+AD: f5bb1496052a4361dddf72a288e36953a3d815d6876c013f1d6ba839e127f721b052b1f7d8ca20c7dc0386a7d459ebd7eb9fc8cb08941e6ca9ddb980f3115f65bc1928a414d441ae71dcb879d5bfe0cde0562bc37f8fde0d5291ad405c92fcbb860c43b55ac0fe663b54b3d0616aca13a5c82b7b5d34125a05c2acb5530141030e6f2aa0c8322b2c8fa307e7518918e550e9f48921c6168f094d8758e16b9f815fd0458095c4143f0922adb1840d0e685636825a9c90ee90ee537f4b8dceecbc4287c82dc9a00d7e51671e37ea284ee3ca501b1b2596459d3f592f70186f41125739e342c9f6be9241973b1414dfe5fb8cba1af82e679278cfcf95420df0c5364af4d7e72ad57d5c871fcbc35462
+CT: 7a3bf3e3ad5ae3ab71fb1f7121c3d8fb511099484b50af7ca128ee0337ed4b828dc4cde0b88dc1e8089101fa82c9beb3eb48fdcf0f5b16da441f5a3fce9a590022af95a94aed6a3e71e505f60f303c78c356f274ea85a55354078530664ecda32c80e77dc20974b3b38f4825b8fbee8c3970769a2f42c5181608a8d7d76ef4d093961b665ee42b9708fcafe2c82d3a307173e2a25ad2528c3bf83352b9265e45b70722d7cf8c9b80826d21335234ee3db69d0d37871c83222365900c96c17a7e9f5742d0bfe383be24d0d44590d4b0f29f7abe0c65daaffb968b3f2657b1eb300534eacb52ec7a6b6f9f57a50a91b1799f491361cf613c934b7f520dc4eeeb40ffc45e10be0a95e76f366d4eac14
+TAG: f613b65226afb64c614fe60d9c71ed74
+
+KEY: 2f0f4631ab1c1bcf8f3ad0559c818d50e0af7d8cd63faa357f2069f30881d9cb
+NONCE: 7d0ced2fdb1c9173
+IN: 6516ba1d29357144eebfa486d21decf223da3aa76ec29bbfcbe7f1eeaf4a847710e5080177f7e5a7c8b4752c219b1cc70aef4db861ba67d0fa6222d9f4a1dc756a0ba44e62906f9374a960c16198866d867854d88f528a60e212eb91645787e75685b2e215c0a41990abc344a77236ec0186ba63a664592938cc5a8ac1d3eb99c95ce00e19fbe249263083d85b052d48bfdffc01585dc57bb2a2c6c4a819604c1ec0548c6f0f78dc05e4418b36277dc07233c7532f9c289d6aed0cc6bc7df4fd0a536c497b982e2dad2c30d2db1c6545a845c5dfa83a4ac49ef06fc9c919079d3e299e31b5c3be370814ae5022ae469d3ee55246a41bd0dc4e64351cc38c3c09af0a1aee3b388a6892deff0df3f93cd92d722b
+AD: 1ccfa1ececc8de1e200d0ecc19dcf67b7c96bea3a282c2bccba61035db5c14776387b8b8f58e5757deb0129d4e5e315f64df354a5985d2e47ebbbeafe0c914f7cf1d63dd0311ace19e69a8b6ff0ab25cc8df0408d22132205e89e5eb679268d82b2913e64e3f885bbf4a6d379b760b94590e3140dd7275ab4713cb56d0b716e2718f11316640cb394802862d39e77a46d0c065af3caf7dec14e887039d8aa8c3d3a8ac1ee06026f49d00b2f59d971b54735e95a51f199389a93a4fc24ebaba1f7a2eef7412f61febf79084fbf481afc6fb6b204084e5ef5df71f30506459dea074f11fc055cd2a8c0fc922c4811a849984352a56a15659b7d07a4cc90b88623638ea00c4c8bc13884df2237b359f2877aa41d6
+CT: e580093789ba17ffb46672dc326f09278aca08598d3e5458eaa53e6ed45d5c71a396e35b5ea3fe7b7c0496a734d24f1c75420694be2ff095d5172fd3407794e4b99fd7c374fbe8d1564a048614d3f355bfb5866de1a53e1a51f9f5e8312253cfd82f36efaa1898c850ca0d975ad1e8b0d9597a5a9e6516fe2a3c92efb7495557a8afc3da15b0d3e2ba58f612519836946cf2d15b898320d16a026c8c00a1be2e35f0ebe68f28d91c6c45d24c3f3c157cb132fa659b7794df883d90741fa2d2afcc4f27858e13ecd41b154a35d24947ae7361170060c107d8ecacb393ea67104b60457278a392fdf1794bab97d3b02b71a4eb015eaa38a4b4c944c2bc7cd5e329da4a1ab2937a6af81a6caa5fce752331fdefd4
+TAG: 0fd7419c54bc84265ed310a3411a3f2e
+
+KEY: a48b9b6df475e566aba7671fbd76772cb0eff0b12499967978ce3e25fac92feb
+NONCE: 2ccbf0d6c40cb302
+IN: 09da1cacd001dce4f7573a065a4406fe0da04ab367a2d87780a2762e168957a88d3fa78f0a4b6978d449026e5a801d32884b6e14fdaaaf864214f928ebc03dead081fee96683ebb032362d5088c4c2a3b1e242f055f2604919f4dd551db777a258cf9da6d95a2bde249247812b9efc7985cf08707620808524d6dd3079b0b63bf0f71ea5de834ccb8b7c6a97125fd6ca49148e866d3134bbf1d8a6b714e9a80fe549c8bfefe342f41be2ba2300e0028f78cefab65274632dfdbe70bf7d655ec4036df561f2d4fc4d56a482bbe2f9f2ae279b3aa216b39afee75e53602de319484db89a51e844f38c361634e474f8f1f01c340f3f3594860d671346449c6d08ee38de22d246309bc7e4a252a29c86aa6d94b5b4fa58904c70
+AD: 1c2503d5aa1aad193f0da12874074ea0432bb76a61cd43a3017061514da0759846a0f3ae3a49fdb0b6d29f713de665beacb6568f2694112ca380d13f3c1698316866a7a7f87f1d7503a92176ab84fc08977b46ba664508a858e7525753c45511b3d2f407d5e993c6ede77f13d12975707e5195704970a89f71fc30828049f92f944f3aa93d6a5297e678e08952919beb7eac5919df1919cab3c3da6aa696a1eeab6371f310f7e81143e7d240b0213ae554524b52000306160dd4877bf13ba0f13bbe867da7c7d707f31335eef4cd942938ac890a0829ec66bd30ae01a2188a6e5ea0f17cd7dc875e17f03c0ab5dd18e36db8a1fc1f72859ee046b62368f168b3bea2234e0432c07b7d8e1b9277f21e692c513b9e816e6860
+CT: 7d35cfe4be56bd6e0e09dedcd01735b915bc1891a4d1f6a541abc4bcd0ebe89dcb8e365e5813742e8ec65777b6159422fada747da99394252baf8a046fc1b60ad79755f545f4448627b7acaf403000894f5641e78d3f946dfca29ec617f0660dcd6e8d8827e67e1022a245c595d86e60fbd176bf721b171bbe5ecaf4ae671b9f3dd3920146e6ad431bd8fc431820e19454b6ca209723d80fdbee187fca9c937c979206ae97be55f6ba7366a5608770a11d537396485eb0a66586385f4d4cf3905d1fc90831c3e136d5d513fa22be285193142994a3ed477145bacdcbdd791e8b3b88b0d4f1d18b27382550a818c4fd8884bf36f677c6c3ff5677406e510911e696af75e5b3f859bef699bdd16e6215fdb98d874025eada50
+TAG: 2aabff35611b3e0013f6ae0df130799b
+
+KEY: 923d4b086b9e43b986f7b65e4cea6113a3d8aabefa89323c5e4d5b6f158bb7e0
+NONCE: a0f73297b87f5deb
+IN: 21435e8d5c8edf0684f58c2cba4070c10b4801adf46b6c4d322eb3990a38a9ad338ad704b9df6597f3e68d66cd5b56290c8466db2231e56d6bcb9c44e1bd081f42ca2a894dad369df2bd0d2c63d6c881732d6ea22bb22b5bc9a62eaffa1b094d0845f6b966d2cb095e7b3b8bcbc15e707449d35c8df4aea30c3b7243e977fffd59c80f1c5c9af4bb5a54b9c786fbbe8d21b2b906a87a786caed841a34a3e0cc0ac3209d83c58afba19edd63622dd261532d2cfb0b49d527d8eaa0887a087f5129d897f665264b229f860363d71a88b7d49c8dc6360182b357b0662391bb41337f46010ac32b9fada2d60a2efcb99365d3b27b7ac396900d1c821d0df8b86cc9cc1f2673259a33efea610bf8e1d00d7e9db2afea21da8f58c55f799999d
+AD: c853a8b39c0dc597d562f123cd221e4104b65423a062a4f4ba890ba344feb84290f61817e23330c365f58c3583ce08360d3c1171982ead5496d525ac878f23a57480a6ee39d4e65afd6268245bb982a2545fa1195427cdbbcd404cdad5198f55cce2a5a028fae435f71b15921d066e8d43766c32b2f2c3f57c0674e129607dcd3703eca529414adaee79d81fed432153cceb6f3fc53404810d8ec878f7d94be5d379d0e0e1aa9bc404b4b5d396038a9d76a5ce53c9f3759b8e50fb331858ca58cee81bfc3ee58baef5d19c402a3dc8b36370ec1ace5a4aa2527fb94b4f933a4ab8ccaaf6a5af5a779eae5667c2a24ab027e781c8d4f30c377aa5885a2fdaf6507d18cd824a847c35368b4ea984d2c3c3824a5b8ba3042e1852504a21a3
+CT: f2e21052eebbb86a4f5e803360855d8632aa727dca6f5e79dd74d7aff106e442001928d113005b030f8446f8eff2ee951db663978abe43090dd5ad2c51ba97a0ecf988c607d95e486d02524f690fa3c28d5c48c1f75c1f555e7b43fe7e46f2ca2b9fdb408ec4ba18b6cdde2af673183cb7b1a3c23ae77eddd4cac75e1ea14743fc571f8d31ce2e96787524cd48aadaa474181c096a032184574ddc25a6e0ac8441c212bc36298708e33c963ae931e6c6241d1affeef7b6ef759495df44b6ab647447693cf703569e69aa72f1def9a342b8978c1edea9703a421ca75b92cac4de14b88c693200022b8a2ed22b1c4678b99f4d695e080dd1196d7168e14f0d0f8ff880d742e97b9f6d00af1f7118e10b77c5ef3ea6c52f84a20fd6ea46dc
+TAG: fa8ee13400fb3f63b899df582f2fec45
+
+KEY: df73adab2768559ea983cce85453fe81d79be3b3c57f202b31b94d6635cf2e4b
+NONCE: e7a87e6bf6b5a354
+IN: 0032a37abf661faa18c587fd2aa88885c061deeba81105dd221969bed5d59c7204b09b1a8c4c8de3b9f748c7fc70626ebeaca060233a57b102221b1bf0f3d9fdaaad3d2b1439c24d08f9c67f49f3c47128f92ee530abf4c4f4573bc60ae4b38109f55bca3ca9e1ba9f9fd6e34ba0d174892977a53356e1f5c88c614fe3ff3b3dd0818e7a2285412e3b37444bbe8a80942efcfd03958809a6966cda9430b2f0c9e552f4bced6e19eb3e85fc5758bd7b588297ccbed37ed94c3adc8c08ea8b058462aac9d57a939ec711bc4ecfec944d2b653b7cfc7b02a65d7057c9fdadd51b9da8cc4a3c68dae9da8b9c5319c1a2baa3d6c891c5ac4a39461484b5a01abc64df447ada24c04a4363e605eaccf339a9aa515e724206206da6d22bbd2f52e64cd7c895
+AD: f833e5ab4f8bc89167f80f576b1d6b22cdd0e30721f5f735799746cf645b6eff531d4c7b03584f3dfcb73cbd35ac42736216dc7f0de098a4f42c61ceb4b227ee288e47d697a0a76afc762f084e8fdbf9351c28340c324771c109a469341ab10ca10483ed2af5e878d7d3dc2bced2f72da3d1a25852b103ee9878e8158eb4309c1ce528f3a178ace153b6d3ae0af0d577cb3cb1540489e80427f792217ad8a09b84f027fca7ceb651b4264e98e94b4cb8a37b133390897233e8ba9103628d05b9609e8552c4a4b11e3f2fa8d56af36957390e88cba44656be3edace798cf8cdf7771bac338a256bc3cba6df97728f222f423ca7c6d149c9372d66163a98f79a234b00d4b75fb2ec860dcc2d1998105e4b9c01d68f079f3e0aa21cc534047fc7b858f8
+CT: b842eadfdf431c135bd6581d3eccae54e2267d8890036aa33dfe2d2d9715c44625441210a3a0d666d708d30588fe851ec36e10d8fa3584ed77b095149494b7c54379d62c8935e1d2b9a8f47e4759ad0b3437fdf2cc2fb6c5ea25ad10e0bdc9dc5b0517fc237eb783cc461c46665e2b1d1a5b8008dbf409ea2a63fea0276de23a32c99d92a498807a0f95e208fc6262321a78aafaf0cc3f833fff37bd4efa66f6023a25cdc6702cee3912799563d908a5183c9956a06aa71085d855dc7c809ed6e2889592b361ab3ab39060f8e419152187a794a19c2a1128882201900ea2cd597860674bf78d9720643df8701676718fd201baed4935a88e50558daf86edd08a9ab227ac7afae55c974b68de8dacad4a4d79b13ed6dfe74017a4cb9148e033436fb6
+TAG: 184095b7a8190abec08bb72d19eeb103
+
+KEY: 55a4be2448b464c2ea52a2f2664ed6aba865c14ea1fea77f4689331fd105c8d4
+NONCE: db37c0a405b4626d
+IN: d266e66272e5d3462081b004cb42429c8b9741e9f678153754d726f6f9aa513464763c5e793b482fe512fece97585f1426120d4cefb3d0a8cc0a8db4bde93fc72c78f44d4fecca14650c660d3e285b327e7cdd813063e7e867b8a2d059a41bab70432b7f857199894da90dca3fe5272bae1ec694a1a07b60b05df275784d4975637e4673109f3ba846dfd1a048b202ed8e89973be608b91ee4743b1e759900f1443038951fe6189e806638985f3c16338c3c60695df58e621154d79bb973859c4558e9dca90470f77c73f004443ad5db0717abbe43266f90e57397b83ac34d1fef2e897e2483d5bcdcb627abd64b0d1aef525835f25e76d6e9158232cdde6dce970b59f58de8a98e653be32fb58edabbcefa5065d73afdf1c9c4fbf50c1022bd22bfcb98e4b422
+AD: fd6a3fdd879f8880843eac20ae01c1b9dc3487d270a806572088ef2ddc1f1e0de495e71d4813bf5c501ad31e5d791c4b5b3a0a71b63fdddcc8de4b056064ef467989ecccc5d0160d403bf3a025d4892b3b1de3e062bc3581d4410f273338311eb4637529e4a680a6e4a5e26e308630a5b6d49ead6d543f8f2bf9050aa94ce091318721e1d8b96e279f34b9759b65037bec4bf6ccda6929705aeeeebe49e327e4d7a916620c9faf3765120658af34c53fbb97ec07657b3f088fcbdc401aa7949ddeda34d885018c2c23f4f0bb8218bf0d4fc90643658b4d8834f4a8c08e590c2a790995baa9e77627c342d283e454f84fcc05be15e9627a2d9be340c9d72f222bbdfc47905f56616cd9f936d49e4732f319f020513340fb8b22828db251b102b6b137c9533936d6
+CT: bd11ed07b7b4b30eeaf25d6a41a549cca0a5aee71f990ac566a37265d7af2ce3c03703427ee0b2755c2bdfc29f9d826aec6ee4ad28af48079ac23db16580b97424f3a4e35cc23625d39f95699d9ff5143e9a2bc26fcfee4f125f5aa2d968ccfc2faaf9db3c28850f6757f735cbc50c94c498bcde4f23bffafa8dd5f70d1a011e35eb26e905d4e68848fedebeb197be595c085ba33f11ba8398258445051751888e9bba111f800f31b37c447074ca6dce6d54b4dfad6cee5138643d4f6ac045e8047248924e88ea4294c7878bc22c9b41924ce301f22693c33733107bf1ba85e34806c5e4366ea66fc52a5f89dd9bf213239158b3d4d2600dde696c61d76c398b9bf10de9118e812e891c8f3355c0ecc6405f79bc32a58905e37888a1d8395fbedc3ac54eca569f
+TAG: f7d3b58a34a86e99267e5db206f17bbe
+
+KEY: 3304e4917ad7777b86c26a636292c9cc4c10d32003c49e07209eb0ef8505031a
+NONCE: 4d572d116fbd8c4d
+IN: 2f242c2ba33790ecef862b0e077ff8b15eb9d10cf2ff621ed65902494431dcbd
+AD: e699bbf250cdd93d229d0740e433897e2d19132e2b722df8b69bb6a7c2cf3b93
+CT: fb81e30436e437c7f686f86b1b65c73549a9d09db810d320785c3634934150b3
+TAG: 8b
+
+KEY: ed6057bb163f1609ff28b938122f495e3d5ae4ec3dbd7456c9b5c82e28e952dc
+NONCE: e6ff6852f3a3afde
+IN: 3c50edc967eb0b3b2355f6400e0a036e796c8b7d72c5e583a86e820d53e76c43
+AD: 2441db55148e14e9e241d68296eb60d529408f0534143089671bce546db96d88
+CT: 6ecabccee31519374d4bed11296e7483d1cb759bea3f4446a96bda8b4ca6d7ac
+TAG: 355f
+
+KEY: 73568183c1f9725af30e0f2067606ce802c3fe3ab5cff8d02b3db8c35176ee0d
+NONCE: 0bc9e19321b3d00a
+IN: ec2590af5ccd226a32ff750c1b029c11e3dd76c469a5579da9418e4c3fdc0d41
+AD: df30160ae0cbf2cf8992221bd62dffe691dd602afa784ca691479e957af3acf1
+CT: 9e8d8ac30626f8b831448d6976933aa5bb8c6dbc794e1f4b7eeb0e4a59342c07
+TAG: 9fd36a
+
+KEY: 273bcb3f8c067da4ec3418799ad40e7e4aee74ad7e629499d646df4a7e585025
+NONCE: f60be3eb894b4030
+IN: 697498ba964d5ef401da4d94844fab1efc635e7157d0831a325bb5a4cf1fbd34
+AD: 9129715deab14f02c76ba8172571b1fa9d50365cd795bfccdfc28e7e7b4f66fc
+CT: bd4cd5af83be1c13933302675d9fcaf1c4cacdf269f6ff441d1ea2211c54e7ed
+TAG: 7ab12a37
+
+KEY: ad39610c2e6a6d0961207390e076e972c2edadca885c92965fa648b2ce34fdbf
+NONCE: a90db690bba83b78
+IN: 31c49e3cd3d80a82e6b90316dfb94b38b8a23042519bf40c8181fec873c99002
+AD: ddbd7d821d18d44c66295abf245b227b5cf4366811b7b34c07679600abdbfc29
+CT: 94628fc303a0546edd51e966f2bd87968f37800c607d5e5a91f727fc1fec406f
+TAG: c22ec4e4c8
+
+KEY: 29984954060ba06ece1bcfc0e50195f4632c6df48da1e02ae6c14f7065668971
+NONCE: cce53a25aeeaf747
+IN: b9b87433a9894f3c9ca8212623d62369a565a2edcddd276e07d611eda3597426
+AD: 19fa9aa59697559d8b46d9cd49c3b763c0b73b26b9e334a3eeac2c86fdbaca8d
+CT: b68c83397770c36f073710882fa86d43b0e54e8efef0ff75075604d0d7ec4e1b
+TAG: 40d4ab752f3d
+
+KEY: 5c3b838b84100b2a818c0842e9fe19a7c50cf5f3ea73364c816ef588e500ff3f
+NONCE: fdf6b0229e4bcc2a
+IN: 2ba91904c143be99297b39f52856904af41705c176c8c6554b6bc89bddffbcc1
+AD: 3539d9dd821f004f4ced1637071f4be6abd7fe98f017f0a8ce3f49dc8d496f46
+CT: ff9d6d924e737a1df8c2bd3047e40ab401f903aa0e5b51acb991bac38ac2cc4d
+TAG: 1bcaa415a6a3c7
+
+KEY: 6d65e627cab6d5eb1a088b25bd6c3a8a004a7a19cccae909d62fed3559c812f7
+NONCE: 7ff00a8798b792de
+IN: 6848ee4ac820291a2e1dc3baad97f1ad8b7160dfeaa1bc83b2700ae42b5a366b
+AD: d2437b1306bf0ea211449fac863ca0d1074d84caee9009c5d54b9e9bdc8de6b1
+CT: 2da0abe2a71e1c0b1ab309c160a8cebe45c6e16170aa5561806484ba2b5b9a9a
+TAG: 566003e1f78d2a90
+
+KEY: 63401046a96efbc8c6483a2c396b2a593d3fae0db565525b85999fae13a46b6a
+NONCE: 051393d775e635ee
+IN: 2b4b6477580382aae782f8b5772c0948a444d8d95caacd85c0856c7e4393fe09
+AD: 3d84d2e70e9c062d1f511eb685a9a90c8d5fa50eadf8455c7148666b3e7155e0
+CT: 880c1123e54fd8ffb3c293720dd174913572e619ef46504cdaa64fc451b0ec1c
+TAG: 339274339c88d50ac0
+
+KEY: 291fccfce0782f1787d62d4b9293d2ada4c04d37a8288ba9ba9aae0d31aad204
+NONCE: 7450bbd62e4aba7b
+IN: adc251e793181e5d4c4bd983b853eb13f2096ccb340996b6eca4cd2157efcec7
+AD: 4c598f6deedc8c1d97da33654763495cca3517430eec4edb006b10c95e031ae6
+CT: 28bda22e4922cd8ff6739cd8a6bdafce036d9c61a145a65ca1b86f6d4d3206a1
+TAG: d98fd43fe7ac74d4b016
+
+KEY: fa3a9674d4a0eb36b2f7547c956443d09e6b4e4acfc9deda838eb7ebdb999a8d
+NONCE: 0a2572592c3bbbf6
+IN: ae27f70fda9f5a5be0f704a27f0b8a9c04ce83d3c2e0d7ec152da25f473b0c8a
+AD: 6ee8705a9a3655d198497ad410da02005872ecbe397824851b80f4050bfdd311
+CT: f356cbd88e4e2aff62d91e3f914032085388955bbba995fde013758b8702e38f
+TAG: 00324c76fecd3f50e1e3b8
+
+KEY: 471ec87b992b104d369748d96856b5f66149cb45ca05c17f29d24eb9526fe6db
+NONCE: 23a2df9ed0b47439
+IN: 2b9452bca0f48e5519ec3d0736597608df6ad9ce799eba913cff71573d79c092
+AD: a56722ddfaee5f1b64398c225ee8bcdcfde5c2127101c363bfac52bc409c1082
+CT: 7bbc464aac5dd29c25262fe0b116c176d827c2cc8dd63428393b0a9110f3c194
+TAG: 2e87f4a6663a62e47c7e197f
+
+KEY: a29d1cfd4ccdc18803fbca9500f4bb29ce99cfcbf8acc41b8208dae4b7ee5d64
+NONCE: 634f99e88e237ef0
+IN: 09ee5982c5743f396d0c29c13e3fbb8fb89f61705da05466291e010effd51a5c
+AD: 564dddfcc3227b413244f1105b610f192decf15c4cfa067f4d7fcd6bd7af11b8
+CT: 32916b67a6f32733623344c98c49773f3e721dc2ded105fb245799525bc9c84c
+TAG: ff463c07e7ef831321d3fd775f
+
+KEY: 08ba23616d911188f91da063278bef1237dcbf17f52585e53c2c4b6cf3ac9f0d
+NONCE: 989ae593eddd3874
+IN: 749152c9478944c8271c0c11e07bc1c569eec01493e65b3b94842a1bf5d721f8
+AD: a12d1a45b7c9b91ab08751a70b753714052ad24e0b2619fe8c3be303c65f2dbc
+CT: 34c40538ee1d22ddf8ac290dd7d423dfc622b5cf8f3412a5343e277822aea713
+TAG: 014c7c678e0949e88071d1fe3531
+
+KEY: c2ba8bed8634156afc6bfe3754c91744d4131de39d059f3a866399f916553b5c
+NONCE: 80fbf7b433a4cd9c
+IN: 419be6623e7964f9f26068dd969e4a139617e67c5ffb269b3013c433fe771c77
+AD: 3937592db78a61ff469691b6800792019bc2b3d42512f23c1b1a66a8274495cb
+CT: 9d5bd1c7e766763eb00684c038043111d8c6390a8d6e17a15ef97c02ab16f09c
+TAG: a64d0eeb4a01481ec0cee8c1c357e3
diff --git a/crypto/cipher/cipher.h b/crypto/cipher/cipher.h
index e98a632..5ce1d63 100644
--- a/crypto/cipher/cipher.h
+++ b/crypto/cipher/cipher.h
@@ -434,6 +434,9 @@
 #define CIPHER_F_aead_aes_gcm_seal 110
 #define CIPHER_F_aead_aes_gcm_open 111
 #define CIPHER_F_aead_aes_gcm_init 112
+#define CIPHER_F_aead_chacha20_poly1305_init 113
+#define CIPHER_F_aead_chacha20_poly1305_open 114
+#define CIPHER_F_aead_chacha20_poly1305_seal 115
 #define CIPHER_R_WRAP_MODE_NOT_ALLOWED 100
 #define CIPHER_R_AES_KEY_SETUP_FAILED 101
 #define CIPHER_R_INPUT_NOT_INITIALIZED 102
@@ -450,5 +453,6 @@
 #define CIPHER_R_OUTPUT_ALIASES_INPUT 113
 #define CIPHER_R_UNSUPPORTED_KEY_SIZE 114
 #define CIPHER_R_TOO_LARGE 115
+#define CIPHER_R_IV_TOO_LARGE 116
 
 #endif  /* OPENSSL_HEADER_CIPHER_H */
diff --git a/crypto/cipher/cipher_error.c b/crypto/cipher/cipher_error.c
index 0736404..ec53f16 100644
--- a/crypto/cipher/cipher_error.c
+++ b/crypto/cipher/cipher_error.c
@@ -28,6 +28,9 @@
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_init, 0), "aead_aes_gcm_init"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_open, 0), "aead_aes_gcm_open"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_seal, 0), "aead_aes_gcm_seal"},
+  {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_init, 0), "aead_chacha20_poly1305_init"},
+  {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_open, 0), "aead_chacha20_poly1305_open"},
+  {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_seal, 0), "aead_chacha20_poly1305_seal"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aes_init_key, 0), "aes_init_key"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aesni_init_key, 0), "aesni_init_key"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_AES_KEY_SETUP_FAILED), "AES_KEY_SETUP_FAILED"},
@@ -39,6 +42,7 @@
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH), "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INITIALIZATION_ERROR), "INITIALIZATION_ERROR"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INPUT_NOT_INITIALIZED), "INPUT_NOT_INITIALIZED"},
+  {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_IV_TOO_LARGE), "IV_TOO_LARGE"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_NO_CIPHER_SET), "NO_CIPHER_SET"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_OUTPUT_ALIASES_INPUT), "OUTPUT_ALIASES_INPUT"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_TAG_TOO_LARGE), "TAG_TOO_LARGE"},
diff --git a/crypto/cipher/e_chacha20poly1305.c b/crypto/cipher/e_chacha20poly1305.c
new file mode 100644
index 0000000..8b6d378
--- /dev/null
+++ b/crypto/cipher/e_chacha20poly1305.c
@@ -0,0 +1,220 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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/aead.h>
+
+#include <openssl/chacha.h>
+#include <openssl/cipher.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/poly1305.h>
+
+#include "internal.h"
+
+
+#define POLY1305_TAG_LEN 16
+#define CHACHA20_NONCE_LEN 8
+
+struct aead_chacha20_poly1305_ctx {
+  unsigned char key[32];
+  unsigned char tag_len;
+};
+
+static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
+                                       size_t key_len, size_t tag_len) {
+  struct aead_chacha20_poly1305_ctx *c20_ctx;
+
+  if (tag_len == 0) {
+    tag_len = POLY1305_TAG_LEN;
+  }
+
+  if (tag_len > POLY1305_TAG_LEN) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_init, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  if (key_len != sizeof(c20_ctx->key)) {
+    return 0; /* internal error - EVP_AEAD_CTX_init should catch this. */
+  }
+
+  c20_ctx = OPENSSL_malloc(sizeof(struct aead_chacha20_poly1305_ctx));
+  if (c20_ctx == NULL) {
+    return 0;
+  }
+
+  memcpy(c20_ctx->key, key, key_len);
+  c20_ctx->tag_len = tag_len;
+  ctx->aead_state = c20_ctx;
+
+  return 1;
+}
+
+static void aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) {
+  struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+  OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key));
+  OPENSSL_free(c20_ctx);
+}
+
+static void poly1305_update_with_length(poly1305_state *poly1305,
+                                        const uint8_t *data, size_t data_len) {
+  size_t j = data_len;
+  uint8_t length_bytes[8];
+  unsigned i;
+
+  for (i = 0; i < sizeof(length_bytes); i++) {
+    length_bytes[i] = j;
+    j >>= 8;
+  }
+
+  CRYPTO_poly1305_update(poly1305, data, data_len);
+  CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
+}
+
+#if __arm__
+#define ALIGNED __attribute__((aligned(16)))
+#else
+#define ALIGNED
+#endif
+
+static int aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
+                                       size_t *out_len, size_t max_out_len,
+                                       const uint8_t *nonce, size_t nonce_len,
+                                       const uint8_t *in, size_t in_len,
+                                       const uint8_t *ad, size_t ad_len) {
+  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+  uint8_t poly1305_key[32] ALIGNED;
+  poly1305_state poly1305;
+  const uint64_t in_len_64 = in_len;
+
+  /* The underlying ChaCha implementation may not overflow the block
+   * counter into the second counter word. Therefore we disallow
+   * individual operations that work on more than 256GB at a time.
+   * |in_len_64| is needed because, on 32-bit platforms, size_t is only
+   * 32-bits and this produces a warning because it's always false.
+   * Casting to uint64_t inside the conditional is not sufficient to stop
+   * the warning. */
+  if (in_len_64 >= (1ull << 32) * 64 - 64) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  if (in_len + c20_ctx->tag_len < in_len) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  if (max_out_len < in_len + c20_ctx->tag_len) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal,
+                      CIPHER_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  if (nonce_len != CHACHA20_NONCE_LEN) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_IV_TOO_LARGE);
+    return 0;
+  }
+
+  memset(poly1305_key, 0, sizeof(poly1305_key));
+  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
+                   c20_ctx->key, nonce, 0);
+
+  CRYPTO_poly1305_init(&poly1305, poly1305_key);
+  poly1305_update_with_length(&poly1305, ad, ad_len);
+  CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
+  poly1305_update_with_length(&poly1305, out, in_len);
+
+  if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
+    uint8_t tag[POLY1305_TAG_LEN];
+    CRYPTO_poly1305_finish(&poly1305, tag);
+    memcpy(out + in_len, tag, c20_ctx->tag_len);
+    *out_len = in_len + c20_ctx->tag_len;
+    return 1;
+  }
+
+  CRYPTO_poly1305_finish(&poly1305, out + in_len);
+  *out_len = in_len + c20_ctx->tag_len;
+  return 1;
+}
+
+static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
+                                       size_t *out_len, size_t max_out_len,
+                                       const uint8_t *nonce, size_t nonce_len,
+                                       const uint8_t *in, size_t in_len,
+                                       const uint8_t *ad, size_t ad_len) {
+  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+  uint8_t mac[POLY1305_TAG_LEN];
+  uint8_t poly1305_key[32] ALIGNED;
+  size_t plaintext_len;
+  poly1305_state poly1305;
+  const uint64_t in_len_64 = in_len;
+
+  if (in_len < c20_ctx->tag_len) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
+    return 0;
+  }
+
+  /* The underlying ChaCha implementation may not overflow the block
+   * counter into the second counter word. Therefore we disallow
+   * individual operations that work on more than 256GB at a time.
+   * |in_len_64| is needed because, on 32-bit platforms, size_t is only
+   * 32-bits and this produces a warning because it's always false.
+   * Casting to uint64_t inside the conditional is not sufficient to stop
+   * the warning. */
+  if (in_len_64 >= (1ull << 32) * 64 - 64) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  if (nonce_len != CHACHA20_NONCE_LEN) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_IV_TOO_LARGE);
+    return 0;
+  }
+
+  plaintext_len = in_len - c20_ctx->tag_len;
+
+  if (max_out_len < plaintext_len) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open,
+                      CIPHER_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  memset(poly1305_key, 0, sizeof(poly1305_key));
+  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
+                   c20_ctx->key, nonce, 0);
+
+  CRYPTO_poly1305_init(&poly1305, poly1305_key);
+  poly1305_update_with_length(&poly1305, ad, ad_len);
+  poly1305_update_with_length(&poly1305, in, plaintext_len);
+  CRYPTO_poly1305_finish(&poly1305, mac);
+
+  if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
+    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
+    return 0;
+  }
+
+  CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1);
+  *out_len = plaintext_len;
+  return 1;
+}
+
+static const EVP_AEAD aead_chacha20_poly1305 = {
+    32,                 /* key len */
+    CHACHA20_NONCE_LEN, /* nonce len */
+    POLY1305_TAG_LEN,   /* overhead */
+    POLY1305_TAG_LEN,   /* max tag length */
+    aead_chacha20_poly1305_init, aead_chacha20_poly1305_cleanup,
+    aead_chacha20_poly1305_seal, aead_chacha20_poly1305_open,
+};
+
+const EVP_AEAD *EVP_aead_chacha20_poly1305() { return &aead_chacha20_poly1305; }
diff --git a/crypto/poly1305/CMakeLists.txt b/crypto/poly1305/CMakeLists.txt
new file mode 100644
index 0000000..65d7dbb
--- /dev/null
+++ b/crypto/poly1305/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "arm")
+	set(
+		POLY1305_ARCH_SOURCES
+
+		poly1305_arm_asm.S
+	)
+endif()
+
+add_library(
+	poly1305
+
+	OBJECT
+
+	poly1305.c
+	poly1305_arm.c
+	poly1305_vec.c
+
+	${POLY1305_ARCH_SOURCES}
+)
diff --git a/crypto/poly1305/poly1305.c b/crypto/poly1305/poly1305.c
new file mode 100644
index 0000000..256ad69
--- /dev/null
+++ b/crypto/poly1305/poly1305.c
@@ -0,0 +1,323 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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 implementation of poly1305 is by Andrew Moon
+ * (https://github.com/floodyberry/poly1305-donna) and released as public
+ * domain. */
+
+#include <openssl/poly1305.h>
+
+#include <string.h>
+
+#include <openssl/cpu.h>
+
+
+#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64)
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM)
+/* We can assume little-endian. */
+static uint32_t U8TO32_LE(const uint8_t *m) {
+  uint32_t r;
+  memcpy(&r, m, sizeof(r));
+  return r;
+}
+
+static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); }
+#else
+static uint32_t U8TO32_LE(const uint8_t *m) {
+  return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 |
+         (uint32_t)m[3] << 24;
+}
+
+static void U32TO8_LE(uint8_t *m, uint32_t v) {
+  m[0] = v;
+  m[1] = v >> 8;
+  m[2] = v >> 16;
+  m[3] = v >> 24;
+}
+#endif
+
+#if defined(OPENSSL_ARM)
+void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]);
+
+void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in,
+                                 size_t in_len);
+
+void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]);
+#endif
+
+static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; }
+
+struct poly1305_state_st {
+  uint32_t r0, r1, r2, r3, r4;
+  uint32_t s1, s2, s3, s4;
+  uint32_t h0, h1, h2, h3, h4;
+  uint8_t buf[16];
+  unsigned int buf_used;
+  uint8_t key[16];
+};
+
+/* poly1305_blocks updates |state| given some amount of input data. This
+ * function may only be called with a |len| that is not a multiple of 16 at the
+ * end of the data. Otherwise the input must be buffered into 16 byte blocks. */
+static void poly1305_update(struct poly1305_state_st *state, const uint8_t *in,
+                            size_t len) {
+  uint32_t t0, t1, t2, t3;
+  uint64_t t[5];
+  uint32_t b;
+  uint64_t c;
+  size_t j;
+  uint8_t mp[16];
+
+  if (len < 16) {
+    goto poly1305_donna_atmost15bytes;
+  }
+
+poly1305_donna_16bytes:
+  t0 = U8TO32_LE(in);
+  t1 = U8TO32_LE(in + 4);
+  t2 = U8TO32_LE(in + 8);
+  t3 = U8TO32_LE(in + 12);
+
+  in += 16;
+  len -= 16;
+
+  state->h0 += t0 & 0x3ffffff;
+  state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+  state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+  state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+  state->h4 += (t3 >> 8) | (1 << 24);
+
+poly1305_donna_mul:
+  t[0] = mul32x32_64(state->h0, state->r0) + mul32x32_64(state->h1, state->s4) +
+         mul32x32_64(state->h2, state->s3) + mul32x32_64(state->h3, state->s2) +
+         mul32x32_64(state->h4, state->s1);
+  t[1] = mul32x32_64(state->h0, state->r1) + mul32x32_64(state->h1, state->r0) +
+         mul32x32_64(state->h2, state->s4) + mul32x32_64(state->h3, state->s3) +
+         mul32x32_64(state->h4, state->s2);
+  t[2] = mul32x32_64(state->h0, state->r2) + mul32x32_64(state->h1, state->r1) +
+         mul32x32_64(state->h2, state->r0) + mul32x32_64(state->h3, state->s4) +
+         mul32x32_64(state->h4, state->s3);
+  t[3] = mul32x32_64(state->h0, state->r3) + mul32x32_64(state->h1, state->r2) +
+         mul32x32_64(state->h2, state->r1) + mul32x32_64(state->h3, state->r0) +
+         mul32x32_64(state->h4, state->s4);
+  t[4] = mul32x32_64(state->h0, state->r4) + mul32x32_64(state->h1, state->r3) +
+         mul32x32_64(state->h2, state->r2) + mul32x32_64(state->h3, state->r1) +
+         mul32x32_64(state->h4, state->r0);
+
+  state->h0 = (uint32_t)t[0] & 0x3ffffff;
+  c = (t[0] >> 26);
+  t[1] += c;
+  state->h1 = (uint32_t)t[1] & 0x3ffffff;
+  b = (uint32_t)(t[1] >> 26);
+  t[2] += b;
+  state->h2 = (uint32_t)t[2] & 0x3ffffff;
+  b = (uint32_t)(t[2] >> 26);
+  t[3] += b;
+  state->h3 = (uint32_t)t[3] & 0x3ffffff;
+  b = (uint32_t)(t[3] >> 26);
+  t[4] += b;
+  state->h4 = (uint32_t)t[4] & 0x3ffffff;
+  b = (uint32_t)(t[4] >> 26);
+  state->h0 += b * 5;
+
+  if (len >= 16)
+    goto poly1305_donna_16bytes;
+
+/* final bytes */
+poly1305_donna_atmost15bytes:
+  if (!len)
+    return;
+
+  for (j = 0; j < len; j++)
+    mp[j] = in[j];
+  mp[j++] = 1;
+  for (; j < 16; j++)
+    mp[j] = 0;
+  len = 0;
+
+  t0 = U8TO32_LE(mp + 0);
+  t1 = U8TO32_LE(mp + 4);
+  t2 = U8TO32_LE(mp + 8);
+  t3 = U8TO32_LE(mp + 12);
+
+  state->h0 += t0 & 0x3ffffff;
+  state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+  state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+  state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+  state->h4 += (t3 >> 8);
+
+  goto poly1305_donna_mul;
+}
+
+void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) {
+  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+  uint32_t t0, t1, t2, t3;
+
+#if defined(OPENSSL_ARM)
+  if (CRYPTO_is_NEON_capable()) {
+    CRYPTO_poly1305_init_neon(statep, key);
+    return;
+  }
+#endif
+
+  t0 = U8TO32_LE(key + 0);
+  t1 = U8TO32_LE(key + 4);
+  t2 = U8TO32_LE(key + 8);
+  t3 = U8TO32_LE(key + 12);
+
+  /* precompute multipliers */
+  state->r0 = t0 & 0x3ffffff;
+  t0 >>= 26;
+  t0 |= t1 << 6;
+  state->r1 = t0 & 0x3ffff03;
+  t1 >>= 20;
+  t1 |= t2 << 12;
+  state->r2 = t1 & 0x3ffc0ff;
+  t2 >>= 14;
+  t2 |= t3 << 18;
+  state->r3 = t2 & 0x3f03fff;
+  t3 >>= 8;
+  state->r4 = t3 & 0x00fffff;
+
+  state->s1 = state->r1 * 5;
+  state->s2 = state->r2 * 5;
+  state->s3 = state->r3 * 5;
+  state->s4 = state->r4 * 5;
+
+  /* init state */
+  state->h0 = 0;
+  state->h1 = 0;
+  state->h2 = 0;
+  state->h3 = 0;
+  state->h4 = 0;
+
+  state->buf_used = 0;
+  memcpy(state->key, key + 16, sizeof(state->key));
+}
+
+void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in,
+                            size_t in_len) {
+  unsigned int i;
+  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+
+#if defined(OPENSSL_ARM)
+  if (CRYPTO_is_NEON_capable()) {
+    CRYPTO_poly1305_update_neon(statep, in, in_len);
+    return;
+  }
+#endif
+
+  if (state->buf_used) {
+    unsigned int todo = 16 - state->buf_used;
+    if (todo > in_len)
+      todo = in_len;
+    for (i = 0; i < todo; i++)
+      state->buf[state->buf_used + i] = in[i];
+    state->buf_used += todo;
+    in_len -= todo;
+    in += todo;
+
+    if (state->buf_used == 16) {
+      poly1305_update(state, state->buf, 16);
+      state->buf_used = 0;
+    }
+  }
+
+  if (in_len >= 16) {
+    size_t todo = in_len & ~0xf;
+    poly1305_update(state, in, todo);
+    in += todo;
+    in_len &= 0xf;
+  }
+
+  if (in_len) {
+    for (i = 0; i < in_len; i++)
+      state->buf[i] = in[i];
+    state->buf_used = in_len;
+  }
+}
+
+void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) {
+  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+  uint64_t f0, f1, f2, f3;
+  uint32_t g0, g1, g2, g3, g4;
+  uint32_t b, nb;
+
+#if defined(OPENSSL_ARM)
+  if (CRYPTO_is_NEON_capable()) {
+    CRYPTO_poly1305_finish_neon(statep, mac);
+    return;
+  }
+#endif
+
+  if (state->buf_used)
+    poly1305_update(state, state->buf, state->buf_used);
+
+  b = state->h0 >> 26;
+  state->h0 = state->h0 & 0x3ffffff;
+  state->h1 += b;
+  b = state->h1 >> 26;
+  state->h1 = state->h1 & 0x3ffffff;
+  state->h2 += b;
+  b = state->h2 >> 26;
+  state->h2 = state->h2 & 0x3ffffff;
+  state->h3 += b;
+  b = state->h3 >> 26;
+  state->h3 = state->h3 & 0x3ffffff;
+  state->h4 += b;
+  b = state->h4 >> 26;
+  state->h4 = state->h4 & 0x3ffffff;
+  state->h0 += b * 5;
+
+  g0 = state->h0 + 5;
+  b = g0 >> 26;
+  g0 &= 0x3ffffff;
+  g1 = state->h1 + b;
+  b = g1 >> 26;
+  g1 &= 0x3ffffff;
+  g2 = state->h2 + b;
+  b = g2 >> 26;
+  g2 &= 0x3ffffff;
+  g3 = state->h3 + b;
+  b = g3 >> 26;
+  g3 &= 0x3ffffff;
+  g4 = state->h4 + b - (1 << 26);
+
+  b = (g4 >> 31) - 1;
+  nb = ~b;
+  state->h0 = (state->h0 & nb) | (g0 & b);
+  state->h1 = (state->h1 & nb) | (g1 & b);
+  state->h2 = (state->h2 & nb) | (g2 & b);
+  state->h3 = (state->h3 & nb) | (g3 & b);
+  state->h4 = (state->h4 & nb) | (g4 & b);
+
+  f0 = ((state->h0) | (state->h1 << 26)) + (uint64_t)U8TO32_LE(&state->key[0]);
+  f1 = ((state->h1 >> 6) | (state->h2 << 20)) +
+       (uint64_t)U8TO32_LE(&state->key[4]);
+  f2 = ((state->h2 >> 12) | (state->h3 << 14)) +
+       (uint64_t)U8TO32_LE(&state->key[8]);
+  f3 = ((state->h3 >> 18) | (state->h4 << 8)) +
+       (uint64_t)U8TO32_LE(&state->key[12]);
+
+  U32TO8_LE(&mac[0], f0);
+  f1 += (f0 >> 32);
+  U32TO8_LE(&mac[4], f1);
+  f2 += (f1 >> 32);
+  U32TO8_LE(&mac[8], f2);
+  f3 += (f2 >> 32);
+  U32TO8_LE(&mac[12], f3);
+}
+
+#endif  /* OPENSSL_WINDOWS || !OPENSSL_X86_64 */
diff --git a/crypto/poly1305/poly1305.h b/crypto/poly1305/poly1305.h
new file mode 100644
index 0000000..a15bf1a
--- /dev/null
+++ b/crypto/poly1305/poly1305.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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 OPENSSL_HEADER_POLY1305_H
+#define OPENSSL_HEADER_POLY1305_H
+
+#include <openssl/base.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+typedef unsigned char poly1305_state[512];
+
+/* poly1305_init sets up |state| so that it can be used to calculate an
+ * authentication tag with the one-time key |key|. Note that |key| is a
+ * one-time key and therefore there is no `reset' method because that would
+ * enable several messages to be authenticated with the same key. */
+extern void CRYPTO_poly1305_init(poly1305_state* state, const uint8_t key[32]);
+
+/* poly1305_update processes |in_len| bytes from |in|. It can be called zero or
+ * more times after poly1305_init. */
+extern void CRYPTO_poly1305_update(poly1305_state* state, const uint8_t* in,
+                                   size_t in_len);
+
+/* poly1305_finish completes the poly1305 calculation and writes a 16 byte
+ * authentication tag to |mac|. */
+extern void CRYPTO_poly1305_finish(poly1305_state* state, uint8_t mac[16]);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_POLY1305_H */
diff --git a/crypto/poly1305/poly1305_arm.c b/crypto/poly1305/poly1305_arm.c
new file mode 100644
index 0000000..9d5e276
--- /dev/null
+++ b/crypto/poly1305/poly1305_arm.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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 implementation was taken from the public domain, neon2 version in
+ * SUPERCOP by D. J. Bernstein and Peter Schwabe. */
+
+#include <openssl/poly1305.h>
+
+
+#if defined(OPENSSL_ARM)
+
+typedef struct {
+  uint32_t v[12]; /* for alignment; only using 10 */
+} fe1305x2;
+
+#define addmulmod openssl_poly1305_neon2_addmulmod
+#define blocks openssl_poly1305_neon2_blocks
+
+extern void addmulmod(fe1305x2 *r, const fe1305x2 *x, const fe1305x2 *y,
+                      const fe1305x2 *c);
+
+extern int blocks(fe1305x2 *h, const fe1305x2 *precomp, const uint8_t *in,
+                  unsigned int inlen);
+
+static void freeze(fe1305x2 *r) {
+  int i;
+
+  uint32_t x0 = r->v[0];
+  uint32_t x1 = r->v[2];
+  uint32_t x2 = r->v[4];
+  uint32_t x3 = r->v[6];
+  uint32_t x4 = r->v[8];
+  uint32_t y0;
+  uint32_t y1;
+  uint32_t y2;
+  uint32_t y3;
+  uint32_t y4;
+  uint32_t swap;
+
+  for (i = 0; i < 3; ++i) {
+    x1 += x0 >> 26;
+    x0 &= 0x3ffffff;
+    x2 += x1 >> 26;
+    x1 &= 0x3ffffff;
+    x3 += x2 >> 26;
+    x2 &= 0x3ffffff;
+    x4 += x3 >> 26;
+    x3 &= 0x3ffffff;
+    x0 += 5 * (x4 >> 26);
+    x4 &= 0x3ffffff;
+  }
+
+  y0 = x0 + 5;
+  y1 = x1 + (y0 >> 26);
+  y0 &= 0x3ffffff;
+  y2 = x2 + (y1 >> 26);
+  y1 &= 0x3ffffff;
+  y3 = x3 + (y2 >> 26);
+  y2 &= 0x3ffffff;
+  y4 = x4 + (y3 >> 26);
+  y3 &= 0x3ffffff;
+  swap = -(y4 >> 26);
+  y4 &= 0x3ffffff;
+
+  y0 ^= x0;
+  y1 ^= x1;
+  y2 ^= x2;
+  y3 ^= x3;
+  y4 ^= x4;
+
+  y0 &= swap;
+  y1 &= swap;
+  y2 &= swap;
+  y3 &= swap;
+  y4 &= swap;
+
+  y0 ^= x0;
+  y1 ^= x1;
+  y2 ^= x2;
+  y3 ^= x3;
+  y4 ^= x4;
+
+  r->v[0] = y0;
+  r->v[2] = y1;
+  r->v[4] = y2;
+  r->v[6] = y3;
+  r->v[8] = y4;
+}
+
+static void fe1305x2_tobytearray(uint8_t *r, fe1305x2 *x) {
+  uint32_t x0 = x->v[0];
+  uint32_t x1 = x->v[2];
+  uint32_t x2 = x->v[4];
+  uint32_t x3 = x->v[6];
+  uint32_t x4 = x->v[8];
+
+  x1 += x0 >> 26;
+  x0 &= 0x3ffffff;
+  x2 += x1 >> 26;
+  x1 &= 0x3ffffff;
+  x3 += x2 >> 26;
+  x2 &= 0x3ffffff;
+  x4 += x3 >> 26;
+  x3 &= 0x3ffffff;
+
+  *(uint32_t *)r = x0 + (x1 << 26);
+  *(uint32_t *)(r + 4) = (x1 >> 6) + (x2 << 20);
+  *(uint32_t *)(r + 8) = (x2 >> 12) + (x3 << 14);
+  *(uint32_t *)(r + 12) = (x3 >> 18) + (x4 << 8);
+}
+
+/* load32 exists to avoid breaking strict aliasing rules in
+ * fe1305x2_frombytearray. */
+static uint32_t load32(uint8_t *t) {
+  uint32_t tmp;
+  memcpy(&tmp, t, sizeof(tmp));
+  return tmp;
+}
+
+static void fe1305x2_frombytearray(fe1305x2 *r, const uint8_t *x,
+                                   unsigned long long xlen) {
+  int i;
+  uint8_t t[17];
+
+  for (i = 0; (i < 16) && (i < xlen); i++)
+    t[i] = x[i];
+  xlen -= i;
+  x += i;
+  t[i++] = 1;
+  for (; i < 17; i++)
+    t[i] = 0;
+
+  r->v[0] = 0x3ffffff & load32(t);
+  r->v[2] = 0x3ffffff & (load32(t + 3) >> 2);
+  r->v[4] = 0x3ffffff & (load32(t + 6) >> 4);
+  r->v[6] = 0x3ffffff & (load32(t + 9) >> 6);
+  r->v[8] = load32(t + 13);
+
+  if (xlen) {
+    for (i = 0; (i < 16) && (i < xlen); i++)
+      t[i] = x[i];
+    t[i++] = 1;
+    for (; i < 17; i++)
+      t[i] = 0;
+
+    r->v[1] = 0x3ffffff & load32(t);
+    r->v[3] = 0x3ffffff & (load32(t + 3) >> 2);
+    r->v[5] = 0x3ffffff & (load32(t + 6) >> 4);
+    r->v[7] = 0x3ffffff & (load32(t + 9) >> 6);
+    r->v[9] = load32(t + 13);
+  } else
+    r->v[1] = r->v[3] = r->v[5] = r->v[7] = r->v[9] = 0;
+}
+
+static const fe1305x2 zero __attribute__((aligned(16)));
+
+struct poly1305_state_st {
+  uint8_t data[sizeof(fe1305x2[5]) + 128];
+  uint8_t buf[32];
+  unsigned int buf_used;
+  uint8_t key[16];
+};
+
+void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]) {
+  struct poly1305_state_st *st = (struct poly1305_state_st *)(state);
+  fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data)));
+  fe1305x2 *const h = r + 1;
+  fe1305x2 *const c = h + 1;
+  fe1305x2 *const precomp = c + 1;
+  unsigned int j;
+
+  r->v[1] = r->v[0] = 0x3ffffff & *(uint32_t *)key;
+  r->v[3] = r->v[2] = 0x3ffff03 & ((*(uint32_t *)(key + 3)) >> 2);
+  r->v[5] = r->v[4] = 0x3ffc0ff & ((*(uint32_t *)(key + 6)) >> 4);
+  r->v[7] = r->v[6] = 0x3f03fff & ((*(uint32_t *)(key + 9)) >> 6);
+  r->v[9] = r->v[8] = 0x00fffff & ((*(uint32_t *)(key + 12)) >> 8);
+
+  for (j = 0; j < 10; j++)
+    h->v[j] = 0; /* XXX: should fast-forward a bit */
+
+  addmulmod(precomp, r, r, &zero);                 /* precompute r^2 */
+  addmulmod(precomp + 1, precomp, precomp, &zero); /* precompute r^4 */
+
+  memcpy(st->key, key + 16, 16);
+  st->buf_used = 0;
+}
+
+void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in,
+                                 size_t in_len) {
+  struct poly1305_state_st *st = (struct poly1305_state_st *)(state);
+  fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data)));
+  fe1305x2 *const h = r + 1;
+  fe1305x2 *const c = h + 1;
+  fe1305x2 *const precomp = c + 1;
+  unsigned int i;
+
+  if (st->buf_used) {
+    unsigned int todo = 32 - st->buf_used;
+    if (todo > in_len)
+      todo = in_len;
+    for (i = 0; i < todo; i++)
+      st->buf[st->buf_used + i] = in[i];
+    st->buf_used += todo;
+    in_len -= todo;
+    in += todo;
+
+    if (st->buf_used == sizeof(st->buf) && in_len) {
+      addmulmod(h, h, precomp, &zero);
+      fe1305x2_frombytearray(c, st->buf, sizeof(st->buf));
+      for (i = 0; i < 10; i++)
+        h->v[i] += c->v[i];
+      st->buf_used = 0;
+    }
+  }
+
+  while (in_len > 32) {
+    unsigned int tlen = 1048576;
+    if (in_len < tlen)
+      tlen = in_len;
+    tlen -= blocks(h, precomp, in, tlen);
+    in_len -= tlen;
+    in += tlen;
+  }
+
+  if (in_len) {
+    for (i = 0; i < in_len; i++)
+      st->buf[i] = in[i];
+    st->buf_used = in_len;
+  }
+}
+
+void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]) {
+  struct poly1305_state_st *st = (struct poly1305_state_st *)(state);
+  fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data)));
+  fe1305x2 *const h = r + 1;
+  fe1305x2 *const c = h + 1;
+  fe1305x2 *const precomp = c + 1;
+
+  addmulmod(h, h, precomp, &zero);
+
+  if (st->buf_used > 16) {
+    fe1305x2_frombytearray(c, st->buf, st->buf_used);
+    precomp->v[1] = r->v[1];
+    precomp->v[3] = r->v[3];
+    precomp->v[5] = r->v[5];
+    precomp->v[7] = r->v[7];
+    precomp->v[9] = r->v[9];
+    addmulmod(h, h, precomp, c);
+  } else if (st->buf_used > 0) {
+    fe1305x2_frombytearray(c, st->buf, st->buf_used);
+    r->v[1] = 1;
+    r->v[3] = 0;
+    r->v[5] = 0;
+    r->v[7] = 0;
+    r->v[9] = 0;
+    addmulmod(h, h, r, c);
+  }
+
+  h->v[0] += h->v[1];
+  h->v[2] += h->v[3];
+  h->v[4] += h->v[5];
+  h->v[6] += h->v[7];
+  h->v[8] += h->v[9];
+  freeze(h);
+
+  fe1305x2_frombytearray(c, st->key, 16);
+  c->v[8] ^= (1 << 24);
+
+  h->v[0] += c->v[0];
+  h->v[2] += c->v[2];
+  h->v[4] += c->v[4];
+  h->v[6] += c->v[6];
+  h->v[8] += c->v[8];
+  fe1305x2_tobytearray(mac, h);
+}
+
+#endif  /* OPENSSL_ARM */
diff --git a/crypto/poly1305/poly1305_arm_asm.S b/crypto/poly1305/poly1305_arm_asm.S
new file mode 100644
index 0000000..e196e57
--- /dev/null
+++ b/crypto/poly1305/poly1305_arm_asm.S
@@ -0,0 +1,2013 @@
+#if defined(__arm__)
+
+# This implementation was taken from the public domain, neon2 version in
+# SUPERCOP by D. J. Bernstein and Peter Schwabe.
+
+# qhasm: int32 input_0
+
+# qhasm: int32 input_1
+
+# qhasm: int32 input_2
+
+# qhasm: int32 input_3
+
+# qhasm: stack32 input_4
+
+# qhasm: stack32 input_5
+
+# qhasm: stack32 input_6
+
+# qhasm: stack32 input_7
+
+# qhasm: int32 caller_r4
+
+# qhasm: int32 caller_r5
+
+# qhasm: int32 caller_r6
+
+# qhasm: int32 caller_r7
+
+# qhasm: int32 caller_r8
+
+# qhasm: int32 caller_r9
+
+# qhasm: int32 caller_r10
+
+# qhasm: int32 caller_r11
+
+# qhasm: int32 caller_r12
+
+# qhasm: int32 caller_r14
+
+# qhasm: reg128 caller_q4
+
+# qhasm: reg128 caller_q5
+
+# qhasm: reg128 caller_q6
+
+# qhasm: reg128 caller_q7
+
+# qhasm: startcode
+.fpu neon
+.text
+
+# qhasm: reg128 r0
+
+# qhasm: reg128 r1
+
+# qhasm: reg128 r2
+
+# qhasm: reg128 r3
+
+# qhasm: reg128 r4
+
+# qhasm: reg128 x01
+
+# qhasm: reg128 x23
+
+# qhasm: reg128 x4
+
+# qhasm: reg128 y0
+
+# qhasm: reg128 y12
+
+# qhasm: reg128 y34
+
+# qhasm: reg128 5y12
+
+# qhasm: reg128 5y34
+
+# qhasm: stack128 y0_stack
+
+# qhasm: stack128 y12_stack
+
+# qhasm: stack128 y34_stack
+
+# qhasm: stack128 5y12_stack
+
+# qhasm: stack128 5y34_stack
+
+# qhasm: reg128 z0
+
+# qhasm: reg128 z12
+
+# qhasm: reg128 z34
+
+# qhasm: reg128 5z12
+
+# qhasm: reg128 5z34
+
+# qhasm: stack128 z0_stack
+
+# qhasm: stack128 z12_stack
+
+# qhasm: stack128 z34_stack
+
+# qhasm: stack128 5z12_stack
+
+# qhasm: stack128 5z34_stack
+
+# qhasm: stack128 two24
+
+# qhasm: int32 ptr
+
+# qhasm: reg128 c01
+
+# qhasm: reg128 c23
+
+# qhasm: reg128 d01
+
+# qhasm: reg128 d23
+
+# qhasm: reg128 t0
+
+# qhasm: reg128 t1
+
+# qhasm: reg128 t2
+
+# qhasm: reg128 t3
+
+# qhasm: reg128 t4
+
+# qhasm: reg128 mask
+
+# qhasm: reg128 u0
+
+# qhasm: reg128 u1
+
+# qhasm: reg128 u2
+
+# qhasm: reg128 u3
+
+# qhasm: reg128 u4
+
+# qhasm: reg128 v01
+
+# qhasm: reg128 mid
+
+# qhasm: reg128 v23
+
+# qhasm: reg128 v4
+
+# qhasm: int32 len
+
+# qhasm: qpushenter crypto_onetimeauth_poly1305_neon2_blocks
+.align 4
+.global openssl_poly1305_neon2_blocks
+.type openssl_poly1305_neon2_blocks STT_FUNC
+openssl_poly1305_neon2_blocks:
+vpush {q4,q5,q6,q7}
+mov r12,sp
+sub sp,sp,#192
+and sp,sp,#0xffffffe0
+
+# qhasm: len = input_3
+# asm 1: mov >len=int32#4,<input_3=int32#4
+# asm 2: mov >len=r3,<input_3=r3
+mov r3,r3
+
+# qhasm: new y0
+
+# qhasm: y0  = mem64[input_1]y0[1]; input_1 += 8
+# asm 1: vld1.8 {<y0=reg128#1%bot},[<input_1=int32#2]!
+# asm 2: vld1.8 {<y0=d0},[<input_1=r1]!
+vld1.8 {d0},[r1]!
+
+# qhasm: y12 = mem128[input_1]; input_1 += 16
+# asm 1: vld1.8 {>y12=reg128#2%bot->y12=reg128#2%top},[<input_1=int32#2]!
+# asm 2: vld1.8 {>y12=d2->y12=d3},[<input_1=r1]!
+vld1.8 {d2-d3},[r1]!
+
+# qhasm: y34 = mem128[input_1]; input_1 += 16
+# asm 1: vld1.8 {>y34=reg128#3%bot->y34=reg128#3%top},[<input_1=int32#2]!
+# asm 2: vld1.8 {>y34=d4->y34=d5},[<input_1=r1]!
+vld1.8 {d4-d5},[r1]!
+
+# qhasm: input_1 += 8
+# asm 1: add >input_1=int32#2,<input_1=int32#2,#8
+# asm 2: add >input_1=r1,<input_1=r1,#8
+add r1,r1,#8
+
+# qhasm: new z0
+
+# qhasm: z0  = mem64[input_1]z0[1]; input_1 += 8
+# asm 1: vld1.8 {<z0=reg128#4%bot},[<input_1=int32#2]!
+# asm 2: vld1.8 {<z0=d6},[<input_1=r1]!
+vld1.8 {d6},[r1]!
+
+# qhasm: z12 = mem128[input_1]; input_1 += 16
+# asm 1: vld1.8 {>z12=reg128#5%bot->z12=reg128#5%top},[<input_1=int32#2]!
+# asm 2: vld1.8 {>z12=d8->z12=d9},[<input_1=r1]!
+vld1.8 {d8-d9},[r1]!
+
+# qhasm: z34 = mem128[input_1]; input_1 += 16
+# asm 1: vld1.8 {>z34=reg128#6%bot->z34=reg128#6%top},[<input_1=int32#2]!
+# asm 2: vld1.8 {>z34=d10->z34=d11},[<input_1=r1]!
+vld1.8 {d10-d11},[r1]!
+
+# qhasm: 2x mask = 0xffffffff
+# asm 1: vmov.i64 >mask=reg128#7,#0xffffffff
+# asm 2: vmov.i64 >mask=q6,#0xffffffff
+vmov.i64 q6,#0xffffffff
+
+# qhasm: 2x u4 = 0xff
+# asm 1: vmov.i64 >u4=reg128#8,#0xff
+# asm 2: vmov.i64 >u4=q7,#0xff
+vmov.i64 q7,#0xff
+
+# qhasm: x01 aligned= mem128[input_0];input_0+=16
+# asm 1: vld1.8 {>x01=reg128#9%bot->x01=reg128#9%top},[<input_0=int32#1,: 128]!
+# asm 2: vld1.8 {>x01=d16->x01=d17},[<input_0=r0,: 128]!
+vld1.8 {d16-d17},[r0,: 128]!
+
+# qhasm: x23 aligned= mem128[input_0];input_0+=16
+# asm 1: vld1.8 {>x23=reg128#10%bot->x23=reg128#10%top},[<input_0=int32#1,: 128]!
+# asm 2: vld1.8 {>x23=d18->x23=d19},[<input_0=r0,: 128]!
+vld1.8 {d18-d19},[r0,: 128]!
+
+# qhasm: x4  aligned= mem64[input_0]x4[1]
+# asm 1: vld1.8 {<x4=reg128#11%bot},[<input_0=int32#1,: 64]
+# asm 2: vld1.8 {<x4=d20},[<input_0=r0,: 64]
+vld1.8 {d20},[r0,: 64]
+
+# qhasm: input_0 -= 32
+# asm 1: sub >input_0=int32#1,<input_0=int32#1,#32
+# asm 2: sub >input_0=r0,<input_0=r0,#32
+sub r0,r0,#32
+
+# qhasm: 2x mask unsigned>>=6
+# asm 1: vshr.u64 >mask=reg128#7,<mask=reg128#7,#6
+# asm 2: vshr.u64 >mask=q6,<mask=q6,#6
+vshr.u64 q6,q6,#6
+
+# qhasm: 2x u4 unsigned>>= 7
+# asm 1: vshr.u64 >u4=reg128#8,<u4=reg128#8,#7
+# asm 2: vshr.u64 >u4=q7,<u4=q7,#7
+vshr.u64 q7,q7,#7
+
+# qhasm: 4x 5y12 = y12 << 2
+# asm 1: vshl.i32 >5y12=reg128#12,<y12=reg128#2,#2
+# asm 2: vshl.i32 >5y12=q11,<y12=q1,#2
+vshl.i32 q11,q1,#2
+
+# qhasm: 4x 5y34 = y34 << 2
+# asm 1: vshl.i32 >5y34=reg128#13,<y34=reg128#3,#2
+# asm 2: vshl.i32 >5y34=q12,<y34=q2,#2
+vshl.i32 q12,q2,#2
+
+# qhasm: 4x 5y12 += y12
+# asm 1: vadd.i32 >5y12=reg128#12,<5y12=reg128#12,<y12=reg128#2
+# asm 2: vadd.i32 >5y12=q11,<5y12=q11,<y12=q1
+vadd.i32 q11,q11,q1
+
+# qhasm: 4x 5y34 += y34
+# asm 1: vadd.i32 >5y34=reg128#13,<5y34=reg128#13,<y34=reg128#3
+# asm 2: vadd.i32 >5y34=q12,<5y34=q12,<y34=q2
+vadd.i32 q12,q12,q2
+
+# qhasm: 2x u4 <<= 24
+# asm 1: vshl.i64 >u4=reg128#8,<u4=reg128#8,#24
+# asm 2: vshl.i64 >u4=q7,<u4=q7,#24
+vshl.i64 q7,q7,#24
+
+# qhasm: 4x 5z12 = z12 << 2
+# asm 1: vshl.i32 >5z12=reg128#14,<z12=reg128#5,#2
+# asm 2: vshl.i32 >5z12=q13,<z12=q4,#2
+vshl.i32 q13,q4,#2
+
+# qhasm: 4x 5z34 = z34 << 2
+# asm 1: vshl.i32 >5z34=reg128#15,<z34=reg128#6,#2
+# asm 2: vshl.i32 >5z34=q14,<z34=q5,#2
+vshl.i32 q14,q5,#2
+
+# qhasm: 4x 5z12 += z12
+# asm 1: vadd.i32 >5z12=reg128#14,<5z12=reg128#14,<z12=reg128#5
+# asm 2: vadd.i32 >5z12=q13,<5z12=q13,<z12=q4
+vadd.i32 q13,q13,q4
+
+# qhasm: 4x 5z34 += z34
+# asm 1: vadd.i32 >5z34=reg128#15,<5z34=reg128#15,<z34=reg128#6
+# asm 2: vadd.i32 >5z34=q14,<5z34=q14,<z34=q5
+vadd.i32 q14,q14,q5
+
+# qhasm: new two24
+
+# qhasm: new y0_stack
+
+# qhasm: new y12_stack
+
+# qhasm: new y34_stack
+
+# qhasm: new 5y12_stack
+
+# qhasm: new 5y34_stack
+
+# qhasm: new z0_stack
+
+# qhasm: new z12_stack
+
+# qhasm: new z34_stack
+
+# qhasm: new 5z12_stack
+
+# qhasm: new 5z34_stack
+
+# qhasm: ptr = &two24
+# asm 1: lea >ptr=int32#2,<two24=stack128#1
+# asm 2: lea >ptr=r1,<two24=[sp,#0]
+add r1,sp,#0
+
+# qhasm: mem128[ptr] aligned= u4
+# asm 1: vst1.8 {<u4=reg128#8%bot-<u4=reg128#8%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<u4=d14-<u4=d15},[<ptr=r1,: 128]
+vst1.8 {d14-d15},[r1,: 128]
+
+# qhasm: r4 = u4
+# asm 1: vmov >r4=reg128#16,<u4=reg128#8
+# asm 2: vmov >r4=q15,<u4=q7
+vmov q15,q7
+
+# qhasm: r0 = u4
+# asm 1: vmov >r0=reg128#8,<u4=reg128#8
+# asm 2: vmov >r0=q7,<u4=q7
+vmov q7,q7
+
+# qhasm: ptr = &y0_stack
+# asm 1: lea >ptr=int32#2,<y0_stack=stack128#2
+# asm 2: lea >ptr=r1,<y0_stack=[sp,#16]
+add r1,sp,#16
+
+# qhasm: mem128[ptr] aligned= y0
+# asm 1: vst1.8 {<y0=reg128#1%bot-<y0=reg128#1%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<y0=d0-<y0=d1},[<ptr=r1,: 128]
+vst1.8 {d0-d1},[r1,: 128]
+
+# qhasm: ptr = &y12_stack
+# asm 1: lea >ptr=int32#2,<y12_stack=stack128#3
+# asm 2: lea >ptr=r1,<y12_stack=[sp,#32]
+add r1,sp,#32
+
+# qhasm: mem128[ptr] aligned= y12
+# asm 1: vst1.8 {<y12=reg128#2%bot-<y12=reg128#2%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<y12=d2-<y12=d3},[<ptr=r1,: 128]
+vst1.8 {d2-d3},[r1,: 128]
+
+# qhasm: ptr = &y34_stack
+# asm 1: lea >ptr=int32#2,<y34_stack=stack128#4
+# asm 2: lea >ptr=r1,<y34_stack=[sp,#48]
+add r1,sp,#48
+
+# qhasm: mem128[ptr] aligned= y34
+# asm 1: vst1.8 {<y34=reg128#3%bot-<y34=reg128#3%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<y34=d4-<y34=d5},[<ptr=r1,: 128]
+vst1.8 {d4-d5},[r1,: 128]
+
+# qhasm: ptr = &z0_stack
+# asm 1: lea >ptr=int32#2,<z0_stack=stack128#7
+# asm 2: lea >ptr=r1,<z0_stack=[sp,#96]
+add r1,sp,#96
+
+# qhasm: mem128[ptr] aligned= z0
+# asm 1: vst1.8 {<z0=reg128#4%bot-<z0=reg128#4%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<z0=d6-<z0=d7},[<ptr=r1,: 128]
+vst1.8 {d6-d7},[r1,: 128]
+
+# qhasm: ptr = &z12_stack
+# asm 1: lea >ptr=int32#2,<z12_stack=stack128#8
+# asm 2: lea >ptr=r1,<z12_stack=[sp,#112]
+add r1,sp,#112
+
+# qhasm: mem128[ptr] aligned= z12
+# asm 1: vst1.8 {<z12=reg128#5%bot-<z12=reg128#5%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<z12=d8-<z12=d9},[<ptr=r1,: 128]
+vst1.8 {d8-d9},[r1,: 128]
+
+# qhasm: ptr = &z34_stack
+# asm 1: lea >ptr=int32#2,<z34_stack=stack128#9
+# asm 2: lea >ptr=r1,<z34_stack=[sp,#128]
+add r1,sp,#128
+
+# qhasm: mem128[ptr] aligned= z34
+# asm 1: vst1.8 {<z34=reg128#6%bot-<z34=reg128#6%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<z34=d10-<z34=d11},[<ptr=r1,: 128]
+vst1.8 {d10-d11},[r1,: 128]
+
+# qhasm: ptr = &5y12_stack
+# asm 1: lea >ptr=int32#2,<5y12_stack=stack128#5
+# asm 2: lea >ptr=r1,<5y12_stack=[sp,#64]
+add r1,sp,#64
+
+# qhasm: mem128[ptr] aligned= 5y12
+# asm 1: vst1.8 {<5y12=reg128#12%bot-<5y12=reg128#12%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<5y12=d22-<5y12=d23},[<ptr=r1,: 128]
+vst1.8 {d22-d23},[r1,: 128]
+
+# qhasm: ptr = &5y34_stack
+# asm 1: lea >ptr=int32#2,<5y34_stack=stack128#6
+# asm 2: lea >ptr=r1,<5y34_stack=[sp,#80]
+add r1,sp,#80
+
+# qhasm: mem128[ptr] aligned= 5y34
+# asm 1: vst1.8 {<5y34=reg128#13%bot-<5y34=reg128#13%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<5y34=d24-<5y34=d25},[<ptr=r1,: 128]
+vst1.8 {d24-d25},[r1,: 128]
+
+# qhasm: ptr = &5z12_stack
+# asm 1: lea >ptr=int32#2,<5z12_stack=stack128#10
+# asm 2: lea >ptr=r1,<5z12_stack=[sp,#144]
+add r1,sp,#144
+
+# qhasm: mem128[ptr] aligned= 5z12
+# asm 1: vst1.8 {<5z12=reg128#14%bot-<5z12=reg128#14%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<5z12=d26-<5z12=d27},[<ptr=r1,: 128]
+vst1.8 {d26-d27},[r1,: 128]
+
+# qhasm: ptr = &5z34_stack
+# asm 1: lea >ptr=int32#2,<5z34_stack=stack128#11
+# asm 2: lea >ptr=r1,<5z34_stack=[sp,#160]
+add r1,sp,#160
+
+# qhasm: mem128[ptr] aligned= 5z34
+# asm 1: vst1.8 {<5z34=reg128#15%bot-<5z34=reg128#15%top},[<ptr=int32#2,: 128]
+# asm 2: vst1.8 {<5z34=d28-<5z34=d29},[<ptr=r1,: 128]
+vst1.8 {d28-d29},[r1,: 128]
+
+# qhasm:                       unsigned>? len - 64
+# asm 1: cmp <len=int32#4,#64
+# asm 2: cmp <len=r3,#64
+cmp r3,#64
+
+# qhasm: goto below64bytes if !unsigned>
+bls ._below64bytes
+
+# qhasm: input_2 += 32
+# asm 1: add >input_2=int32#2,<input_2=int32#3,#32
+# asm 2: add >input_2=r1,<input_2=r2,#32
+add r1,r2,#32
+
+# qhasm: mainloop2:
+._mainloop2:
+
+# qhasm:   c01 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>c01=reg128#1%bot->c01=reg128#1%top},[<input_2=int32#2]!
+# asm 2: vld1.8 {>c01=d0->c01=d1},[<input_2=r1]!
+vld1.8 {d0-d1},[r1]!
+
+# qhasm:   c23 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>c23=reg128#2%bot->c23=reg128#2%top},[<input_2=int32#2]!
+# asm 2: vld1.8 {>c23=d2->c23=d3},[<input_2=r1]!
+vld1.8 {d2-d3},[r1]!
+
+# qhasm: r4[0,1] += x01[0] unsigned*  z34[2];  r4[2,3] += x01[1] unsigned*  z34[3]
+# asm 1: vmlal.u32 <r4=reg128#16,<x01=reg128#9%bot,<z34=reg128#6%top
+# asm 2: vmlal.u32 <r4=q15,<x01=d16,<z34=d11
+vmlal.u32 q15,d16,d11
+
+# qhasm:   ptr = &z12_stack
+# asm 1: lea >ptr=int32#3,<z12_stack=stack128#8
+# asm 2: lea >ptr=r2,<z12_stack=[sp,#112]
+add r2,sp,#112
+
+# qhasm:   z12 aligned= mem128[ptr]
+# asm 1: vld1.8 {>z12=reg128#3%bot->z12=reg128#3%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>z12=d4->z12=d5},[<ptr=r2,: 128]
+vld1.8 {d4-d5},[r2,: 128]
+
+# qhasm: r4[0,1] += x01[2] unsigned* z34[0];  r4[2,3] += x01[3] unsigned* z34[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<x01=reg128#9%top,<z34=reg128#6%bot
+# asm 2: vmlal.u32 <r4=q15,<x01=d17,<z34=d10
+vmlal.u32 q15,d17,d10
+
+# qhasm:   ptr = &z0_stack
+# asm 1: lea >ptr=int32#3,<z0_stack=stack128#7
+# asm 2: lea >ptr=r2,<z0_stack=[sp,#96]
+add r2,sp,#96
+
+# qhasm:   z0 aligned= mem128[ptr]
+# asm 1: vld1.8 {>z0=reg128#4%bot->z0=reg128#4%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>z0=d6->z0=d7},[<ptr=r2,: 128]
+vld1.8 {d6-d7},[r2,: 128]
+
+# qhasm: r4[0,1] += x23[0] unsigned* z12[2];  r4[2,3] += x23[1] unsigned* z12[3]
+# asm 1: vmlal.u32 <r4=reg128#16,<x23=reg128#10%bot,<z12=reg128#3%top
+# asm 2: vmlal.u32 <r4=q15,<x23=d18,<z12=d5
+vmlal.u32 q15,d18,d5
+
+# qhasm:   c01 c23 = c01[0]c01[1]c01[2]c23[2]c23[0]c23[1]c01[3]c23[3]
+# asm 1: vtrn.32 <c01=reg128#1%top,<c23=reg128#2%top
+# asm 2: vtrn.32 <c01=d1,<c23=d3
+vtrn.32 d1,d3
+
+# qhasm: r4[0,1] += x23[2] unsigned* z12[0];  r4[2,3] += x23[3] unsigned* z12[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<x23=reg128#10%top,<z12=reg128#3%bot
+# asm 2: vmlal.u32 <r4=q15,<x23=d19,<z12=d4
+vmlal.u32 q15,d19,d4
+
+# qhasm: r4[0,1] +=  x4[0] unsigned* z0[0];  r4[2,3] +=  x4[1] unsigned* z0[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<x4=reg128#11%bot,<z0=reg128#4%bot
+# asm 2: vmlal.u32 <r4=q15,<x4=d20,<z0=d6
+vmlal.u32 q15,d20,d6
+
+# qhasm: r3[0,1] = c23[2]<<18; r3[2,3] = c23[3]<<18 
+# asm 1: vshll.u32 >r3=reg128#5,<c23=reg128#2%top,#18
+# asm 2: vshll.u32 >r3=q4,<c23=d3,#18
+vshll.u32 q4,d3,#18
+
+# qhasm:   c01 c23 = c01[0]c23[0]c01[2]c01[3]c01[1]c23[1]c23[2]c23[3]
+# asm 1: vtrn.32 <c01=reg128#1%bot,<c23=reg128#2%bot
+# asm 2: vtrn.32 <c01=d0,<c23=d2
+vtrn.32 d0,d2
+
+# qhasm: r3[0,1] += x01[0] unsigned* z34[0];   r3[2,3] += x01[1] unsigned* z34[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<x01=reg128#9%bot,<z34=reg128#6%bot
+# asm 2: vmlal.u32 <r3=q4,<x01=d16,<z34=d10
+vmlal.u32 q4,d16,d10
+
+# qhasm: r3[0,1] += x01[2] unsigned* z12[2];   r3[2,3] += x01[3] unsigned* z12[3]
+# asm 1: vmlal.u32 <r3=reg128#5,<x01=reg128#9%top,<z12=reg128#3%top
+# asm 2: vmlal.u32 <r3=q4,<x01=d17,<z12=d5
+vmlal.u32 q4,d17,d5
+
+# qhasm:   r0 = r0[1]c01[0]r0[2,3] 
+# asm 1: vext.32 <r0=reg128#8%bot,<r0=reg128#8%bot,<c01=reg128#1%bot,#1
+# asm 2: vext.32 <r0=d14,<r0=d14,<c01=d0,#1
+vext.32 d14,d14,d0,#1
+
+# qhasm: r3[0,1] += x23[0] unsigned* z12[0];   r3[2,3] += x23[1] unsigned* z12[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<x23=reg128#10%bot,<z12=reg128#3%bot
+# asm 2: vmlal.u32 <r3=q4,<x23=d18,<z12=d4
+vmlal.u32 q4,d18,d4
+
+# qhasm: 								input_2 -= 64
+# asm 1: sub >input_2=int32#2,<input_2=int32#2,#64
+# asm 2: sub >input_2=r1,<input_2=r1,#64
+sub r1,r1,#64
+
+# qhasm: r3[0,1] += x23[2] unsigned* z0[0];   r3[2,3] += x23[3] unsigned* z0[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<x23=reg128#10%top,<z0=reg128#4%bot
+# asm 2: vmlal.u32 <r3=q4,<x23=d19,<z0=d6
+vmlal.u32 q4,d19,d6
+
+# qhasm:   ptr = &5z34_stack
+# asm 1: lea >ptr=int32#3,<5z34_stack=stack128#11
+# asm 2: lea >ptr=r2,<5z34_stack=[sp,#160]
+add r2,sp,#160
+
+# qhasm:   5z34 aligned= mem128[ptr]
+# asm 1: vld1.8 {>5z34=reg128#6%bot->5z34=reg128#6%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>5z34=d10->5z34=d11},[<ptr=r2,: 128]
+vld1.8 {d10-d11},[r2,: 128]
+
+# qhasm: r3[0,1] +=  x4[0] unsigned*  5z34[2]; r3[2,3] +=  x4[1] unsigned*  5z34[3]
+# asm 1: vmlal.u32 <r3=reg128#5,<x4=reg128#11%bot,<5z34=reg128#6%top
+# asm 2: vmlal.u32 <r3=q4,<x4=d20,<5z34=d11
+vmlal.u32 q4,d20,d11
+
+# qhasm:   r0 = r0[1]r0[0]r0[3]r0[2] 
+# asm 1: vrev64.i32 >r0=reg128#8,<r0=reg128#8
+# asm 2: vrev64.i32 >r0=q7,<r0=q7
+vrev64.i32 q7,q7
+
+# qhasm:   r2[0,1] = c01[2]<<12; r2[2,3] = c01[3]<<12 
+# asm 1: vshll.u32 >r2=reg128#14,<c01=reg128#1%top,#12
+# asm 2: vshll.u32 >r2=q13,<c01=d1,#12
+vshll.u32 q13,d1,#12
+
+# qhasm:   		d01 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>d01=reg128#12%bot->d01=reg128#12%top},[<input_2=int32#2]!
+# asm 2: vld1.8 {>d01=d22->d01=d23},[<input_2=r1]!
+vld1.8 {d22-d23},[r1]!
+
+# qhasm: r2[0,1] += x01[0] unsigned* z12[2];   r2[2,3] += x01[1] unsigned* z12[3]
+# asm 1: vmlal.u32 <r2=reg128#14,<x01=reg128#9%bot,<z12=reg128#3%top
+# asm 2: vmlal.u32 <r2=q13,<x01=d16,<z12=d5
+vmlal.u32 q13,d16,d5
+
+# qhasm: r2[0,1] += x01[2] unsigned* z12[0];   r2[2,3] += x01[3] unsigned* z12[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<x01=reg128#9%top,<z12=reg128#3%bot
+# asm 2: vmlal.u32 <r2=q13,<x01=d17,<z12=d4
+vmlal.u32 q13,d17,d4
+
+# qhasm: r2[0,1] += x23[0] unsigned* z0[0];   r2[2,3] += x23[1] unsigned* z0[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<x23=reg128#10%bot,<z0=reg128#4%bot
+# asm 2: vmlal.u32 <r2=q13,<x23=d18,<z0=d6
+vmlal.u32 q13,d18,d6
+
+# qhasm: r2[0,1] += x23[2] unsigned*  5z34[2]; r2[2,3] += x23[3] unsigned*  5z34[3]
+# asm 1: vmlal.u32 <r2=reg128#14,<x23=reg128#10%top,<5z34=reg128#6%top
+# asm 2: vmlal.u32 <r2=q13,<x23=d19,<5z34=d11
+vmlal.u32 q13,d19,d11
+
+# qhasm: r2[0,1] +=  x4[0] unsigned* 5z34[0]; r2[2,3] +=  x4[1] unsigned* 5z34[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<x4=reg128#11%bot,<5z34=reg128#6%bot
+# asm 2: vmlal.u32 <r2=q13,<x4=d20,<5z34=d10
+vmlal.u32 q13,d20,d10
+
+# qhasm:   r0 = r0[0,1]c01[1]r0[2] 
+# asm 1: vext.32 <r0=reg128#8%top,<c01=reg128#1%bot,<r0=reg128#8%top,#1
+# asm 2: vext.32 <r0=d15,<c01=d0,<r0=d15,#1
+vext.32 d15,d0,d15,#1
+
+# qhasm:   r1[0,1] = c23[0]<<6; r1[2,3] = c23[1]<<6 
+# asm 1: vshll.u32 >r1=reg128#15,<c23=reg128#2%bot,#6
+# asm 2: vshll.u32 >r1=q14,<c23=d2,#6
+vshll.u32 q14,d2,#6
+
+# qhasm: r1[0,1] += x01[0] unsigned* z12[0];   r1[2,3] += x01[1] unsigned* z12[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<x01=reg128#9%bot,<z12=reg128#3%bot
+# asm 2: vmlal.u32 <r1=q14,<x01=d16,<z12=d4
+vmlal.u32 q14,d16,d4
+
+# qhasm: r1[0,1] += x01[2] unsigned* z0[0];   r1[2,3] += x01[3] unsigned* z0[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<x01=reg128#9%top,<z0=reg128#4%bot
+# asm 2: vmlal.u32 <r1=q14,<x01=d17,<z0=d6
+vmlal.u32 q14,d17,d6
+
+# qhasm: r1[0,1] += x23[0] unsigned*  5z34[2]; r1[2,3] += x23[1] unsigned*  5z34[3]
+# asm 1: vmlal.u32 <r1=reg128#15,<x23=reg128#10%bot,<5z34=reg128#6%top
+# asm 2: vmlal.u32 <r1=q14,<x23=d18,<5z34=d11
+vmlal.u32 q14,d18,d11
+
+# qhasm: r1[0,1] += x23[2] unsigned* 5z34[0]; r1[2,3] += x23[3] unsigned* 5z34[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<x23=reg128#10%top,<5z34=reg128#6%bot
+# asm 2: vmlal.u32 <r1=q14,<x23=d19,<5z34=d10
+vmlal.u32 q14,d19,d10
+
+# qhasm: ptr = &5z12_stack
+# asm 1: lea >ptr=int32#3,<5z12_stack=stack128#10
+# asm 2: lea >ptr=r2,<5z12_stack=[sp,#144]
+add r2,sp,#144
+
+# qhasm: 5z12 aligned= mem128[ptr]
+# asm 1: vld1.8 {>5z12=reg128#1%bot->5z12=reg128#1%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>5z12=d0->5z12=d1},[<ptr=r2,: 128]
+vld1.8 {d0-d1},[r2,: 128]
+
+# qhasm: r1[0,1] +=  x4[0] unsigned* 5z12[2]; r1[2,3] +=  x4[1] unsigned* 5z12[3]
+# asm 1: vmlal.u32 <r1=reg128#15,<x4=reg128#11%bot,<5z12=reg128#1%top
+# asm 2: vmlal.u32 <r1=q14,<x4=d20,<5z12=d1
+vmlal.u32 q14,d20,d1
+
+# qhasm:   		d23 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>d23=reg128#2%bot->d23=reg128#2%top},[<input_2=int32#2]!
+# asm 2: vld1.8 {>d23=d2->d23=d3},[<input_2=r1]!
+vld1.8 {d2-d3},[r1]!
+
+# qhasm:   		input_2 += 32
+# asm 1: add >input_2=int32#2,<input_2=int32#2,#32
+# asm 2: add >input_2=r1,<input_2=r1,#32
+add r1,r1,#32
+
+# qhasm: r0[0,1] +=  x4[0] unsigned* 5z12[0]; r0[2,3] +=  x4[1] unsigned* 5z12[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<x4=reg128#11%bot,<5z12=reg128#1%bot
+# asm 2: vmlal.u32 <r0=q7,<x4=d20,<5z12=d0
+vmlal.u32 q7,d20,d0
+
+# qhasm: r0[0,1] += x23[0] unsigned* 5z34[0]; r0[2,3] += x23[1] unsigned* 5z34[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<x23=reg128#10%bot,<5z34=reg128#6%bot
+# asm 2: vmlal.u32 <r0=q7,<x23=d18,<5z34=d10
+vmlal.u32 q7,d18,d10
+
+# qhasm:   		d01 d23 = d01[0] d23[0] d01[1] d23[1] 
+# asm 1: vswp <d23=reg128#2%bot,<d01=reg128#12%top
+# asm 2: vswp <d23=d2,<d01=d23
+vswp d2,d23
+
+# qhasm: r0[0,1] += x23[2] unsigned* 5z12[2]; r0[2,3] += x23[3] unsigned* 5z12[3]
+# asm 1: vmlal.u32 <r0=reg128#8,<x23=reg128#10%top,<5z12=reg128#1%top
+# asm 2: vmlal.u32 <r0=q7,<x23=d19,<5z12=d1
+vmlal.u32 q7,d19,d1
+
+# qhasm: r0[0,1] += x01[0] unsigned* z0[0];   r0[2,3] += x01[1] unsigned* z0[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<x01=reg128#9%bot,<z0=reg128#4%bot
+# asm 2: vmlal.u32 <r0=q7,<x01=d16,<z0=d6
+vmlal.u32 q7,d16,d6
+
+# qhasm:   		new mid
+
+# qhasm:   		2x v4 = d23 unsigned>> 40  
+# asm 1: vshr.u64 >v4=reg128#4,<d23=reg128#2,#40
+# asm 2: vshr.u64 >v4=q3,<d23=q1,#40
+vshr.u64 q3,q1,#40
+
+# qhasm:   		mid = d01[1]d23[0] mid[2,3] 
+# asm 1: vext.32 <mid=reg128#1%bot,<d01=reg128#12%bot,<d23=reg128#2%bot,#1
+# asm 2: vext.32 <mid=d0,<d01=d22,<d23=d2,#1
+vext.32 d0,d22,d2,#1
+
+# qhasm:   		new v23
+
+# qhasm:   		v23[2] = d23[0,1] unsigned>> 14; v23[3] = d23[2,3] unsigned>> 14
+# asm 1: vshrn.u64 <v23=reg128#10%top,<d23=reg128#2,#14
+# asm 2: vshrn.u64 <v23=d19,<d23=q1,#14
+vshrn.u64 d19,q1,#14
+
+# qhasm:   		mid = mid[0,1] d01[3]d23[2] 
+# asm 1: vext.32 <mid=reg128#1%top,<d01=reg128#12%top,<d23=reg128#2%top,#1
+# asm 2: vext.32 <mid=d1,<d01=d23,<d23=d3,#1
+vext.32 d1,d23,d3,#1
+
+# qhasm:   		new v01
+
+# qhasm:   		v01[2] = d01[0,1] unsigned>> 26; v01[3] = d01[2,3] unsigned>> 26
+# asm 1: vshrn.u64 <v01=reg128#11%top,<d01=reg128#12,#26
+# asm 2: vshrn.u64 <v01=d21,<d01=q11,#26
+vshrn.u64 d21,q11,#26
+
+# qhasm:   		v01 = d01[1]d01[0] v01[2,3] 
+# asm 1: vext.32 <v01=reg128#11%bot,<d01=reg128#12%bot,<d01=reg128#12%bot,#1
+# asm 2: vext.32 <v01=d20,<d01=d22,<d01=d22,#1
+vext.32 d20,d22,d22,#1
+
+# qhasm: r0[0,1] += x01[2] unsigned*  5z34[2]; r0[2,3] += x01[3] unsigned*  5z34[3]
+# asm 1: vmlal.u32 <r0=reg128#8,<x01=reg128#9%top,<5z34=reg128#6%top
+# asm 2: vmlal.u32 <r0=q7,<x01=d17,<5z34=d11
+vmlal.u32 q7,d17,d11
+
+# qhasm:   		v01 = v01[1]d01[2] v01[2,3] 
+# asm 1: vext.32 <v01=reg128#11%bot,<v01=reg128#11%bot,<d01=reg128#12%top,#1
+# asm 2: vext.32 <v01=d20,<v01=d20,<d01=d23,#1
+vext.32 d20,d20,d23,#1
+
+# qhasm:   		v23[0] = mid[0,1] unsigned>> 20; v23[1] = mid[2,3] unsigned>> 20
+# asm 1: vshrn.u64 <v23=reg128#10%bot,<mid=reg128#1,#20
+# asm 2: vshrn.u64 <v23=d18,<mid=q0,#20
+vshrn.u64 d18,q0,#20
+
+# qhasm:   		v4 = v4[0]v4[2]v4[1]v4[3]  
+# asm 1: vtrn.32 <v4=reg128#4%bot,<v4=reg128#4%top
+# asm 2: vtrn.32 <v4=d6,<v4=d7
+vtrn.32 d6,d7
+
+# qhasm:   		4x v01 &= 0x03ffffff
+# asm 1: vand.i32 <v01=reg128#11,#0x03ffffff
+# asm 2: vand.i32 <v01=q10,#0x03ffffff
+vand.i32 q10,#0x03ffffff
+
+# qhasm: ptr = &y34_stack
+# asm 1: lea >ptr=int32#3,<y34_stack=stack128#4
+# asm 2: lea >ptr=r2,<y34_stack=[sp,#48]
+add r2,sp,#48
+
+# qhasm: y34 aligned= mem128[ptr]
+# asm 1: vld1.8 {>y34=reg128#3%bot->y34=reg128#3%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>y34=d4->y34=d5},[<ptr=r2,: 128]
+vld1.8 {d4-d5},[r2,: 128]
+
+# qhasm:   		4x v23 &= 0x03ffffff
+# asm 1: vand.i32 <v23=reg128#10,#0x03ffffff
+# asm 2: vand.i32 <v23=q9,#0x03ffffff
+vand.i32 q9,#0x03ffffff
+
+# qhasm: ptr = &y12_stack
+# asm 1: lea >ptr=int32#3,<y12_stack=stack128#3
+# asm 2: lea >ptr=r2,<y12_stack=[sp,#32]
+add r2,sp,#32
+
+# qhasm: y12 aligned= mem128[ptr]
+# asm 1: vld1.8 {>y12=reg128#2%bot->y12=reg128#2%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>y12=d2->y12=d3},[<ptr=r2,: 128]
+vld1.8 {d2-d3},[r2,: 128]
+
+# qhasm:   		4x v4 |= 0x01000000
+# asm 1: vorr.i32 <v4=reg128#4,#0x01000000
+# asm 2: vorr.i32 <v4=q3,#0x01000000
+vorr.i32 q3,#0x01000000
+
+# qhasm: ptr = &y0_stack
+# asm 1: lea >ptr=int32#3,<y0_stack=stack128#2
+# asm 2: lea >ptr=r2,<y0_stack=[sp,#16]
+add r2,sp,#16
+
+# qhasm: y0 aligned= mem128[ptr]
+# asm 1: vld1.8 {>y0=reg128#1%bot->y0=reg128#1%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>y0=d0->y0=d1},[<ptr=r2,: 128]
+vld1.8 {d0-d1},[r2,: 128]
+
+# qhasm: r4[0,1] += v01[0] unsigned*  y34[2];  r4[2,3] += v01[1] unsigned*  y34[3]
+# asm 1: vmlal.u32 <r4=reg128#16,<v01=reg128#11%bot,<y34=reg128#3%top
+# asm 2: vmlal.u32 <r4=q15,<v01=d20,<y34=d5
+vmlal.u32 q15,d20,d5
+
+# qhasm: r4[0,1] += v01[2] unsigned* y34[0];  r4[2,3] += v01[3] unsigned* y34[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<v01=reg128#11%top,<y34=reg128#3%bot
+# asm 2: vmlal.u32 <r4=q15,<v01=d21,<y34=d4
+vmlal.u32 q15,d21,d4
+
+# qhasm: r4[0,1] += v23[0] unsigned* y12[2];  r4[2,3] += v23[1] unsigned* y12[3]
+# asm 1: vmlal.u32 <r4=reg128#16,<v23=reg128#10%bot,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r4=q15,<v23=d18,<y12=d3
+vmlal.u32 q15,d18,d3
+
+# qhasm: r4[0,1] += v23[2] unsigned* y12[0];  r4[2,3] += v23[3] unsigned* y12[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<v23=reg128#10%top,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r4=q15,<v23=d19,<y12=d2
+vmlal.u32 q15,d19,d2
+
+# qhasm: r4[0,1] +=  v4[0] unsigned* y0[0];  r4[2,3] +=  v4[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r4=reg128#16,<v4=reg128#4%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r4=q15,<v4=d6,<y0=d0
+vmlal.u32 q15,d6,d0
+
+# qhasm: ptr = &5y34_stack
+# asm 1: lea >ptr=int32#3,<5y34_stack=stack128#6
+# asm 2: lea >ptr=r2,<5y34_stack=[sp,#80]
+add r2,sp,#80
+
+# qhasm: 5y34 aligned= mem128[ptr]
+# asm 1: vld1.8 {>5y34=reg128#13%bot->5y34=reg128#13%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>5y34=d24->5y34=d25},[<ptr=r2,: 128]
+vld1.8 {d24-d25},[r2,: 128]
+
+# qhasm: r3[0,1] += v01[0] unsigned* y34[0];   r3[2,3] += v01[1] unsigned* y34[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<v01=reg128#11%bot,<y34=reg128#3%bot
+# asm 2: vmlal.u32 <r3=q4,<v01=d20,<y34=d4
+vmlal.u32 q4,d20,d4
+
+# qhasm: r3[0,1] += v01[2] unsigned* y12[2];   r3[2,3] += v01[3] unsigned* y12[3]
+# asm 1: vmlal.u32 <r3=reg128#5,<v01=reg128#11%top,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r3=q4,<v01=d21,<y12=d3
+vmlal.u32 q4,d21,d3
+
+# qhasm: r3[0,1] += v23[0] unsigned* y12[0];   r3[2,3] += v23[1] unsigned* y12[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<v23=reg128#10%bot,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r3=q4,<v23=d18,<y12=d2
+vmlal.u32 q4,d18,d2
+
+# qhasm: r3[0,1] += v23[2] unsigned* y0[0];   r3[2,3] += v23[3] unsigned* y0[1]
+# asm 1: vmlal.u32 <r3=reg128#5,<v23=reg128#10%top,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r3=q4,<v23=d19,<y0=d0
+vmlal.u32 q4,d19,d0
+
+# qhasm: r3[0,1] +=  v4[0] unsigned*  5y34[2]; r3[2,3] +=  v4[1] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r3=reg128#5,<v4=reg128#4%bot,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r3=q4,<v4=d6,<5y34=d25
+vmlal.u32 q4,d6,d25
+
+# qhasm: ptr = &5y12_stack
+# asm 1: lea >ptr=int32#3,<5y12_stack=stack128#5
+# asm 2: lea >ptr=r2,<5y12_stack=[sp,#64]
+add r2,sp,#64
+
+# qhasm: 5y12 aligned= mem128[ptr]
+# asm 1: vld1.8 {>5y12=reg128#12%bot->5y12=reg128#12%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>5y12=d22->5y12=d23},[<ptr=r2,: 128]
+vld1.8 {d22-d23},[r2,: 128]
+
+# qhasm: r0[0,1] +=  v4[0] unsigned* 5y12[0]; r0[2,3] +=  v4[1] unsigned* 5y12[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<v4=reg128#4%bot,<5y12=reg128#12%bot
+# asm 2: vmlal.u32 <r0=q7,<v4=d6,<5y12=d22
+vmlal.u32 q7,d6,d22
+
+# qhasm: r0[0,1] += v23[0] unsigned* 5y34[0]; r0[2,3] += v23[1] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<v23=reg128#10%bot,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r0=q7,<v23=d18,<5y34=d24
+vmlal.u32 q7,d18,d24
+
+# qhasm: r0[0,1] += v23[2] unsigned* 5y12[2]; r0[2,3] += v23[3] unsigned* 5y12[3]
+# asm 1: vmlal.u32 <r0=reg128#8,<v23=reg128#10%top,<5y12=reg128#12%top
+# asm 2: vmlal.u32 <r0=q7,<v23=d19,<5y12=d23
+vmlal.u32 q7,d19,d23
+
+# qhasm: r0[0,1] += v01[0] unsigned* y0[0];   r0[2,3] += v01[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r0=reg128#8,<v01=reg128#11%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r0=q7,<v01=d20,<y0=d0
+vmlal.u32 q7,d20,d0
+
+# qhasm: r0[0,1] += v01[2] unsigned*  5y34[2]; r0[2,3] += v01[3] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r0=reg128#8,<v01=reg128#11%top,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r0=q7,<v01=d21,<5y34=d25
+vmlal.u32 q7,d21,d25
+
+# qhasm: r1[0,1] += v01[0] unsigned* y12[0];   r1[2,3] += v01[1] unsigned* y12[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<v01=reg128#11%bot,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r1=q14,<v01=d20,<y12=d2
+vmlal.u32 q14,d20,d2
+
+# qhasm: r1[0,1] += v01[2] unsigned* y0[0];   r1[2,3] += v01[3] unsigned* y0[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<v01=reg128#11%top,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r1=q14,<v01=d21,<y0=d0
+vmlal.u32 q14,d21,d0
+
+# qhasm: r1[0,1] += v23[0] unsigned*  5y34[2]; r1[2,3] += v23[1] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r1=reg128#15,<v23=reg128#10%bot,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r1=q14,<v23=d18,<5y34=d25
+vmlal.u32 q14,d18,d25
+
+# qhasm: r1[0,1] += v23[2] unsigned* 5y34[0]; r1[2,3] += v23[3] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r1=reg128#15,<v23=reg128#10%top,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r1=q14,<v23=d19,<5y34=d24
+vmlal.u32 q14,d19,d24
+
+# qhasm: r1[0,1] +=  v4[0] unsigned* 5y12[2]; r1[2,3] +=  v4[1] unsigned* 5y12[3]
+# asm 1: vmlal.u32 <r1=reg128#15,<v4=reg128#4%bot,<5y12=reg128#12%top
+# asm 2: vmlal.u32 <r1=q14,<v4=d6,<5y12=d23
+vmlal.u32 q14,d6,d23
+
+# qhasm: r2[0,1] += v01[0] unsigned* y12[2];   r2[2,3] += v01[1] unsigned* y12[3]
+# asm 1: vmlal.u32 <r2=reg128#14,<v01=reg128#11%bot,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r2=q13,<v01=d20,<y12=d3
+vmlal.u32 q13,d20,d3
+
+# qhasm: r2[0,1] += v01[2] unsigned* y12[0];   r2[2,3] += v01[3] unsigned* y12[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<v01=reg128#11%top,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r2=q13,<v01=d21,<y12=d2
+vmlal.u32 q13,d21,d2
+
+# qhasm: r2[0,1] += v23[0] unsigned* y0[0];   r2[2,3] += v23[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<v23=reg128#10%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r2=q13,<v23=d18,<y0=d0
+vmlal.u32 q13,d18,d0
+
+# qhasm: r2[0,1] += v23[2] unsigned*  5y34[2]; r2[2,3] += v23[3] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r2=reg128#14,<v23=reg128#10%top,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r2=q13,<v23=d19,<5y34=d25
+vmlal.u32 q13,d19,d25
+
+# qhasm: r2[0,1] +=  v4[0] unsigned* 5y34[0]; r2[2,3] +=  v4[1] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r2=reg128#14,<v4=reg128#4%bot,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r2=q13,<v4=d6,<5y34=d24
+vmlal.u32 q13,d6,d24
+
+# qhasm: 				ptr = &two24
+# asm 1: lea >ptr=int32#3,<two24=stack128#1
+# asm 2: lea >ptr=r2,<two24=[sp,#0]
+add r2,sp,#0
+
+# qhasm: 2x t1 = r0 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#4,<r0=reg128#8,#26
+# asm 2: vshr.u64 >t1=q3,<r0=q7,#26
+vshr.u64 q3,q7,#26
+
+# qhasm:   				len -= 64
+# asm 1: sub >len=int32#4,<len=int32#4,#64
+# asm 2: sub >len=r3,<len=r3,#64
+sub r3,r3,#64
+
+# qhasm:    r0 &= mask
+# asm 1: vand >r0=reg128#6,<r0=reg128#8,<mask=reg128#7
+# asm 2: vand >r0=q5,<r0=q7,<mask=q6
+vand q5,q7,q6
+
+# qhasm: 2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#4,<r1=reg128#15,<t1=reg128#4
+# asm 2: vadd.i64 >r1=q3,<r1=q14,<t1=q3
+vadd.i64 q3,q14,q3
+
+# qhasm: 		2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#8,<r3=reg128#5,#26
+# asm 2: vshr.u64 >t4=q7,<r3=q4,#26
+vshr.u64 q7,q4,#26
+
+# qhasm: 		   r3 &= mask
+# asm 1: vand >r3=reg128#5,<r3=reg128#5,<mask=reg128#7
+# asm 2: vand >r3=q4,<r3=q4,<mask=q6
+vand q4,q4,q6
+
+# qhasm: 		2x x4 = r4 + t4
+# asm 1: vadd.i64 >x4=reg128#8,<r4=reg128#16,<t4=reg128#8
+# asm 2: vadd.i64 >x4=q7,<r4=q15,<t4=q7
+vadd.i64 q7,q15,q7
+
+# qhasm: 				r4 aligned= mem128[ptr]
+# asm 1: vld1.8 {>r4=reg128#16%bot->r4=reg128#16%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>r4=d30->r4=d31},[<ptr=r2,: 128]
+vld1.8 {d30-d31},[r2,: 128]
+
+# qhasm: 2x t2 = r1 unsigned>> 26
+# asm 1: vshr.u64 >t2=reg128#9,<r1=reg128#4,#26
+# asm 2: vshr.u64 >t2=q8,<r1=q3,#26
+vshr.u64 q8,q3,#26
+
+# qhasm:    r1 &= mask
+# asm 1: vand >r1=reg128#4,<r1=reg128#4,<mask=reg128#7
+# asm 2: vand >r1=q3,<r1=q3,<mask=q6
+vand q3,q3,q6
+
+# qhasm: 		2x t0 = x4 unsigned>> 26
+# asm 1: vshr.u64 >t0=reg128#10,<x4=reg128#8,#26
+# asm 2: vshr.u64 >t0=q9,<x4=q7,#26
+vshr.u64 q9,q7,#26
+
+# qhasm: 2x r2 += t2
+# asm 1: vadd.i64 >r2=reg128#9,<r2=reg128#14,<t2=reg128#9
+# asm 2: vadd.i64 >r2=q8,<r2=q13,<t2=q8
+vadd.i64 q8,q13,q8
+
+# qhasm: 		   x4 &= mask
+# asm 1: vand >x4=reg128#11,<x4=reg128#8,<mask=reg128#7
+# asm 2: vand >x4=q10,<x4=q7,<mask=q6
+vand q10,q7,q6
+
+# qhasm: 		2x x01 = r0 + t0
+# asm 1: vadd.i64 >x01=reg128#6,<r0=reg128#6,<t0=reg128#10
+# asm 2: vadd.i64 >x01=q5,<r0=q5,<t0=q9
+vadd.i64 q5,q5,q9
+
+# qhasm: 				r0 aligned= mem128[ptr]
+# asm 1: vld1.8 {>r0=reg128#8%bot->r0=reg128#8%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>r0=d14->r0=d15},[<ptr=r2,: 128]
+vld1.8 {d14-d15},[r2,: 128]
+
+# qhasm: 				ptr = &z34_stack
+# asm 1: lea >ptr=int32#3,<z34_stack=stack128#9
+# asm 2: lea >ptr=r2,<z34_stack=[sp,#128]
+add r2,sp,#128
+
+# qhasm: 		2x t0 <<= 2
+# asm 1: vshl.i64 >t0=reg128#10,<t0=reg128#10,#2
+# asm 2: vshl.i64 >t0=q9,<t0=q9,#2
+vshl.i64 q9,q9,#2
+
+# qhasm: 2x t3 = r2 unsigned>> 26
+# asm 1: vshr.u64 >t3=reg128#14,<r2=reg128#9,#26
+# asm 2: vshr.u64 >t3=q13,<r2=q8,#26
+vshr.u64 q13,q8,#26
+
+# qhasm: 		2x x01 += t0
+# asm 1: vadd.i64 >x01=reg128#15,<x01=reg128#6,<t0=reg128#10
+# asm 2: vadd.i64 >x01=q14,<x01=q5,<t0=q9
+vadd.i64 q14,q5,q9
+
+# qhasm: 				z34 aligned= mem128[ptr]
+# asm 1: vld1.8 {>z34=reg128#6%bot->z34=reg128#6%top},[<ptr=int32#3,: 128]
+# asm 2: vld1.8 {>z34=d10->z34=d11},[<ptr=r2,: 128]
+vld1.8 {d10-d11},[r2,: 128]
+
+# qhasm:    x23 = r2 & mask
+# asm 1: vand >x23=reg128#10,<r2=reg128#9,<mask=reg128#7
+# asm 2: vand >x23=q9,<r2=q8,<mask=q6
+vand q9,q8,q6
+
+# qhasm: 2x r3 += t3
+# asm 1: vadd.i64 >r3=reg128#5,<r3=reg128#5,<t3=reg128#14
+# asm 2: vadd.i64 >r3=q4,<r3=q4,<t3=q13
+vadd.i64 q4,q4,q13
+
+# qhasm: 								input_2 += 32
+# asm 1: add >input_2=int32#2,<input_2=int32#2,#32
+# asm 2: add >input_2=r1,<input_2=r1,#32
+add r1,r1,#32
+
+# qhasm: 		2x t1 = x01 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#14,<x01=reg128#15,#26
+# asm 2: vshr.u64 >t1=q13,<x01=q14,#26
+vshr.u64 q13,q14,#26
+
+# qhasm: 						x23 = x23[0,2,1,3]
+# asm 1: vtrn.32 <x23=reg128#10%bot,<x23=reg128#10%top
+# asm 2: vtrn.32 <x23=d18,<x23=d19
+vtrn.32 d18,d19
+
+# qhasm: 		   x01 = x01 & mask
+# asm 1: vand >x01=reg128#9,<x01=reg128#15,<mask=reg128#7
+# asm 2: vand >x01=q8,<x01=q14,<mask=q6
+vand q8,q14,q6
+
+# qhasm: 		2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#4,<r1=reg128#4,<t1=reg128#14
+# asm 2: vadd.i64 >r1=q3,<r1=q3,<t1=q13
+vadd.i64 q3,q3,q13
+
+# qhasm: 2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#14,<r3=reg128#5,#26
+# asm 2: vshr.u64 >t4=q13,<r3=q4,#26
+vshr.u64 q13,q4,#26
+
+# qhasm: 						x01 = x01[0,2,1,3]
+# asm 1: vtrn.32 <x01=reg128#9%bot,<x01=reg128#9%top
+# asm 2: vtrn.32 <x01=d16,<x01=d17
+vtrn.32 d16,d17
+
+# qhasm:    r3 &= mask
+# asm 1: vand >r3=reg128#5,<r3=reg128#5,<mask=reg128#7
+# asm 2: vand >r3=q4,<r3=q4,<mask=q6
+vand q4,q4,q6
+
+# qhasm: 						r1 = r1[0,2,1,3]
+# asm 1: vtrn.32 <r1=reg128#4%bot,<r1=reg128#4%top
+# asm 2: vtrn.32 <r1=d6,<r1=d7
+vtrn.32 d6,d7
+
+# qhasm: 2x x4 += t4
+# asm 1: vadd.i64 >x4=reg128#11,<x4=reg128#11,<t4=reg128#14
+# asm 2: vadd.i64 >x4=q10,<x4=q10,<t4=q13
+vadd.i64 q10,q10,q13
+
+# qhasm: 						r3 = r3[0,2,1,3]
+# asm 1: vtrn.32 <r3=reg128#5%bot,<r3=reg128#5%top
+# asm 2: vtrn.32 <r3=d8,<r3=d9
+vtrn.32 d8,d9
+
+# qhasm: 						x01 = x01[0,1] r1[0,1]
+# asm 1: vext.32 <x01=reg128#9%top,<r1=reg128#4%bot,<r1=reg128#4%bot,#0
+# asm 2: vext.32 <x01=d17,<r1=d6,<r1=d6,#0
+vext.32 d17,d6,d6,#0
+
+# qhasm: 						x23 = x23[0,1] r3[0,1]
+# asm 1: vext.32 <x23=reg128#10%top,<r3=reg128#5%bot,<r3=reg128#5%bot,#0
+# asm 2: vext.32 <x23=d19,<r3=d8,<r3=d8,#0
+vext.32 d19,d8,d8,#0
+
+# qhasm: 						x4 = x4[0,2,1,3]
+# asm 1: vtrn.32 <x4=reg128#11%bot,<x4=reg128#11%top
+# asm 2: vtrn.32 <x4=d20,<x4=d21
+vtrn.32 d20,d21
+
+# qhasm:                   unsigned>? len - 64
+# asm 1: cmp <len=int32#4,#64
+# asm 2: cmp <len=r3,#64
+cmp r3,#64
+
+# qhasm: goto mainloop2 if unsigned>
+bhi ._mainloop2
+
+# qhasm: input_2 -= 32
+# asm 1: sub >input_2=int32#3,<input_2=int32#2,#32
+# asm 2: sub >input_2=r2,<input_2=r1,#32
+sub r2,r1,#32
+
+# qhasm: below64bytes:
+._below64bytes:
+
+# qhasm:              unsigned>? len - 32
+# asm 1: cmp <len=int32#4,#32
+# asm 2: cmp <len=r3,#32
+cmp r3,#32
+
+# qhasm: goto end if !unsigned>
+bls ._end
+
+# qhasm: mainloop:
+._mainloop:
+
+# qhasm:   new r0
+
+# qhasm: ptr = &two24
+# asm 1: lea >ptr=int32#2,<two24=stack128#1
+# asm 2: lea >ptr=r1,<two24=[sp,#0]
+add r1,sp,#0
+
+# qhasm: r4 aligned= mem128[ptr]
+# asm 1: vld1.8 {>r4=reg128#5%bot->r4=reg128#5%top},[<ptr=int32#2,: 128]
+# asm 2: vld1.8 {>r4=d8->r4=d9},[<ptr=r1,: 128]
+vld1.8 {d8-d9},[r1,: 128]
+
+# qhasm: u4 aligned= mem128[ptr]
+# asm 1: vld1.8 {>u4=reg128#6%bot->u4=reg128#6%top},[<ptr=int32#2,: 128]
+# asm 2: vld1.8 {>u4=d10->u4=d11},[<ptr=r1,: 128]
+vld1.8 {d10-d11},[r1,: 128]
+
+# qhasm:   c01 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>c01=reg128#8%bot->c01=reg128#8%top},[<input_2=int32#3]!
+# asm 2: vld1.8 {>c01=d14->c01=d15},[<input_2=r2]!
+vld1.8 {d14-d15},[r2]!
+
+# qhasm: r4[0,1] += x01[0] unsigned*  y34[2];  r4[2,3] += x01[1] unsigned*  y34[3]
+# asm 1: vmlal.u32 <r4=reg128#5,<x01=reg128#9%bot,<y34=reg128#3%top
+# asm 2: vmlal.u32 <r4=q4,<x01=d16,<y34=d5
+vmlal.u32 q4,d16,d5
+
+# qhasm:   c23 = mem128[input_2];input_2+=16 
+# asm 1: vld1.8 {>c23=reg128#14%bot->c23=reg128#14%top},[<input_2=int32#3]!
+# asm 2: vld1.8 {>c23=d26->c23=d27},[<input_2=r2]!
+vld1.8 {d26-d27},[r2]!
+
+# qhasm: r4[0,1] += x01[2] unsigned* y34[0];  r4[2,3] += x01[3] unsigned* y34[1]
+# asm 1: vmlal.u32 <r4=reg128#5,<x01=reg128#9%top,<y34=reg128#3%bot
+# asm 2: vmlal.u32 <r4=q4,<x01=d17,<y34=d4
+vmlal.u32 q4,d17,d4
+
+# qhasm:   r0 = u4[1]c01[0]r0[2,3] 
+# asm 1: vext.32 <r0=reg128#4%bot,<u4=reg128#6%bot,<c01=reg128#8%bot,#1
+# asm 2: vext.32 <r0=d6,<u4=d10,<c01=d14,#1
+vext.32 d6,d10,d14,#1
+
+# qhasm: r4[0,1] += x23[0] unsigned* y12[2];  r4[2,3] += x23[1] unsigned* y12[3]
+# asm 1: vmlal.u32 <r4=reg128#5,<x23=reg128#10%bot,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r4=q4,<x23=d18,<y12=d3
+vmlal.u32 q4,d18,d3
+
+# qhasm:   r0 = r0[0,1]u4[1]c23[0] 
+# asm 1: vext.32 <r0=reg128#4%top,<u4=reg128#6%bot,<c23=reg128#14%bot,#1
+# asm 2: vext.32 <r0=d7,<u4=d10,<c23=d26,#1
+vext.32 d7,d10,d26,#1
+
+# qhasm: r4[0,1] += x23[2] unsigned* y12[0];  r4[2,3] += x23[3] unsigned* y12[1]
+# asm 1: vmlal.u32 <r4=reg128#5,<x23=reg128#10%top,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r4=q4,<x23=d19,<y12=d2
+vmlal.u32 q4,d19,d2
+
+# qhasm:   r0 = r0[1]r0[0]r0[3]r0[2] 
+# asm 1: vrev64.i32 >r0=reg128#4,<r0=reg128#4
+# asm 2: vrev64.i32 >r0=q3,<r0=q3
+vrev64.i32 q3,q3
+
+# qhasm: r4[0,1] +=  x4[0] unsigned* y0[0];  r4[2,3] +=  x4[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r4=reg128#5,<x4=reg128#11%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r4=q4,<x4=d20,<y0=d0
+vmlal.u32 q4,d20,d0
+
+# qhasm: r0[0,1] +=  x4[0] unsigned* 5y12[0]; r0[2,3] +=  x4[1] unsigned* 5y12[1]
+# asm 1: vmlal.u32 <r0=reg128#4,<x4=reg128#11%bot,<5y12=reg128#12%bot
+# asm 2: vmlal.u32 <r0=q3,<x4=d20,<5y12=d22
+vmlal.u32 q3,d20,d22
+
+# qhasm: r0[0,1] += x23[0] unsigned* 5y34[0]; r0[2,3] += x23[1] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r0=reg128#4,<x23=reg128#10%bot,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r0=q3,<x23=d18,<5y34=d24
+vmlal.u32 q3,d18,d24
+
+# qhasm: r0[0,1] += x23[2] unsigned* 5y12[2]; r0[2,3] += x23[3] unsigned* 5y12[3]
+# asm 1: vmlal.u32 <r0=reg128#4,<x23=reg128#10%top,<5y12=reg128#12%top
+# asm 2: vmlal.u32 <r0=q3,<x23=d19,<5y12=d23
+vmlal.u32 q3,d19,d23
+
+# qhasm:   c01 c23 = c01[0]c23[0]c01[2]c23[2]c01[1]c23[1]c01[3]c23[3] 
+# asm 1: vtrn.32 <c01=reg128#8,<c23=reg128#14
+# asm 2: vtrn.32 <c01=q7,<c23=q13
+vtrn.32 q7,q13
+
+# qhasm: r0[0,1] += x01[0] unsigned* y0[0];   r0[2,3] += x01[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r0=reg128#4,<x01=reg128#9%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r0=q3,<x01=d16,<y0=d0
+vmlal.u32 q3,d16,d0
+
+# qhasm:   r3[0,1] = c23[2]<<18; r3[2,3] = c23[3]<<18 
+# asm 1: vshll.u32 >r3=reg128#6,<c23=reg128#14%top,#18
+# asm 2: vshll.u32 >r3=q5,<c23=d27,#18
+vshll.u32 q5,d27,#18
+
+# qhasm: r0[0,1] += x01[2] unsigned*  5y34[2]; r0[2,3] += x01[3] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r0=reg128#4,<x01=reg128#9%top,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r0=q3,<x01=d17,<5y34=d25
+vmlal.u32 q3,d17,d25
+
+# qhasm: r3[0,1] += x01[0] unsigned* y34[0];   r3[2,3] += x01[1] unsigned* y34[1]
+# asm 1: vmlal.u32 <r3=reg128#6,<x01=reg128#9%bot,<y34=reg128#3%bot
+# asm 2: vmlal.u32 <r3=q5,<x01=d16,<y34=d4
+vmlal.u32 q5,d16,d4
+
+# qhasm: r3[0,1] += x01[2] unsigned* y12[2];   r3[2,3] += x01[3] unsigned* y12[3]
+# asm 1: vmlal.u32 <r3=reg128#6,<x01=reg128#9%top,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r3=q5,<x01=d17,<y12=d3
+vmlal.u32 q5,d17,d3
+
+# qhasm: r3[0,1] += x23[0] unsigned* y12[0];   r3[2,3] += x23[1] unsigned* y12[1]
+# asm 1: vmlal.u32 <r3=reg128#6,<x23=reg128#10%bot,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r3=q5,<x23=d18,<y12=d2
+vmlal.u32 q5,d18,d2
+
+# qhasm: r3[0,1] += x23[2] unsigned* y0[0];   r3[2,3] += x23[3] unsigned* y0[1]
+# asm 1: vmlal.u32 <r3=reg128#6,<x23=reg128#10%top,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r3=q5,<x23=d19,<y0=d0
+vmlal.u32 q5,d19,d0
+
+# qhasm:   r1[0,1] = c23[0]<<6; r1[2,3] = c23[1]<<6 
+# asm 1: vshll.u32 >r1=reg128#14,<c23=reg128#14%bot,#6
+# asm 2: vshll.u32 >r1=q13,<c23=d26,#6
+vshll.u32 q13,d26,#6
+
+# qhasm: r3[0,1] +=  x4[0] unsigned*  5y34[2]; r3[2,3] +=  x4[1] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r3=reg128#6,<x4=reg128#11%bot,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r3=q5,<x4=d20,<5y34=d25
+vmlal.u32 q5,d20,d25
+
+# qhasm: r1[0,1] += x01[0] unsigned* y12[0];   r1[2,3] += x01[1] unsigned* y12[1]
+# asm 1: vmlal.u32 <r1=reg128#14,<x01=reg128#9%bot,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r1=q13,<x01=d16,<y12=d2
+vmlal.u32 q13,d16,d2
+
+# qhasm: r1[0,1] += x01[2] unsigned* y0[0];   r1[2,3] += x01[3] unsigned* y0[1]
+# asm 1: vmlal.u32 <r1=reg128#14,<x01=reg128#9%top,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r1=q13,<x01=d17,<y0=d0
+vmlal.u32 q13,d17,d0
+
+# qhasm: r1[0,1] += x23[0] unsigned*  5y34[2]; r1[2,3] += x23[1] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r1=reg128#14,<x23=reg128#10%bot,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r1=q13,<x23=d18,<5y34=d25
+vmlal.u32 q13,d18,d25
+
+# qhasm: r1[0,1] += x23[2] unsigned* 5y34[0]; r1[2,3] += x23[3] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r1=reg128#14,<x23=reg128#10%top,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r1=q13,<x23=d19,<5y34=d24
+vmlal.u32 q13,d19,d24
+
+# qhasm:   r2[0,1] = c01[2]<<12; r2[2,3] = c01[3]<<12 
+# asm 1: vshll.u32 >r2=reg128#8,<c01=reg128#8%top,#12
+# asm 2: vshll.u32 >r2=q7,<c01=d15,#12
+vshll.u32 q7,d15,#12
+
+# qhasm: r1[0,1] +=  x4[0] unsigned* 5y12[2]; r1[2,3] +=  x4[1] unsigned* 5y12[3]
+# asm 1: vmlal.u32 <r1=reg128#14,<x4=reg128#11%bot,<5y12=reg128#12%top
+# asm 2: vmlal.u32 <r1=q13,<x4=d20,<5y12=d23
+vmlal.u32 q13,d20,d23
+
+# qhasm: r2[0,1] += x01[0] unsigned* y12[2];   r2[2,3] += x01[1] unsigned* y12[3]
+# asm 1: vmlal.u32 <r2=reg128#8,<x01=reg128#9%bot,<y12=reg128#2%top
+# asm 2: vmlal.u32 <r2=q7,<x01=d16,<y12=d3
+vmlal.u32 q7,d16,d3
+
+# qhasm: r2[0,1] += x01[2] unsigned* y12[0];   r2[2,3] += x01[3] unsigned* y12[1]
+# asm 1: vmlal.u32 <r2=reg128#8,<x01=reg128#9%top,<y12=reg128#2%bot
+# asm 2: vmlal.u32 <r2=q7,<x01=d17,<y12=d2
+vmlal.u32 q7,d17,d2
+
+# qhasm: r2[0,1] += x23[0] unsigned* y0[0];   r2[2,3] += x23[1] unsigned* y0[1]
+# asm 1: vmlal.u32 <r2=reg128#8,<x23=reg128#10%bot,<y0=reg128#1%bot
+# asm 2: vmlal.u32 <r2=q7,<x23=d18,<y0=d0
+vmlal.u32 q7,d18,d0
+
+# qhasm: r2[0,1] += x23[2] unsigned*  5y34[2]; r2[2,3] += x23[3] unsigned*  5y34[3]
+# asm 1: vmlal.u32 <r2=reg128#8,<x23=reg128#10%top,<5y34=reg128#13%top
+# asm 2: vmlal.u32 <r2=q7,<x23=d19,<5y34=d25
+vmlal.u32 q7,d19,d25
+
+# qhasm: r2[0,1] +=  x4[0] unsigned* 5y34[0]; r2[2,3] +=  x4[1] unsigned* 5y34[1]
+# asm 1: vmlal.u32 <r2=reg128#8,<x4=reg128#11%bot,<5y34=reg128#13%bot
+# asm 2: vmlal.u32 <r2=q7,<x4=d20,<5y34=d24
+vmlal.u32 q7,d20,d24
+
+# qhasm: 2x t1 = r0 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#9,<r0=reg128#4,#26
+# asm 2: vshr.u64 >t1=q8,<r0=q3,#26
+vshr.u64 q8,q3,#26
+
+# qhasm:    r0 &= mask
+# asm 1: vand >r0=reg128#4,<r0=reg128#4,<mask=reg128#7
+# asm 2: vand >r0=q3,<r0=q3,<mask=q6
+vand q3,q3,q6
+
+# qhasm: 2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#9,<r1=reg128#14,<t1=reg128#9
+# asm 2: vadd.i64 >r1=q8,<r1=q13,<t1=q8
+vadd.i64 q8,q13,q8
+
+# qhasm: 		2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#10,<r3=reg128#6,#26
+# asm 2: vshr.u64 >t4=q9,<r3=q5,#26
+vshr.u64 q9,q5,#26
+
+# qhasm: 		   r3 &= mask
+# asm 1: vand >r3=reg128#6,<r3=reg128#6,<mask=reg128#7
+# asm 2: vand >r3=q5,<r3=q5,<mask=q6
+vand q5,q5,q6
+
+# qhasm: 		2x r4 += t4
+# asm 1: vadd.i64 >r4=reg128#5,<r4=reg128#5,<t4=reg128#10
+# asm 2: vadd.i64 >r4=q4,<r4=q4,<t4=q9
+vadd.i64 q4,q4,q9
+
+# qhasm: 2x t2 = r1 unsigned>> 26
+# asm 1: vshr.u64 >t2=reg128#10,<r1=reg128#9,#26
+# asm 2: vshr.u64 >t2=q9,<r1=q8,#26
+vshr.u64 q9,q8,#26
+
+# qhasm:    r1 &= mask
+# asm 1: vand >r1=reg128#11,<r1=reg128#9,<mask=reg128#7
+# asm 2: vand >r1=q10,<r1=q8,<mask=q6
+vand q10,q8,q6
+
+# qhasm: 		2x t0 = r4 unsigned>> 26
+# asm 1: vshr.u64 >t0=reg128#9,<r4=reg128#5,#26
+# asm 2: vshr.u64 >t0=q8,<r4=q4,#26
+vshr.u64 q8,q4,#26
+
+# qhasm: 2x r2 += t2
+# asm 1: vadd.i64 >r2=reg128#8,<r2=reg128#8,<t2=reg128#10
+# asm 2: vadd.i64 >r2=q7,<r2=q7,<t2=q9
+vadd.i64 q7,q7,q9
+
+# qhasm: 		   r4 &= mask
+# asm 1: vand >r4=reg128#5,<r4=reg128#5,<mask=reg128#7
+# asm 2: vand >r4=q4,<r4=q4,<mask=q6
+vand q4,q4,q6
+
+# qhasm: 		2x r0 += t0
+# asm 1: vadd.i64 >r0=reg128#4,<r0=reg128#4,<t0=reg128#9
+# asm 2: vadd.i64 >r0=q3,<r0=q3,<t0=q8
+vadd.i64 q3,q3,q8
+
+# qhasm: 		2x t0 <<= 2
+# asm 1: vshl.i64 >t0=reg128#9,<t0=reg128#9,#2
+# asm 2: vshl.i64 >t0=q8,<t0=q8,#2
+vshl.i64 q8,q8,#2
+
+# qhasm: 2x t3 = r2 unsigned>> 26
+# asm 1: vshr.u64 >t3=reg128#14,<r2=reg128#8,#26
+# asm 2: vshr.u64 >t3=q13,<r2=q7,#26
+vshr.u64 q13,q7,#26
+
+# qhasm: 		2x r0 += t0
+# asm 1: vadd.i64 >r0=reg128#4,<r0=reg128#4,<t0=reg128#9
+# asm 2: vadd.i64 >r0=q3,<r0=q3,<t0=q8
+vadd.i64 q3,q3,q8
+
+# qhasm:    x23 = r2 & mask
+# asm 1: vand >x23=reg128#10,<r2=reg128#8,<mask=reg128#7
+# asm 2: vand >x23=q9,<r2=q7,<mask=q6
+vand q9,q7,q6
+
+# qhasm: 2x r3 += t3
+# asm 1: vadd.i64 >r3=reg128#6,<r3=reg128#6,<t3=reg128#14
+# asm 2: vadd.i64 >r3=q5,<r3=q5,<t3=q13
+vadd.i64 q5,q5,q13
+
+# qhasm: 		2x t1 = r0 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#8,<r0=reg128#4,#26
+# asm 2: vshr.u64 >t1=q7,<r0=q3,#26
+vshr.u64 q7,q3,#26
+
+# qhasm: 		   x01 = r0 & mask
+# asm 1: vand >x01=reg128#9,<r0=reg128#4,<mask=reg128#7
+# asm 2: vand >x01=q8,<r0=q3,<mask=q6
+vand q8,q3,q6
+
+# qhasm: 		2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#4,<r1=reg128#11,<t1=reg128#8
+# asm 2: vadd.i64 >r1=q3,<r1=q10,<t1=q7
+vadd.i64 q3,q10,q7
+
+# qhasm: 2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#8,<r3=reg128#6,#26
+# asm 2: vshr.u64 >t4=q7,<r3=q5,#26
+vshr.u64 q7,q5,#26
+
+# qhasm:    r3 &= mask
+# asm 1: vand >r3=reg128#6,<r3=reg128#6,<mask=reg128#7
+# asm 2: vand >r3=q5,<r3=q5,<mask=q6
+vand q5,q5,q6
+
+# qhasm: 2x x4 = r4 + t4
+# asm 1: vadd.i64 >x4=reg128#11,<r4=reg128#5,<t4=reg128#8
+# asm 2: vadd.i64 >x4=q10,<r4=q4,<t4=q7
+vadd.i64 q10,q4,q7
+
+# qhasm:   len -= 32
+# asm 1: sub >len=int32#4,<len=int32#4,#32
+# asm 2: sub >len=r3,<len=r3,#32
+sub r3,r3,#32
+
+# qhasm: x01 = x01[0,2,1,3]
+# asm 1: vtrn.32 <x01=reg128#9%bot,<x01=reg128#9%top
+# asm 2: vtrn.32 <x01=d16,<x01=d17
+vtrn.32 d16,d17
+
+# qhasm: x23 = x23[0,2,1,3]
+# asm 1: vtrn.32 <x23=reg128#10%bot,<x23=reg128#10%top
+# asm 2: vtrn.32 <x23=d18,<x23=d19
+vtrn.32 d18,d19
+
+# qhasm: r1 = r1[0,2,1,3]
+# asm 1: vtrn.32 <r1=reg128#4%bot,<r1=reg128#4%top
+# asm 2: vtrn.32 <r1=d6,<r1=d7
+vtrn.32 d6,d7
+
+# qhasm: r3 = r3[0,2,1,3]
+# asm 1: vtrn.32 <r3=reg128#6%bot,<r3=reg128#6%top
+# asm 2: vtrn.32 <r3=d10,<r3=d11
+vtrn.32 d10,d11
+
+# qhasm: x4 = x4[0,2,1,3]
+# asm 1: vtrn.32 <x4=reg128#11%bot,<x4=reg128#11%top
+# asm 2: vtrn.32 <x4=d20,<x4=d21
+vtrn.32 d20,d21
+
+# qhasm: x01 = x01[0,1] r1[0,1]
+# asm 1: vext.32 <x01=reg128#9%top,<r1=reg128#4%bot,<r1=reg128#4%bot,#0
+# asm 2: vext.32 <x01=d17,<r1=d6,<r1=d6,#0
+vext.32 d17,d6,d6,#0
+
+# qhasm: x23 = x23[0,1] r3[0,1]
+# asm 1: vext.32 <x23=reg128#10%top,<r3=reg128#6%bot,<r3=reg128#6%bot,#0
+# asm 2: vext.32 <x23=d19,<r3=d10,<r3=d10,#0
+vext.32 d19,d10,d10,#0
+
+# qhasm: unsigned>? len - 32
+# asm 1: cmp <len=int32#4,#32
+# asm 2: cmp <len=r3,#32
+cmp r3,#32
+
+# qhasm: goto mainloop if unsigned>
+bhi ._mainloop
+
+# qhasm: end:
+._end:
+
+# qhasm: mem128[input_0] = x01;input_0+=16
+# asm 1: vst1.8 {<x01=reg128#9%bot-<x01=reg128#9%top},[<input_0=int32#1]!
+# asm 2: vst1.8 {<x01=d16-<x01=d17},[<input_0=r0]!
+vst1.8 {d16-d17},[r0]!
+
+# qhasm: mem128[input_0] = x23;input_0+=16
+# asm 1: vst1.8 {<x23=reg128#10%bot-<x23=reg128#10%top},[<input_0=int32#1]!
+# asm 2: vst1.8 {<x23=d18-<x23=d19},[<input_0=r0]!
+vst1.8 {d18-d19},[r0]!
+
+# qhasm: mem64[input_0] = x4[0]
+# asm 1: vst1.8 <x4=reg128#11%bot,[<input_0=int32#1]
+# asm 2: vst1.8 <x4=d20,[<input_0=r0]
+vst1.8 d20,[r0]
+
+# qhasm: len = len
+# asm 1: mov >len=int32#1,<len=int32#4
+# asm 2: mov >len=r0,<len=r3
+mov r0,r3
+
+# qhasm: qpopreturn len
+mov sp,r12
+vpop {q4,q5,q6,q7}
+bx lr
+
+# qhasm: int32 input_0
+
+# qhasm: int32 input_1
+
+# qhasm: int32 input_2
+
+# qhasm: int32 input_3
+
+# qhasm: stack32 input_4
+
+# qhasm: stack32 input_5
+
+# qhasm: stack32 input_6
+
+# qhasm: stack32 input_7
+
+# qhasm: int32 caller_r4
+
+# qhasm: int32 caller_r5
+
+# qhasm: int32 caller_r6
+
+# qhasm: int32 caller_r7
+
+# qhasm: int32 caller_r8
+
+# qhasm: int32 caller_r9
+
+# qhasm: int32 caller_r10
+
+# qhasm: int32 caller_r11
+
+# qhasm: int32 caller_r12
+
+# qhasm: int32 caller_r14
+
+# qhasm: reg128 caller_q4
+
+# qhasm: reg128 caller_q5
+
+# qhasm: reg128 caller_q6
+
+# qhasm: reg128 caller_q7
+
+# qhasm: reg128 r0
+
+# qhasm: reg128 r1
+
+# qhasm: reg128 r2
+
+# qhasm: reg128 r3
+
+# qhasm: reg128 r4
+
+# qhasm: reg128 x01
+
+# qhasm: reg128 x23
+
+# qhasm: reg128 x4
+
+# qhasm: reg128 y01
+
+# qhasm: reg128 y23
+
+# qhasm: reg128 y4
+
+# qhasm: reg128 _5y01
+
+# qhasm: reg128 _5y23
+
+# qhasm: reg128 _5y4
+
+# qhasm: reg128 c01
+
+# qhasm: reg128 c23
+
+# qhasm: reg128 c4
+
+# qhasm: reg128 t0
+
+# qhasm: reg128 t1
+
+# qhasm: reg128 t2
+
+# qhasm: reg128 t3
+
+# qhasm: reg128 t4
+
+# qhasm: reg128 mask
+
+# qhasm: enter crypto_onetimeauth_poly1305_neon2_addmulmod
+.align 2
+.global openssl_poly1305_neon2_addmulmod
+.type openssl_poly1305_neon2_addmulmod STT_FUNC
+openssl_poly1305_neon2_addmulmod:
+sub sp,sp,#0
+
+# qhasm: 				2x mask = 0xffffffff
+# asm 1: vmov.i64 >mask=reg128#1,#0xffffffff
+# asm 2: vmov.i64 >mask=q0,#0xffffffff
+vmov.i64 q0,#0xffffffff
+
+# qhasm:   y01 aligned= mem128[input_2];input_2+=16
+# asm 1: vld1.8 {>y01=reg128#2%bot->y01=reg128#2%top},[<input_2=int32#3,: 128]!
+# asm 2: vld1.8 {>y01=d2->y01=d3},[<input_2=r2,: 128]!
+vld1.8 {d2-d3},[r2,: 128]!
+
+# qhasm: 4x _5y01 = y01 << 2
+# asm 1: vshl.i32 >_5y01=reg128#3,<y01=reg128#2,#2
+# asm 2: vshl.i32 >_5y01=q2,<y01=q1,#2
+vshl.i32 q2,q1,#2
+
+# qhasm:   y23 aligned= mem128[input_2];input_2+=16
+# asm 1: vld1.8 {>y23=reg128#4%bot->y23=reg128#4%top},[<input_2=int32#3,: 128]!
+# asm 2: vld1.8 {>y23=d6->y23=d7},[<input_2=r2,: 128]!
+vld1.8 {d6-d7},[r2,: 128]!
+
+# qhasm: 4x _5y23 = y23 << 2
+# asm 1: vshl.i32 >_5y23=reg128#9,<y23=reg128#4,#2
+# asm 2: vshl.i32 >_5y23=q8,<y23=q3,#2
+vshl.i32 q8,q3,#2
+
+# qhasm:   y4  aligned= mem64[input_2]y4[1]
+# asm 1: vld1.8 {<y4=reg128#10%bot},[<input_2=int32#3,: 64]
+# asm 2: vld1.8 {<y4=d18},[<input_2=r2,: 64]
+vld1.8 {d18},[r2,: 64]
+
+# qhasm: 4x _5y4 = y4 << 2
+# asm 1: vshl.i32 >_5y4=reg128#11,<y4=reg128#10,#2
+# asm 2: vshl.i32 >_5y4=q10,<y4=q9,#2
+vshl.i32 q10,q9,#2
+
+# qhasm:   x01 aligned= mem128[input_1];input_1+=16
+# asm 1: vld1.8 {>x01=reg128#12%bot->x01=reg128#12%top},[<input_1=int32#2,: 128]!
+# asm 2: vld1.8 {>x01=d22->x01=d23},[<input_1=r1,: 128]!
+vld1.8 {d22-d23},[r1,: 128]!
+
+# qhasm: 4x _5y01 += y01
+# asm 1: vadd.i32 >_5y01=reg128#3,<_5y01=reg128#3,<y01=reg128#2
+# asm 2: vadd.i32 >_5y01=q2,<_5y01=q2,<y01=q1
+vadd.i32 q2,q2,q1
+
+# qhasm:   x23 aligned= mem128[input_1];input_1+=16
+# asm 1: vld1.8 {>x23=reg128#13%bot->x23=reg128#13%top},[<input_1=int32#2,: 128]!
+# asm 2: vld1.8 {>x23=d24->x23=d25},[<input_1=r1,: 128]!
+vld1.8 {d24-d25},[r1,: 128]!
+
+# qhasm: 4x _5y23 += y23
+# asm 1: vadd.i32 >_5y23=reg128#9,<_5y23=reg128#9,<y23=reg128#4
+# asm 2: vadd.i32 >_5y23=q8,<_5y23=q8,<y23=q3
+vadd.i32 q8,q8,q3
+
+# qhasm: 4x _5y4 += y4
+# asm 1: vadd.i32 >_5y4=reg128#11,<_5y4=reg128#11,<y4=reg128#10
+# asm 2: vadd.i32 >_5y4=q10,<_5y4=q10,<y4=q9
+vadd.i32 q10,q10,q9
+
+# qhasm:   c01 aligned= mem128[input_3];input_3+=16
+# asm 1: vld1.8 {>c01=reg128#14%bot->c01=reg128#14%top},[<input_3=int32#4,: 128]!
+# asm 2: vld1.8 {>c01=d26->c01=d27},[<input_3=r3,: 128]!
+vld1.8 {d26-d27},[r3,: 128]!
+
+# qhasm: 4x x01 += c01
+# asm 1: vadd.i32 >x01=reg128#12,<x01=reg128#12,<c01=reg128#14
+# asm 2: vadd.i32 >x01=q11,<x01=q11,<c01=q13
+vadd.i32 q11,q11,q13
+
+# qhasm:   c23 aligned= mem128[input_3];input_3+=16
+# asm 1: vld1.8 {>c23=reg128#14%bot->c23=reg128#14%top},[<input_3=int32#4,: 128]!
+# asm 2: vld1.8 {>c23=d26->c23=d27},[<input_3=r3,: 128]!
+vld1.8 {d26-d27},[r3,: 128]!
+
+# qhasm: 4x x23 += c23
+# asm 1: vadd.i32 >x23=reg128#13,<x23=reg128#13,<c23=reg128#14
+# asm 2: vadd.i32 >x23=q12,<x23=q12,<c23=q13
+vadd.i32 q12,q12,q13
+
+# qhasm:   x4  aligned= mem64[input_1]x4[1]
+# asm 1: vld1.8 {<x4=reg128#14%bot},[<input_1=int32#2,: 64]
+# asm 2: vld1.8 {<x4=d26},[<input_1=r1,: 64]
+vld1.8 {d26},[r1,: 64]
+
+# qhasm: 				2x mask unsigned>>=6
+# asm 1: vshr.u64 >mask=reg128#1,<mask=reg128#1,#6
+# asm 2: vshr.u64 >mask=q0,<mask=q0,#6
+vshr.u64 q0,q0,#6
+
+# qhasm:   c4  aligned= mem64[input_3]c4[1]
+# asm 1: vld1.8 {<c4=reg128#15%bot},[<input_3=int32#4,: 64]
+# asm 2: vld1.8 {<c4=d28},[<input_3=r3,: 64]
+vld1.8 {d28},[r3,: 64]
+
+# qhasm: 4x x4 += c4
+# asm 1: vadd.i32 >x4=reg128#14,<x4=reg128#14,<c4=reg128#15
+# asm 2: vadd.i32 >x4=q13,<x4=q13,<c4=q14
+vadd.i32 q13,q13,q14
+
+# qhasm: r0[0,1]  = x01[0] unsigned* y01[0];   r0[2,3]  = x01[1] unsigned* y01[1]
+# asm 1: vmull.u32 >r0=reg128#15,<x01=reg128#12%bot,<y01=reg128#2%bot
+# asm 2: vmull.u32 >r0=q14,<x01=d22,<y01=d2
+vmull.u32 q14,d22,d2
+
+# qhasm: r0[0,1] += x01[2] unsigned*  _5y4[0]; r0[2,3] += x01[3] unsigned*  _5y4[1]
+# asm 1: vmlal.u32 <r0=reg128#15,<x01=reg128#12%top,<_5y4=reg128#11%bot
+# asm 2: vmlal.u32 <r0=q14,<x01=d23,<_5y4=d20
+vmlal.u32 q14,d23,d20
+
+# qhasm: r0[0,1] += x23[0] unsigned* _5y23[2]; r0[2,3] += x23[1] unsigned* _5y23[3]
+# asm 1: vmlal.u32 <r0=reg128#15,<x23=reg128#13%bot,<_5y23=reg128#9%top
+# asm 2: vmlal.u32 <r0=q14,<x23=d24,<_5y23=d17
+vmlal.u32 q14,d24,d17
+
+# qhasm: r0[0,1] += x23[2] unsigned* _5y23[0]; r0[2,3] += x23[3] unsigned* _5y23[1]
+# asm 1: vmlal.u32 <r0=reg128#15,<x23=reg128#13%top,<_5y23=reg128#9%bot
+# asm 2: vmlal.u32 <r0=q14,<x23=d25,<_5y23=d16
+vmlal.u32 q14,d25,d16
+
+# qhasm: r0[0,1] +=  x4[0] unsigned* _5y01[2]; r0[2,3] +=  x4[1] unsigned* _5y01[3]
+# asm 1: vmlal.u32 <r0=reg128#15,<x4=reg128#14%bot,<_5y01=reg128#3%top
+# asm 2: vmlal.u32 <r0=q14,<x4=d26,<_5y01=d5
+vmlal.u32 q14,d26,d5
+
+# qhasm: r1[0,1]  = x01[0] unsigned* y01[2];   r1[2,3]  = x01[1] unsigned* y01[3]
+# asm 1: vmull.u32 >r1=reg128#3,<x01=reg128#12%bot,<y01=reg128#2%top
+# asm 2: vmull.u32 >r1=q2,<x01=d22,<y01=d3
+vmull.u32 q2,d22,d3
+
+# qhasm: r1[0,1] += x01[2] unsigned* y01[0];   r1[2,3] += x01[3] unsigned* y01[1]
+# asm 1: vmlal.u32 <r1=reg128#3,<x01=reg128#12%top,<y01=reg128#2%bot
+# asm 2: vmlal.u32 <r1=q2,<x01=d23,<y01=d2
+vmlal.u32 q2,d23,d2
+
+# qhasm: r1[0,1] += x23[0] unsigned*  _5y4[0]; r1[2,3] += x23[1] unsigned*  _5y4[1]
+# asm 1: vmlal.u32 <r1=reg128#3,<x23=reg128#13%bot,<_5y4=reg128#11%bot
+# asm 2: vmlal.u32 <r1=q2,<x23=d24,<_5y4=d20
+vmlal.u32 q2,d24,d20
+
+# qhasm: r1[0,1] += x23[2] unsigned* _5y23[2]; r1[2,3] += x23[3] unsigned* _5y23[3]
+# asm 1: vmlal.u32 <r1=reg128#3,<x23=reg128#13%top,<_5y23=reg128#9%top
+# asm 2: vmlal.u32 <r1=q2,<x23=d25,<_5y23=d17
+vmlal.u32 q2,d25,d17
+
+# qhasm: r1[0,1] +=  x4[0] unsigned* _5y23[0]; r1[2,3] +=  x4[1] unsigned* _5y23[1]
+# asm 1: vmlal.u32 <r1=reg128#3,<x4=reg128#14%bot,<_5y23=reg128#9%bot
+# asm 2: vmlal.u32 <r1=q2,<x4=d26,<_5y23=d16
+vmlal.u32 q2,d26,d16
+
+# qhasm: r2[0,1]  = x01[0] unsigned* y23[0];   r2[2,3]  = x01[1] unsigned* y23[1]
+# asm 1: vmull.u32 >r2=reg128#16,<x01=reg128#12%bot,<y23=reg128#4%bot
+# asm 2: vmull.u32 >r2=q15,<x01=d22,<y23=d6
+vmull.u32 q15,d22,d6
+
+# qhasm: r2[0,1] += x01[2] unsigned* y01[2];   r2[2,3] += x01[3] unsigned* y01[3]
+# asm 1: vmlal.u32 <r2=reg128#16,<x01=reg128#12%top,<y01=reg128#2%top
+# asm 2: vmlal.u32 <r2=q15,<x01=d23,<y01=d3
+vmlal.u32 q15,d23,d3
+
+# qhasm: r2[0,1] += x23[0] unsigned* y01[0];   r2[2,3] += x23[1] unsigned* y01[1]
+# asm 1: vmlal.u32 <r2=reg128#16,<x23=reg128#13%bot,<y01=reg128#2%bot
+# asm 2: vmlal.u32 <r2=q15,<x23=d24,<y01=d2
+vmlal.u32 q15,d24,d2
+
+# qhasm: r2[0,1] += x23[2] unsigned*  _5y4[0]; r2[2,3] += x23[3] unsigned*  _5y4[1]
+# asm 1: vmlal.u32 <r2=reg128#16,<x23=reg128#13%top,<_5y4=reg128#11%bot
+# asm 2: vmlal.u32 <r2=q15,<x23=d25,<_5y4=d20
+vmlal.u32 q15,d25,d20
+
+# qhasm: r2[0,1] +=  x4[0] unsigned* _5y23[2]; r2[2,3] +=  x4[1] unsigned* _5y23[3]
+# asm 1: vmlal.u32 <r2=reg128#16,<x4=reg128#14%bot,<_5y23=reg128#9%top
+# asm 2: vmlal.u32 <r2=q15,<x4=d26,<_5y23=d17
+vmlal.u32 q15,d26,d17
+
+# qhasm: r3[0,1]  = x01[0] unsigned* y23[2];   r3[2,3]  = x01[1] unsigned* y23[3]
+# asm 1: vmull.u32 >r3=reg128#9,<x01=reg128#12%bot,<y23=reg128#4%top
+# asm 2: vmull.u32 >r3=q8,<x01=d22,<y23=d7
+vmull.u32 q8,d22,d7
+
+# qhasm: r3[0,1] += x01[2] unsigned* y23[0];   r3[2,3] += x01[3] unsigned* y23[1]
+# asm 1: vmlal.u32 <r3=reg128#9,<x01=reg128#12%top,<y23=reg128#4%bot
+# asm 2: vmlal.u32 <r3=q8,<x01=d23,<y23=d6
+vmlal.u32 q8,d23,d6
+
+# qhasm: r3[0,1] += x23[0] unsigned* y01[2];   r3[2,3] += x23[1] unsigned* y01[3]
+# asm 1: vmlal.u32 <r3=reg128#9,<x23=reg128#13%bot,<y01=reg128#2%top
+# asm 2: vmlal.u32 <r3=q8,<x23=d24,<y01=d3
+vmlal.u32 q8,d24,d3
+
+# qhasm: r3[0,1] += x23[2] unsigned* y01[0];   r3[2,3] += x23[3] unsigned* y01[1]
+# asm 1: vmlal.u32 <r3=reg128#9,<x23=reg128#13%top,<y01=reg128#2%bot
+# asm 2: vmlal.u32 <r3=q8,<x23=d25,<y01=d2
+vmlal.u32 q8,d25,d2
+
+# qhasm: r3[0,1] +=  x4[0] unsigned*  _5y4[0]; r3[2,3] +=  x4[1] unsigned*  _5y4[1]
+# asm 1: vmlal.u32 <r3=reg128#9,<x4=reg128#14%bot,<_5y4=reg128#11%bot
+# asm 2: vmlal.u32 <r3=q8,<x4=d26,<_5y4=d20
+vmlal.u32 q8,d26,d20
+
+# qhasm: r4[0,1]  = x01[0] unsigned*  y4[0];  r4[2,3]  = x01[1] unsigned*  y4[1]
+# asm 1: vmull.u32 >r4=reg128#10,<x01=reg128#12%bot,<y4=reg128#10%bot
+# asm 2: vmull.u32 >r4=q9,<x01=d22,<y4=d18
+vmull.u32 q9,d22,d18
+
+# qhasm: r4[0,1] += x01[2] unsigned* y23[2];  r4[2,3] += x01[3] unsigned* y23[3]
+# asm 1: vmlal.u32 <r4=reg128#10,<x01=reg128#12%top,<y23=reg128#4%top
+# asm 2: vmlal.u32 <r4=q9,<x01=d23,<y23=d7
+vmlal.u32 q9,d23,d7
+
+# qhasm: r4[0,1] += x23[0] unsigned* y23[0];  r4[2,3] += x23[1] unsigned* y23[1]
+# asm 1: vmlal.u32 <r4=reg128#10,<x23=reg128#13%bot,<y23=reg128#4%bot
+# asm 2: vmlal.u32 <r4=q9,<x23=d24,<y23=d6
+vmlal.u32 q9,d24,d6
+
+# qhasm: r4[0,1] += x23[2] unsigned* y01[2];  r4[2,3] += x23[3] unsigned* y01[3]
+# asm 1: vmlal.u32 <r4=reg128#10,<x23=reg128#13%top,<y01=reg128#2%top
+# asm 2: vmlal.u32 <r4=q9,<x23=d25,<y01=d3
+vmlal.u32 q9,d25,d3
+
+# qhasm: r4[0,1] +=  x4[0] unsigned* y01[0];  r4[2,3] +=  x4[1] unsigned* y01[1]
+# asm 1: vmlal.u32 <r4=reg128#10,<x4=reg128#14%bot,<y01=reg128#2%bot
+# asm 2: vmlal.u32 <r4=q9,<x4=d26,<y01=d2
+vmlal.u32 q9,d26,d2
+
+# qhasm: 2x t1 = r0 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#2,<r0=reg128#15,#26
+# asm 2: vshr.u64 >t1=q1,<r0=q14,#26
+vshr.u64 q1,q14,#26
+
+# qhasm:    r0 &= mask
+# asm 1: vand >r0=reg128#4,<r0=reg128#15,<mask=reg128#1
+# asm 2: vand >r0=q3,<r0=q14,<mask=q0
+vand q3,q14,q0
+
+# qhasm: 2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#2,<r1=reg128#3,<t1=reg128#2
+# asm 2: vadd.i64 >r1=q1,<r1=q2,<t1=q1
+vadd.i64 q1,q2,q1
+
+# qhasm:                 2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#3,<r3=reg128#9,#26
+# asm 2: vshr.u64 >t4=q2,<r3=q8,#26
+vshr.u64 q2,q8,#26
+
+# qhasm:                    r3 &= mask
+# asm 1: vand >r3=reg128#9,<r3=reg128#9,<mask=reg128#1
+# asm 2: vand >r3=q8,<r3=q8,<mask=q0
+vand q8,q8,q0
+
+# qhasm:                 2x r4 += t4
+# asm 1: vadd.i64 >r4=reg128#3,<r4=reg128#10,<t4=reg128#3
+# asm 2: vadd.i64 >r4=q2,<r4=q9,<t4=q2
+vadd.i64 q2,q9,q2
+
+# qhasm: 2x t2 = r1 unsigned>> 26
+# asm 1: vshr.u64 >t2=reg128#10,<r1=reg128#2,#26
+# asm 2: vshr.u64 >t2=q9,<r1=q1,#26
+vshr.u64 q9,q1,#26
+
+# qhasm:    r1 &= mask
+# asm 1: vand >r1=reg128#2,<r1=reg128#2,<mask=reg128#1
+# asm 2: vand >r1=q1,<r1=q1,<mask=q0
+vand q1,q1,q0
+
+# qhasm:                 2x t0 = r4 unsigned>> 26
+# asm 1: vshr.u64 >t0=reg128#11,<r4=reg128#3,#26
+# asm 2: vshr.u64 >t0=q10,<r4=q2,#26
+vshr.u64 q10,q2,#26
+
+# qhasm: 2x r2 += t2
+# asm 1: vadd.i64 >r2=reg128#10,<r2=reg128#16,<t2=reg128#10
+# asm 2: vadd.i64 >r2=q9,<r2=q15,<t2=q9
+vadd.i64 q9,q15,q9
+
+# qhasm:                    r4 &= mask
+# asm 1: vand >r4=reg128#3,<r4=reg128#3,<mask=reg128#1
+# asm 2: vand >r4=q2,<r4=q2,<mask=q0
+vand q2,q2,q0
+
+# qhasm:                 2x r0 += t0
+# asm 1: vadd.i64 >r0=reg128#4,<r0=reg128#4,<t0=reg128#11
+# asm 2: vadd.i64 >r0=q3,<r0=q3,<t0=q10
+vadd.i64 q3,q3,q10
+
+# qhasm:                 2x t0 <<= 2
+# asm 1: vshl.i64 >t0=reg128#11,<t0=reg128#11,#2
+# asm 2: vshl.i64 >t0=q10,<t0=q10,#2
+vshl.i64 q10,q10,#2
+
+# qhasm: 2x t3 = r2 unsigned>> 26
+# asm 1: vshr.u64 >t3=reg128#12,<r2=reg128#10,#26
+# asm 2: vshr.u64 >t3=q11,<r2=q9,#26
+vshr.u64 q11,q9,#26
+
+# qhasm:                 2x r0 += t0
+# asm 1: vadd.i64 >r0=reg128#4,<r0=reg128#4,<t0=reg128#11
+# asm 2: vadd.i64 >r0=q3,<r0=q3,<t0=q10
+vadd.i64 q3,q3,q10
+
+# qhasm:    x23 = r2 & mask
+# asm 1: vand >x23=reg128#10,<r2=reg128#10,<mask=reg128#1
+# asm 2: vand >x23=q9,<r2=q9,<mask=q0
+vand q9,q9,q0
+
+# qhasm: 2x r3 += t3
+# asm 1: vadd.i64 >r3=reg128#9,<r3=reg128#9,<t3=reg128#12
+# asm 2: vadd.i64 >r3=q8,<r3=q8,<t3=q11
+vadd.i64 q8,q8,q11
+
+# qhasm:                 2x t1 = r0 unsigned>> 26
+# asm 1: vshr.u64 >t1=reg128#11,<r0=reg128#4,#26
+# asm 2: vshr.u64 >t1=q10,<r0=q3,#26
+vshr.u64 q10,q3,#26
+
+# qhasm: 				x23 = x23[0,2,1,3]
+# asm 1: vtrn.32 <x23=reg128#10%bot,<x23=reg128#10%top
+# asm 2: vtrn.32 <x23=d18,<x23=d19
+vtrn.32 d18,d19
+
+# qhasm:                    x01 = r0 & mask
+# asm 1: vand >x01=reg128#4,<r0=reg128#4,<mask=reg128#1
+# asm 2: vand >x01=q3,<r0=q3,<mask=q0
+vand q3,q3,q0
+
+# qhasm:                 2x r1 += t1
+# asm 1: vadd.i64 >r1=reg128#2,<r1=reg128#2,<t1=reg128#11
+# asm 2: vadd.i64 >r1=q1,<r1=q1,<t1=q10
+vadd.i64 q1,q1,q10
+
+# qhasm: 2x t4 = r3 unsigned>> 26
+# asm 1: vshr.u64 >t4=reg128#11,<r3=reg128#9,#26
+# asm 2: vshr.u64 >t4=q10,<r3=q8,#26
+vshr.u64 q10,q8,#26
+
+# qhasm: 				x01 = x01[0,2,1,3]
+# asm 1: vtrn.32 <x01=reg128#4%bot,<x01=reg128#4%top
+# asm 2: vtrn.32 <x01=d6,<x01=d7
+vtrn.32 d6,d7
+
+# qhasm:    r3 &= mask
+# asm 1: vand >r3=reg128#1,<r3=reg128#9,<mask=reg128#1
+# asm 2: vand >r3=q0,<r3=q8,<mask=q0
+vand q0,q8,q0
+
+# qhasm: 				r1 = r1[0,2,1,3]
+# asm 1: vtrn.32 <r1=reg128#2%bot,<r1=reg128#2%top
+# asm 2: vtrn.32 <r1=d2,<r1=d3
+vtrn.32 d2,d3
+
+# qhasm: 2x x4 = r4 + t4
+# asm 1: vadd.i64 >x4=reg128#3,<r4=reg128#3,<t4=reg128#11
+# asm 2: vadd.i64 >x4=q2,<r4=q2,<t4=q10
+vadd.i64 q2,q2,q10
+
+# qhasm: 				r3 = r3[0,2,1,3]
+# asm 1: vtrn.32 <r3=reg128#1%bot,<r3=reg128#1%top
+# asm 2: vtrn.32 <r3=d0,<r3=d1
+vtrn.32 d0,d1
+
+# qhasm: 				x01 = x01[0,1] r1[0,1]
+# asm 1: vext.32 <x01=reg128#4%top,<r1=reg128#2%bot,<r1=reg128#2%bot,#0
+# asm 2: vext.32 <x01=d7,<r1=d2,<r1=d2,#0
+vext.32 d7,d2,d2,#0
+
+# qhasm: 				x23 = x23[0,1] r3[0,1]
+# asm 1: vext.32 <x23=reg128#10%top,<r3=reg128#1%bot,<r3=reg128#1%bot,#0
+# asm 2: vext.32 <x23=d19,<r3=d0,<r3=d0,#0
+vext.32 d19,d0,d0,#0
+
+# qhasm: 				x4 = x4[0,2,1,3]
+# asm 1: vtrn.32 <x4=reg128#3%bot,<x4=reg128#3%top
+# asm 2: vtrn.32 <x4=d4,<x4=d5
+vtrn.32 d4,d5
+
+# qhasm: mem128[input_0] aligned= x01;input_0+=16
+# asm 1: vst1.8 {<x01=reg128#4%bot-<x01=reg128#4%top},[<input_0=int32#1,: 128]!
+# asm 2: vst1.8 {<x01=d6-<x01=d7},[<input_0=r0,: 128]!
+vst1.8 {d6-d7},[r0,: 128]!
+
+# qhasm: mem128[input_0] aligned= x23;input_0+=16
+# asm 1: vst1.8 {<x23=reg128#10%bot-<x23=reg128#10%top},[<input_0=int32#1,: 128]!
+# asm 2: vst1.8 {<x23=d18-<x23=d19},[<input_0=r0,: 128]!
+vst1.8 {d18-d19},[r0,: 128]!
+
+# qhasm: mem64[input_0] aligned= x4[0]
+# asm 1: vst1.8 <x4=reg128#3%bot,[<input_0=int32#1,: 64]
+# asm 2: vst1.8 <x4=d4,[<input_0=r0,: 64]
+vst1.8 d4,[r0,: 64]
+
+# qhasm: return
+add sp,sp,#0
+bx lr
+
+#endif
diff --git a/crypto/poly1305/poly1305_vec.c b/crypto/poly1305/poly1305_vec.c
new file mode 100644
index 0000000..89fcacb
--- /dev/null
+++ b/crypto/poly1305/poly1305_vec.c
@@ -0,0 +1,887 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or 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 implementation of poly1305 is by Andrew Moon
+ * (https://github.com/floodyberry/poly1305-donna) and released as public
+ * domain. It implements SIMD vectorization based on the algorithm described in
+ * http://cr.yp.to/papers.html#neoncrypto. Unrolled to 2 powers, i.e. 64 byte
+ * block size */
+
+#include <openssl/poly1305.h>
+
+
+#if !defined(OPENSSL_WINDOWS) && defined(OPENSSL_X86_64)
+
+#include <emmintrin.h>
+
+#define ALIGN(x) __attribute__((aligned(x)))
+/* inline is not a keyword in C89. */
+#define INLINE 
+#define U8TO64_LE(m) (*(uint64_t *)(m))
+#define U8TO32_LE(m) (*(uint32_t *)(m))
+#define U64TO8_LE(m, v) (*(uint64_t *)(m)) = v
+
+typedef __m128i xmmi;
+typedef unsigned __int128 uint128_t;
+
+static const uint32_t ALIGN(16) poly1305_x64_sse2_message_mask[4] = {
+    (1 << 26) - 1, 0, (1 << 26) - 1, 0};
+static const uint32_t ALIGN(16) poly1305_x64_sse2_5[4] = {5, 0, 5, 0};
+static const uint32_t ALIGN(16) poly1305_x64_sse2_1shl128[4] = {(1 << 24), 0,
+                                                                (1 << 24), 0};
+
+static uint128_t INLINE add128(uint128_t a, uint128_t b) { return a + b; }
+
+static uint128_t INLINE add128_64(uint128_t a, uint64_t b) { return a + b; }
+
+static uint128_t INLINE mul64x64_128(uint64_t a, uint64_t b) {
+  return (uint128_t)a * b;
+}
+
+static uint64_t INLINE lo128(uint128_t a) { return (uint64_t)a; }
+
+static uint64_t INLINE shr128(uint128_t v, const int shift) {
+  return (uint64_t)(v >> shift);
+}
+
+static uint64_t INLINE shr128_pair(uint64_t hi, uint64_t lo, const int shift) {
+  return (uint64_t)((((uint128_t)hi << 64) | lo) >> shift);
+}
+
+typedef struct poly1305_power_t {
+  union {
+    xmmi v;
+    uint64_t u[2];
+    uint32_t d[4];
+  } R20, R21, R22, R23, R24, S21, S22, S23, S24;
+} poly1305_power;
+
+typedef struct poly1305_state_internal_t {
+  poly1305_power P[2]; /* 288 bytes, top 32 bit halves unused = 144
+                          bytes of free storage */
+  union {
+    xmmi H[5]; /*  80 bytes  */
+    uint64_t HH[10];
+  };
+  /* uint64_t r0,r1,r2;       [24 bytes] */
+  /* uint64_t pad0,pad1;      [16 bytes] */
+  uint64_t started;        /*   8 bytes  */
+  uint64_t leftover;       /*   8 bytes  */
+  uint8_t buffer[64];      /*  64 bytes  */
+} poly1305_state_internal; /* 448 bytes total + 63 bytes for
+                              alignment = 511 bytes raw */
+
+static poly1305_state_internal INLINE *poly1305_aligned_state(
+    poly1305_state *state) {
+  return (poly1305_state_internal *)(((uint64_t)state + 63) & ~63);
+}
+
+/* copy 0-63 bytes */
+static void INLINE
+poly1305_block_copy(uint8_t *dst, const uint8_t *src, size_t bytes) {
+  size_t offset = src - dst;
+  if (bytes & 32) {
+    _mm_storeu_si128((xmmi *)(dst + 0),
+                     _mm_loadu_si128((xmmi *)(dst + offset + 0)));
+    _mm_storeu_si128((xmmi *)(dst + 16),
+                     _mm_loadu_si128((xmmi *)(dst + offset + 16)));
+    dst += 32;
+  }
+  if (bytes & 16) {
+    _mm_storeu_si128((xmmi *)dst, _mm_loadu_si128((xmmi *)(dst + offset)));
+    dst += 16;
+  }
+  if (bytes & 8) {
+    *(uint64_t *)dst = *(uint64_t *)(dst + offset);
+    dst += 8;
+  }
+  if (bytes & 4) {
+    *(uint32_t *)dst = *(uint32_t *)(dst + offset);
+    dst += 4;
+  }
+  if (bytes & 2) {
+    *(uint16_t *)dst = *(uint16_t *)(dst + offset);
+    dst += 2;
+  }
+  if (bytes & 1) {
+    *(uint8_t *)dst = *(uint8_t *)(dst + offset);
+  }
+}
+
+/* zero 0-15 bytes */
+static void INLINE poly1305_block_zero(uint8_t *dst, size_t bytes) {
+  if (bytes & 8) {
+    *(uint64_t *)dst = 0;
+    dst += 8;
+  }
+  if (bytes & 4) {
+    *(uint32_t *)dst = 0;
+    dst += 4;
+  }
+  if (bytes & 2) {
+    *(uint16_t *)dst = 0;
+    dst += 2;
+  }
+  if (bytes & 1) {
+    *(uint8_t *)dst = 0;
+  }
+}
+
+static size_t INLINE poly1305_min(size_t a, size_t b) {
+  return (a < b) ? a : b;
+}
+
+void CRYPTO_poly1305_init(poly1305_state *state, const uint8_t key[32]) {
+  poly1305_state_internal *st = poly1305_aligned_state(state);
+  poly1305_power *p;
+  uint64_t r0, r1, r2;
+  uint64_t t0, t1;
+
+  /* clamp key */
+  t0 = U8TO64_LE(key + 0);
+  t1 = U8TO64_LE(key + 8);
+  r0 = t0 & 0xffc0fffffff;
+  t0 >>= 44;
+  t0 |= t1 << 20;
+  r1 = t0 & 0xfffffc0ffff;
+  t1 >>= 24;
+  r2 = t1 & 0x00ffffffc0f;
+
+  /* store r in un-used space of st->P[1] */
+  p = &st->P[1];
+  p->R20.d[1] = (uint32_t)(r0);
+  p->R20.d[3] = (uint32_t)(r0 >> 32);
+  p->R21.d[1] = (uint32_t)(r1);
+  p->R21.d[3] = (uint32_t)(r1 >> 32);
+  p->R22.d[1] = (uint32_t)(r2);
+  p->R22.d[3] = (uint32_t)(r2 >> 32);
+
+  /* store pad */
+  p->R23.d[1] = U8TO32_LE(key + 16);
+  p->R23.d[3] = U8TO32_LE(key + 20);
+  p->R24.d[1] = U8TO32_LE(key + 24);
+  p->R24.d[3] = U8TO32_LE(key + 28);
+
+  /* H = 0 */
+  st->H[0] = _mm_setzero_si128();
+  st->H[1] = _mm_setzero_si128();
+  st->H[2] = _mm_setzero_si128();
+  st->H[3] = _mm_setzero_si128();
+  st->H[4] = _mm_setzero_si128();
+
+  st->started = 0;
+  st->leftover = 0;
+}
+
+static void poly1305_first_block(poly1305_state_internal *st,
+                                 const uint8_t *m) {
+  const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask);
+  const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5);
+  const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128);
+  xmmi T5, T6;
+  poly1305_power *p;
+  uint128_t d[3];
+  uint64_t r0, r1, r2;
+  uint64_t r20, r21, r22, s22;
+  uint64_t pad0, pad1;
+  uint64_t c;
+  uint64_t i;
+
+  /* pull out stored info */
+  p = &st->P[1];
+
+  r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1];
+  r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1];
+  r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1];
+  pad0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1];
+  pad1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1];
+
+  /* compute powers r^2,r^4 */
+  r20 = r0;
+  r21 = r1;
+  r22 = r2;
+  for (i = 0; i < 2; i++) {
+    s22 = r22 * (5 << 2);
+
+    d[0] = add128(mul64x64_128(r20, r20), mul64x64_128(r21 * 2, s22));
+    d[1] = add128(mul64x64_128(r22, s22), mul64x64_128(r20 * 2, r21));
+    d[2] = add128(mul64x64_128(r21, r21), mul64x64_128(r22 * 2, r20));
+
+    r20 = lo128(d[0]) & 0xfffffffffff;
+    c = shr128(d[0], 44);
+    d[1] = add128_64(d[1], c);
+    r21 = lo128(d[1]) & 0xfffffffffff;
+    c = shr128(d[1], 44);
+    d[2] = add128_64(d[2], c);
+    r22 = lo128(d[2]) & 0x3ffffffffff;
+    c = shr128(d[2], 42);
+    r20 += c * 5;
+    c = (r20 >> 44);
+    r20 = r20 & 0xfffffffffff;
+    r21 += c;
+
+    p->R20.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)(r20)&0x3ffffff),
+                                 _MM_SHUFFLE(1, 0, 1, 0));
+    p->R21.v = _mm_shuffle_epi32(
+        _mm_cvtsi32_si128((uint32_t)((r20 >> 26) | (r21 << 18)) & 0x3ffffff),
+        _MM_SHUFFLE(1, 0, 1, 0));
+    p->R22.v =
+        _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r21 >> 8)) & 0x3ffffff),
+                          _MM_SHUFFLE(1, 0, 1, 0));
+    p->R23.v = _mm_shuffle_epi32(
+        _mm_cvtsi32_si128((uint32_t)((r21 >> 34) | (r22 << 10)) & 0x3ffffff),
+        _MM_SHUFFLE(1, 0, 1, 0));
+    p->R24.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r22 >> 16))),
+                                 _MM_SHUFFLE(1, 0, 1, 0));
+    p->S21.v = _mm_mul_epu32(p->R21.v, FIVE);
+    p->S22.v = _mm_mul_epu32(p->R22.v, FIVE);
+    p->S23.v = _mm_mul_epu32(p->R23.v, FIVE);
+    p->S24.v = _mm_mul_epu32(p->R24.v, FIVE);
+    p--;
+  }
+
+  /* put saved info back */
+  p = &st->P[1];
+  p->R20.d[1] = (uint32_t)(r0);
+  p->R20.d[3] = (uint32_t)(r0 >> 32);
+  p->R21.d[1] = (uint32_t)(r1);
+  p->R21.d[3] = (uint32_t)(r1 >> 32);
+  p->R22.d[1] = (uint32_t)(r2);
+  p->R22.d[3] = (uint32_t)(r2 >> 32);
+  p->R23.d[1] = (uint32_t)(pad0);
+  p->R23.d[3] = (uint32_t)(pad0 >> 32);
+  p->R24.d[1] = (uint32_t)(pad1);
+  p->R24.d[3] = (uint32_t)(pad1 >> 32);
+
+  /* H = [Mx,My] */
+  T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)),
+                          _mm_loadl_epi64((xmmi *)(m + 16)));
+  T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)),
+                          _mm_loadl_epi64((xmmi *)(m + 24)));
+  st->H[0] = _mm_and_si128(MMASK, T5);
+  st->H[1] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+  T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12));
+  st->H[2] = _mm_and_si128(MMASK, T5);
+  st->H[3] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+  st->H[4] = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT);
+}
+
+static void poly1305_blocks(poly1305_state_internal *st, const uint8_t *m,
+                            size_t bytes) {
+  const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask);
+  const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5);
+  const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128);
+
+  poly1305_power *p;
+  xmmi H0, H1, H2, H3, H4;
+  xmmi T0, T1, T2, T3, T4, T5, T6;
+  xmmi M0, M1, M2, M3, M4;
+  xmmi C1, C2;
+
+  H0 = st->H[0];
+  H1 = st->H[1];
+  H2 = st->H[2];
+  H3 = st->H[3];
+  H4 = st->H[4];
+
+  while (bytes >= 64) {
+    /* H *= [r^4,r^4] */
+    p = &st->P[0];
+    T0 = _mm_mul_epu32(H0, p->R20.v);
+    T1 = _mm_mul_epu32(H0, p->R21.v);
+    T2 = _mm_mul_epu32(H0, p->R22.v);
+    T3 = _mm_mul_epu32(H0, p->R23.v);
+    T4 = _mm_mul_epu32(H0, p->R24.v);
+    T5 = _mm_mul_epu32(H1, p->S24.v);
+    T6 = _mm_mul_epu32(H1, p->R20.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H2, p->S23.v);
+    T6 = _mm_mul_epu32(H2, p->S24.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H3, p->S22.v);
+    T6 = _mm_mul_epu32(H3, p->S23.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H4, p->S21.v);
+    T6 = _mm_mul_epu32(H4, p->S22.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H1, p->R21.v);
+    T6 = _mm_mul_epu32(H1, p->R22.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H2, p->R20.v);
+    T6 = _mm_mul_epu32(H2, p->R21.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H3, p->S24.v);
+    T6 = _mm_mul_epu32(H3, p->R20.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H4, p->S23.v);
+    T6 = _mm_mul_epu32(H4, p->S24.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H1, p->R23.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H2, p->R22.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H3, p->R21.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H4, p->R20.v);
+    T4 = _mm_add_epi64(T4, T5);
+
+    /* H += [Mx,My]*[r^2,r^2] */
+    T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)),
+                            _mm_loadl_epi64((xmmi *)(m + 16)));
+    T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)),
+                            _mm_loadl_epi64((xmmi *)(m + 24)));
+    M0 = _mm_and_si128(MMASK, T5);
+    M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12));
+    M2 = _mm_and_si128(MMASK, T5);
+    M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT);
+
+    p = &st->P[1];
+    T5 = _mm_mul_epu32(M0, p->R20.v);
+    T6 = _mm_mul_epu32(M0, p->R21.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(M1, p->S24.v);
+    T6 = _mm_mul_epu32(M1, p->R20.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(M2, p->S23.v);
+    T6 = _mm_mul_epu32(M2, p->S24.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(M3, p->S22.v);
+    T6 = _mm_mul_epu32(M3, p->S23.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(M4, p->S21.v);
+    T6 = _mm_mul_epu32(M4, p->S22.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(M0, p->R22.v);
+    T6 = _mm_mul_epu32(M0, p->R23.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(M1, p->R21.v);
+    T6 = _mm_mul_epu32(M1, p->R22.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(M2, p->R20.v);
+    T6 = _mm_mul_epu32(M2, p->R21.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(M3, p->S24.v);
+    T6 = _mm_mul_epu32(M3, p->R20.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(M4, p->S23.v);
+    T6 = _mm_mul_epu32(M4, p->S24.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(M0, p->R24.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(M1, p->R23.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(M2, p->R22.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(M3, p->R21.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(M4, p->R20.v);
+    T4 = _mm_add_epi64(T4, T5);
+
+    /* H += [Mx,My] */
+    T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 32)),
+                            _mm_loadl_epi64((xmmi *)(m + 48)));
+    T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 40)),
+                            _mm_loadl_epi64((xmmi *)(m + 56)));
+    M0 = _mm_and_si128(MMASK, T5);
+    M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12));
+    M2 = _mm_and_si128(MMASK, T5);
+    M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT);
+
+    T0 = _mm_add_epi64(T0, M0);
+    T1 = _mm_add_epi64(T1, M1);
+    T2 = _mm_add_epi64(T2, M2);
+    T3 = _mm_add_epi64(T3, M3);
+    T4 = _mm_add_epi64(T4, M4);
+
+    /* reduce */
+    C1 = _mm_srli_epi64(T0, 26);
+    C2 = _mm_srli_epi64(T3, 26);
+    T0 = _mm_and_si128(T0, MMASK);
+    T3 = _mm_and_si128(T3, MMASK);
+    T1 = _mm_add_epi64(T1, C1);
+    T4 = _mm_add_epi64(T4, C2);
+    C1 = _mm_srli_epi64(T1, 26);
+    C2 = _mm_srli_epi64(T4, 26);
+    T1 = _mm_and_si128(T1, MMASK);
+    T4 = _mm_and_si128(T4, MMASK);
+    T2 = _mm_add_epi64(T2, C1);
+    T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE));
+    C1 = _mm_srli_epi64(T2, 26);
+    C2 = _mm_srli_epi64(T0, 26);
+    T2 = _mm_and_si128(T2, MMASK);
+    T0 = _mm_and_si128(T0, MMASK);
+    T3 = _mm_add_epi64(T3, C1);
+    T1 = _mm_add_epi64(T1, C2);
+    C1 = _mm_srli_epi64(T3, 26);
+    T3 = _mm_and_si128(T3, MMASK);
+    T4 = _mm_add_epi64(T4, C1);
+
+    /* H = (H*[r^4,r^4] + [Mx,My]*[r^2,r^2] + [Mx,My]) */
+    H0 = T0;
+    H1 = T1;
+    H2 = T2;
+    H3 = T3;
+    H4 = T4;
+
+    m += 64;
+    bytes -= 64;
+  }
+
+  st->H[0] = H0;
+  st->H[1] = H1;
+  st->H[2] = H2;
+  st->H[3] = H3;
+  st->H[4] = H4;
+}
+
+static size_t poly1305_combine(poly1305_state_internal *st, const uint8_t *m,
+                               size_t bytes) {
+  const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask);
+  const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128);
+  const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5);
+
+  poly1305_power *p;
+  xmmi H0, H1, H2, H3, H4;
+  xmmi M0, M1, M2, M3, M4;
+  xmmi T0, T1, T2, T3, T4, T5, T6;
+  xmmi C1, C2;
+
+  uint64_t r0, r1, r2;
+  uint64_t t0, t1, t2, t3, t4;
+  uint64_t c;
+  size_t consumed = 0;
+
+  H0 = st->H[0];
+  H1 = st->H[1];
+  H2 = st->H[2];
+  H3 = st->H[3];
+  H4 = st->H[4];
+
+  /* p = [r^2,r^2] */
+  p = &st->P[1];
+
+  if (bytes >= 32) {
+    /* H *= [r^2,r^2] */
+    T0 = _mm_mul_epu32(H0, p->R20.v);
+    T1 = _mm_mul_epu32(H0, p->R21.v);
+    T2 = _mm_mul_epu32(H0, p->R22.v);
+    T3 = _mm_mul_epu32(H0, p->R23.v);
+    T4 = _mm_mul_epu32(H0, p->R24.v);
+    T5 = _mm_mul_epu32(H1, p->S24.v);
+    T6 = _mm_mul_epu32(H1, p->R20.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H2, p->S23.v);
+    T6 = _mm_mul_epu32(H2, p->S24.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H3, p->S22.v);
+    T6 = _mm_mul_epu32(H3, p->S23.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H4, p->S21.v);
+    T6 = _mm_mul_epu32(H4, p->S22.v);
+    T0 = _mm_add_epi64(T0, T5);
+    T1 = _mm_add_epi64(T1, T6);
+    T5 = _mm_mul_epu32(H1, p->R21.v);
+    T6 = _mm_mul_epu32(H1, p->R22.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H2, p->R20.v);
+    T6 = _mm_mul_epu32(H2, p->R21.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H3, p->S24.v);
+    T6 = _mm_mul_epu32(H3, p->R20.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H4, p->S23.v);
+    T6 = _mm_mul_epu32(H4, p->S24.v);
+    T2 = _mm_add_epi64(T2, T5);
+    T3 = _mm_add_epi64(T3, T6);
+    T5 = _mm_mul_epu32(H1, p->R23.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H2, p->R22.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H3, p->R21.v);
+    T4 = _mm_add_epi64(T4, T5);
+    T5 = _mm_mul_epu32(H4, p->R20.v);
+    T4 = _mm_add_epi64(T4, T5);
+
+    /* H += [Mx,My] */
+    T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)),
+                            _mm_loadl_epi64((xmmi *)(m + 16)));
+    T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)),
+                            _mm_loadl_epi64((xmmi *)(m + 24)));
+    M0 = _mm_and_si128(MMASK, T5);
+    M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12));
+    M2 = _mm_and_si128(MMASK, T5);
+    M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26));
+    M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT);
+
+    T0 = _mm_add_epi64(T0, M0);
+    T1 = _mm_add_epi64(T1, M1);
+    T2 = _mm_add_epi64(T2, M2);
+    T3 = _mm_add_epi64(T3, M3);
+    T4 = _mm_add_epi64(T4, M4);
+
+    /* reduce */
+    C1 = _mm_srli_epi64(T0, 26);
+    C2 = _mm_srli_epi64(T3, 26);
+    T0 = _mm_and_si128(T0, MMASK);
+    T3 = _mm_and_si128(T3, MMASK);
+    T1 = _mm_add_epi64(T1, C1);
+    T4 = _mm_add_epi64(T4, C2);
+    C1 = _mm_srli_epi64(T1, 26);
+    C2 = _mm_srli_epi64(T4, 26);
+    T1 = _mm_and_si128(T1, MMASK);
+    T4 = _mm_and_si128(T4, MMASK);
+    T2 = _mm_add_epi64(T2, C1);
+    T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE));
+    C1 = _mm_srli_epi64(T2, 26);
+    C2 = _mm_srli_epi64(T0, 26);
+    T2 = _mm_and_si128(T2, MMASK);
+    T0 = _mm_and_si128(T0, MMASK);
+    T3 = _mm_add_epi64(T3, C1);
+    T1 = _mm_add_epi64(T1, C2);
+    C1 = _mm_srli_epi64(T3, 26);
+    T3 = _mm_and_si128(T3, MMASK);
+    T4 = _mm_add_epi64(T4, C1);
+
+    /* H = (H*[r^2,r^2] + [Mx,My]) */
+    H0 = T0;
+    H1 = T1;
+    H2 = T2;
+    H3 = T3;
+    H4 = T4;
+
+    consumed = 32;
+  }
+
+  /* finalize, H *= [r^2,r] */
+  r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1];
+  r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1];
+  r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1];
+
+  p->R20.d[2] = (uint32_t)(r0)&0x3ffffff;
+  p->R21.d[2] = (uint32_t)((r0 >> 26) | (r1 << 18)) & 0x3ffffff;
+  p->R22.d[2] = (uint32_t)((r1 >> 8)) & 0x3ffffff;
+  p->R23.d[2] = (uint32_t)((r1 >> 34) | (r2 << 10)) & 0x3ffffff;
+  p->R24.d[2] = (uint32_t)((r2 >> 16));
+  p->S21.d[2] = p->R21.d[2] * 5;
+  p->S22.d[2] = p->R22.d[2] * 5;
+  p->S23.d[2] = p->R23.d[2] * 5;
+  p->S24.d[2] = p->R24.d[2] * 5;
+
+  /* H *= [r^2,r] */
+  T0 = _mm_mul_epu32(H0, p->R20.v);
+  T1 = _mm_mul_epu32(H0, p->R21.v);
+  T2 = _mm_mul_epu32(H0, p->R22.v);
+  T3 = _mm_mul_epu32(H0, p->R23.v);
+  T4 = _mm_mul_epu32(H0, p->R24.v);
+  T5 = _mm_mul_epu32(H1, p->S24.v);
+  T6 = _mm_mul_epu32(H1, p->R20.v);
+  T0 = _mm_add_epi64(T0, T5);
+  T1 = _mm_add_epi64(T1, T6);
+  T5 = _mm_mul_epu32(H2, p->S23.v);
+  T6 = _mm_mul_epu32(H2, p->S24.v);
+  T0 = _mm_add_epi64(T0, T5);
+  T1 = _mm_add_epi64(T1, T6);
+  T5 = _mm_mul_epu32(H3, p->S22.v);
+  T6 = _mm_mul_epu32(H3, p->S23.v);
+  T0 = _mm_add_epi64(T0, T5);
+  T1 = _mm_add_epi64(T1, T6);
+  T5 = _mm_mul_epu32(H4, p->S21.v);
+  T6 = _mm_mul_epu32(H4, p->S22.v);
+  T0 = _mm_add_epi64(T0, T5);
+  T1 = _mm_add_epi64(T1, T6);
+  T5 = _mm_mul_epu32(H1, p->R21.v);
+  T6 = _mm_mul_epu32(H1, p->R22.v);
+  T2 = _mm_add_epi64(T2, T5);
+  T3 = _mm_add_epi64(T3, T6);
+  T5 = _mm_mul_epu32(H2, p->R20.v);
+  T6 = _mm_mul_epu32(H2, p->R21.v);
+  T2 = _mm_add_epi64(T2, T5);
+  T3 = _mm_add_epi64(T3, T6);
+  T5 = _mm_mul_epu32(H3, p->S24.v);
+  T6 = _mm_mul_epu32(H3, p->R20.v);
+  T2 = _mm_add_epi64(T2, T5);
+  T3 = _mm_add_epi64(T3, T6);
+  T5 = _mm_mul_epu32(H4, p->S23.v);
+  T6 = _mm_mul_epu32(H4, p->S24.v);
+  T2 = _mm_add_epi64(T2, T5);
+  T3 = _mm_add_epi64(T3, T6);
+  T5 = _mm_mul_epu32(H1, p->R23.v);
+  T4 = _mm_add_epi64(T4, T5);
+  T5 = _mm_mul_epu32(H2, p->R22.v);
+  T4 = _mm_add_epi64(T4, T5);
+  T5 = _mm_mul_epu32(H3, p->R21.v);
+  T4 = _mm_add_epi64(T4, T5);
+  T5 = _mm_mul_epu32(H4, p->R20.v);
+  T4 = _mm_add_epi64(T4, T5);
+
+  C1 = _mm_srli_epi64(T0, 26);
+  C2 = _mm_srli_epi64(T3, 26);
+  T0 = _mm_and_si128(T0, MMASK);
+  T3 = _mm_and_si128(T3, MMASK);
+  T1 = _mm_add_epi64(T1, C1);
+  T4 = _mm_add_epi64(T4, C2);
+  C1 = _mm_srli_epi64(T1, 26);
+  C2 = _mm_srli_epi64(T4, 26);
+  T1 = _mm_and_si128(T1, MMASK);
+  T4 = _mm_and_si128(T4, MMASK);
+  T2 = _mm_add_epi64(T2, C1);
+  T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE));
+  C1 = _mm_srli_epi64(T2, 26);
+  C2 = _mm_srli_epi64(T0, 26);
+  T2 = _mm_and_si128(T2, MMASK);
+  T0 = _mm_and_si128(T0, MMASK);
+  T3 = _mm_add_epi64(T3, C1);
+  T1 = _mm_add_epi64(T1, C2);
+  C1 = _mm_srli_epi64(T3, 26);
+  T3 = _mm_and_si128(T3, MMASK);
+  T4 = _mm_add_epi64(T4, C1);
+
+  /* H = H[0]+H[1] */
+  H0 = _mm_add_epi64(T0, _mm_srli_si128(T0, 8));
+  H1 = _mm_add_epi64(T1, _mm_srli_si128(T1, 8));
+  H2 = _mm_add_epi64(T2, _mm_srli_si128(T2, 8));
+  H3 = _mm_add_epi64(T3, _mm_srli_si128(T3, 8));
+  H4 = _mm_add_epi64(T4, _mm_srli_si128(T4, 8));
+
+  t0 = _mm_cvtsi128_si32(H0);
+  c = (t0 >> 26);
+  t0 &= 0x3ffffff;
+  t1 = _mm_cvtsi128_si32(H1) + c;
+  c = (t1 >> 26);
+  t1 &= 0x3ffffff;
+  t2 = _mm_cvtsi128_si32(H2) + c;
+  c = (t2 >> 26);
+  t2 &= 0x3ffffff;
+  t3 = _mm_cvtsi128_si32(H3) + c;
+  c = (t3 >> 26);
+  t3 &= 0x3ffffff;
+  t4 = _mm_cvtsi128_si32(H4) + c;
+  c = (t4 >> 26);
+  t4 &= 0x3ffffff;
+  t0 = t0 + (c * 5);
+  c = (t0 >> 26);
+  t0 &= 0x3ffffff;
+  t1 = t1 + c;
+
+  st->HH[0] = ((t0) | (t1 << 26)) & 0xfffffffffffull;
+  st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & 0xfffffffffffull;
+  st->HH[2] = ((t3 >> 10) | (t4 << 16)) & 0x3ffffffffffull;
+
+  return consumed;
+}
+
+void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m,
+                            size_t bytes) {
+  poly1305_state_internal *st = poly1305_aligned_state(state);
+  size_t want;
+
+  /* need at least 32 initial bytes to start the accelerated branch */
+  if (!st->started) {
+    if ((st->leftover == 0) && (bytes > 32)) {
+      poly1305_first_block(st, m);
+      m += 32;
+      bytes -= 32;
+    } else {
+      want = poly1305_min(32 - st->leftover, bytes);
+      poly1305_block_copy(st->buffer + st->leftover, m, want);
+      bytes -= want;
+      m += want;
+      st->leftover += want;
+      if ((st->leftover < 32) || (bytes == 0))
+        return;
+      poly1305_first_block(st, st->buffer);
+      st->leftover = 0;
+    }
+    st->started = 1;
+  }
+
+  /* handle leftover */
+  if (st->leftover) {
+    want = poly1305_min(64 - st->leftover, bytes);
+    poly1305_block_copy(st->buffer + st->leftover, m, want);
+    bytes -= want;
+    m += want;
+    st->leftover += want;
+    if (st->leftover < 64)
+      return;
+    poly1305_blocks(st, st->buffer, 64);
+    st->leftover = 0;
+  }
+
+  /* process 64 byte blocks */
+  if (bytes >= 64) {
+    want = (bytes & ~63);
+    poly1305_blocks(st, m, want);
+    m += want;
+    bytes -= want;
+  }
+
+  if (bytes) {
+    poly1305_block_copy(st->buffer + st->leftover, m, bytes);
+    st->leftover += bytes;
+  }
+}
+
+void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) {
+  poly1305_state_internal *st = poly1305_aligned_state(state);
+  size_t leftover = st->leftover;
+  uint8_t *m = st->buffer;
+  uint128_t d[3];
+  uint64_t h0, h1, h2;
+  uint64_t t0, t1;
+  uint64_t g0, g1, g2, c, nc;
+  uint64_t r0, r1, r2, s1, s2;
+  poly1305_power *p;
+
+  if (st->started) {
+    size_t consumed = poly1305_combine(st, m, leftover);
+    leftover -= consumed;
+    m += consumed;
+  }
+
+  /* st->HH will either be 0 or have the combined result */
+  h0 = st->HH[0];
+  h1 = st->HH[1];
+  h2 = st->HH[2];
+
+  p = &st->P[1];
+  r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1];
+  r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1];
+  r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1];
+  s1 = r1 * (5 << 2);
+  s2 = r2 * (5 << 2);
+
+  if (leftover < 16)
+    goto poly1305_donna_atmost15bytes;
+
+poly1305_donna_atleast16bytes:
+  t0 = U8TO64_LE(m + 0);
+  t1 = U8TO64_LE(m + 8);
+  h0 += t0 & 0xfffffffffff;
+  t0 = shr128_pair(t1, t0, 44);
+  h1 += t0 & 0xfffffffffff;
+  h2 += (t1 >> 24) | ((uint64_t)1 << 40);
+
+poly1305_donna_mul:
+  d[0] = add128(add128(mul64x64_128(h0, r0), mul64x64_128(h1, s2)),
+                mul64x64_128(h2, s1));
+  d[1] = add128(add128(mul64x64_128(h0, r1), mul64x64_128(h1, r0)),
+                mul64x64_128(h2, s2));
+  d[2] = add128(add128(mul64x64_128(h0, r2), mul64x64_128(h1, r1)),
+                mul64x64_128(h2, r0));
+  h0 = lo128(d[0]) & 0xfffffffffff;
+  c = shr128(d[0], 44);
+  d[1] = add128_64(d[1], c);
+  h1 = lo128(d[1]) & 0xfffffffffff;
+  c = shr128(d[1], 44);
+  d[2] = add128_64(d[2], c);
+  h2 = lo128(d[2]) & 0x3ffffffffff;
+  c = shr128(d[2], 42);
+  h0 += c * 5;
+
+  m += 16;
+  leftover -= 16;
+  if (leftover >= 16)
+    goto poly1305_donna_atleast16bytes;
+
+/* final bytes */
+poly1305_donna_atmost15bytes:
+  if (!leftover)
+    goto poly1305_donna_finish;
+
+  m[leftover++] = 1;
+  poly1305_block_zero(m + leftover, 16 - leftover);
+  leftover = 16;
+
+  t0 = U8TO64_LE(m + 0);
+  t1 = U8TO64_LE(m + 8);
+  h0 += t0 & 0xfffffffffff;
+  t0 = shr128_pair(t1, t0, 44);
+  h1 += t0 & 0xfffffffffff;
+  h2 += (t1 >> 24);
+
+  goto poly1305_donna_mul;
+
+poly1305_donna_finish:
+  c = (h0 >> 44);
+  h0 &= 0xfffffffffff;
+  h1 += c;
+  c = (h1 >> 44);
+  h1 &= 0xfffffffffff;
+  h2 += c;
+  c = (h2 >> 42);
+  h2 &= 0x3ffffffffff;
+  h0 += c * 5;
+
+  g0 = h0 + 5;
+  c = (g0 >> 44);
+  g0 &= 0xfffffffffff;
+  g1 = h1 + c;
+  c = (g1 >> 44);
+  g1 &= 0xfffffffffff;
+  g2 = h2 + c - ((uint64_t)1 << 42);
+
+  c = (g2 >> 63) - 1;
+  nc = ~c;
+  h0 = (h0 & nc) | (g0 & c);
+  h1 = (h1 & nc) | (g1 & c);
+  h2 = (h2 & nc) | (g2 & c);
+
+  /* pad */
+  t0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1];
+  t1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1];
+  h0 += (t0 & 0xfffffffffff);
+  c = (h0 >> 44);
+  h0 &= 0xfffffffffff;
+  t0 = shr128_pair(t1, t0, 44);
+  h1 += (t0 & 0xfffffffffff) + c;
+  c = (h1 >> 44);
+  h1 &= 0xfffffffffff;
+  t1 = (t1 >> 24);
+  h2 += (t1)+c;
+
+  U64TO8_LE(mac + 0, ((h0) | (h1 << 44)));
+  U64TO8_LE(mac + 8, ((h1 >> 20) | (h2 << 24)));
+}
+
+#endif  /* !OPENSSL_WINDOWS && OPENSSL_X86_64 */