aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcryptobox/poly1305/poly1305.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-02-07 22:10:07 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-02-07 22:28:36 +0000
commit06a8ad2bae9e0aa0fe62e6059198bb3ec57eb08f (patch)
treea9d9d28c941840486c6697362dac219204672fda /src/libcryptobox/poly1305/poly1305.c
parent1e2ff82baa69251c79576609c2a94bd0c006cd72 (diff)
downloadrspamd-06a8ad2bae9e0aa0fe62e6059198bb3ec57eb08f.tar.gz
rspamd-06a8ad2bae9e0aa0fe62e6059198bb3ec57eb08f.zip
Use optimized version of poly1305.
Diffstat (limited to 'src/libcryptobox/poly1305/poly1305.c')
-rw-r--r--src/libcryptobox/poly1305/poly1305.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/libcryptobox/poly1305/poly1305.c b/src/libcryptobox/poly1305/poly1305.c
new file mode 100644
index 000000000..ef3b366bc
--- /dev/null
+++ b/src/libcryptobox/poly1305/poly1305.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015, Vsevolod Stakhov
+ * Copyright (c) 2015, Andrew Moon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "cryptobox.h"
+#include "poly1305.h"
+#include "platform_config.h"
+
+extern unsigned long cpu_config;
+
+typedef struct poly1305_state_internal_t
+{
+ unsigned char opaque[192]; /* largest state required (AVX2) */
+ size_t leftover, block_size;
+ unsigned char buffer[64]; /* largest blocksize (AVX2) */
+} poly1305_state_internal;
+
+typedef struct poly1305_impl_t
+{
+ unsigned long cpu_flags;
+ const char *desc;
+
+ size_t (*block_size)(void);
+ void (*init_ext)(void *state, const poly1305_key *key, size_t bytes_hint);
+ void (*blocks)(void *state, const unsigned char *in, size_t inlen);
+ void (*finish_ext)(void *state, const unsigned char *in, size_t remaining,
+ unsigned char *mac);
+ void (*auth)(unsigned char *mac, const unsigned char *in, size_t inlen,
+ const poly1305_key *key);
+} poly1305_impl_t;
+
+#define POLY1305_DECLARE(ext) \
+ size_t poly1305_block_size_##ext(void); \
+ void poly1305_init_ext_##ext(void *state, const poly1305_key *key, size_t bytes_hint); \
+ void poly1305_blocks_##ext(void *state, const unsigned char *in, size_t inlen); \
+ void poly1305_finish_ext_##ext(void *state, const unsigned char *in, size_t remaining, unsigned char *mac); \
+ void poly1305_auth_##ext(unsigned char *mac, const unsigned char *m, size_t inlen, const poly1305_key *key);
+
+#define POLY1305_IMPL(cpuflags, desc, ext) \
+ {(cpuflags), desc, poly1305_block_size_##ext, poly1305_init_ext_##ext, poly1305_blocks_##ext, poly1305_finish_ext_##ext, poly1305_auth_##ext}
+
+#if defined(HAVE_AVX2)
+POLY1305_DECLARE(avx2)
+#define POLY1305_AVX2 POLY1305_IMPL(CPUID_AVX2, "avx2", avx2)
+#endif
+#if defined(HAVE_AVX)
+POLY1305_DECLARE(avx)
+#define POLY1305_AVX POLY1305_IMPL(CPUID_AVX, "avx", avx)
+#endif
+#if defined(HAVE_SSE2)
+POLY1305_DECLARE(sse2)
+#define POLY1305_SSE2 POLY1305_IMPL(CPUID_SSE2, "sse2", sse2)
+#endif
+
+POLY1305_DECLARE(ref)
+#define POLY1305_GENERIC POLY1305_IMPL(0, "generic", ref)
+
+/* list implemenations from most optimized to least, with generic as the last entry */
+static const poly1305_impl_t poly1305_list[] =
+{
+POLY1305_GENERIC,
+
+#if defined(POLY1305_AVX2)
+ POLY1305_AVX2,
+#endif
+#if defined(POLY1305_AVX)
+ POLY1305_AVX,
+#endif
+#if defined(POLY1305_SSE2)
+ POLY1305_SSE2,
+#endif
+ };
+
+static const poly1305_impl_t *poly1305_opt = &poly1305_list[0];
+;
+
+/* is the pointer aligned on a word boundary? */
+static int poly1305_is_aligned(const void *p)
+{
+ return ((size_t) p & (sizeof(size_t) - 1)) == 0;
+}
+
+void poly1305_load(void)
+{
+ guint i;
+
+ if (cpu_config != 0) {
+ for (i = 0; i < G_N_ELEMENTS(poly1305_list); i++) {
+ if (poly1305_list[i].cpu_flags & cpu_config) {
+ poly1305_opt = &poly1305_list[i];
+ break;
+ }
+ }
+ }
+}
+
+/* processes inlen bytes (full blocks only), handling input alignment */
+static void poly1305_consume(poly1305_state_internal *state,
+ const unsigned char *in, size_t inlen)
+{
+ int in_aligned;
+
+ /* it's ok to call with 0 bytes */
+ if (!inlen)
+ return;
+
+ /* if everything is aligned, handle directly */
+ in_aligned = poly1305_is_aligned (in);
+ if (in_aligned) {
+ poly1305_opt->blocks (state->opaque, in, inlen);
+ return;
+ }
+
+ /* copy the unaligned data to an aligned buffer and process in chunks */
+ while (inlen) {
+ unsigned char buffer[1024];
+ const size_t bytes = (inlen > sizeof(buffer)) ? sizeof(buffer) : inlen;
+ memcpy (buffer, in, bytes);
+ poly1305_opt->blocks (state->opaque, buffer, bytes);
+ in += bytes;
+ inlen -= bytes;
+ }
+}
+
+void poly1305_init(poly1305_state *S, const poly1305_key *key)
+{
+ poly1305_state_internal *state = (poly1305_state_internal *) S;
+ poly1305_opt->init_ext (state->opaque, key, 0);
+ state->leftover = 0;
+ state->block_size = poly1305_opt->block_size ();
+}
+
+void poly1305_init_ext(poly1305_state *S, const poly1305_key *key,
+ size_t bytes_hint)
+{
+ poly1305_state_internal *state = (poly1305_state_internal *) S;
+ poly1305_opt->init_ext (state->opaque, key, bytes_hint);
+ state->leftover = 0;
+ state->block_size = poly1305_opt->block_size ();
+}
+
+void poly1305_update(poly1305_state *S, const unsigned char *in, size_t inlen)
+{
+ poly1305_state_internal *state = (poly1305_state_internal *) S;
+
+ /* handle leftover */
+ if (state->leftover) {
+ size_t want = (state->block_size - state->leftover);
+ if (want > inlen)
+ want = inlen;
+ memcpy (state->buffer + state->leftover, in, want);
+ inlen -= want;
+ in += want;
+ state->leftover += want;
+ if (state->leftover < state->block_size)
+ return;
+ poly1305_opt->blocks (state->opaque, state->buffer, state->block_size);
+ state->leftover = 0;
+ }
+
+ /* process full blocks */
+ if (inlen >= state->block_size) {
+ size_t want = (inlen & ~(state->block_size - 1));
+ poly1305_consume (state, in, want);
+ in += want;
+ inlen -= want;
+ }
+
+ /* store leftover */
+ if (inlen) {
+ memcpy (state->buffer + state->leftover, in, inlen);
+ state->leftover += inlen;
+ }
+}
+
+void poly1305_finish(poly1305_state *S, unsigned char *mac)
+{
+ poly1305_state_internal *state = (poly1305_state_internal *) S;
+ poly1305_opt->finish_ext (state->opaque, state->buffer, state->leftover,
+ mac);
+}
+
+void poly1305_auth(unsigned char *mac, const unsigned char *in, size_t inlen,
+ const poly1305_key *key)
+{
+ poly1305_opt->auth (mac, in, inlen, key);
+}
+
+int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16])
+{
+ size_t i;
+ unsigned int dif = 0;
+
+ for (i = 0; i < 16; i++) {
+ dif |= (mac1[i] ^ mac2[i]);
+ }
+
+ dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1);
+ return (dif & 1);
+}